diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib')
393 files changed, 50217 insertions, 31839 deletions
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp index f1d947d..6e1b0e5 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp @@ -10,6 +10,7 @@ #include "Internals.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" #include "clang/AST/ASTConsumer.h" #include "clang/Rewrite/Rewriter.h" @@ -18,12 +19,10 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/Triple.h" - using namespace clang; using namespace arcmt; -using llvm::StringRef; -bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { if (range.isInvalid()) return false; @@ -39,7 +38,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; - while (I != List.end() && I->getLevel() == Diagnostic::Note) + while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) ++I; // Clear the diagnostic and any notes following it. List.erase(eraseS, I); @@ -52,7 +51,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, return cleared; } -bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const { if (range.isInvalid()) return false; @@ -74,14 +73,14 @@ bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs, return false; } -void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) const { +void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) Diags.Report(*I); } bool CapturedDiagList::hasErrors() const { for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) - if (I->getLevel() >= Diagnostic::Error) + if (I->getLevel() >= DiagnosticsEngine::Error) return true; return false; @@ -89,18 +88,18 @@ bool CapturedDiagList::hasErrors() const { namespace { -class CaptureDiagnosticClient : public DiagnosticClient { - Diagnostic &Diags; +class CaptureDiagnosticConsumer : public DiagnosticConsumer { + DiagnosticsEngine &Diags; CapturedDiagList &CapturedDiags; public: - CaptureDiagnosticClient(Diagnostic &diags, - CapturedDiagList &capturedDiags) + CaptureDiagnosticConsumer(DiagnosticsEngine &diags, + CapturedDiagList &capturedDiags) : Diags(diags), CapturedDiags(capturedDiags) { } - virtual void HandleDiagnostic(Diagnostic::Level level, - const DiagnosticInfo &Info) { + virtual void HandleDiagnostic(DiagnosticsEngine::Level level, + const Diagnostic &Info) { if (arcmt::isARCDiagnostic(Info.getID(), Diags) || - level >= Diagnostic::Error || level == Diagnostic::Note) { + level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { CapturedDiags.push_back(StoredDiagnostic(level, Info)); return; } @@ -108,11 +107,17 @@ public: // Non-ARC warnings are ignored. Diags.setLastDiagnosticIgnored(); } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; } // end anonymous namespace -static inline llvm::StringRef SimulatorVersionDefineName() { +static inline StringRef SimulatorVersionDefineName() { return "__IPHONE_OS_VERSION_MIN_REQUIRED="; } @@ -121,11 +126,11 @@ static inline llvm::StringRef SimulatorVersionDefineName() { // and return the grouped values as integers, e.g: // __IPHONE_OS_VERSION_MIN_REQUIRED=40201 // will return Major=4, Minor=2, Micro=1. -static bool GetVersionFromSimulatorDefine(llvm::StringRef define, +static bool GetVersionFromSimulatorDefine(StringRef define, unsigned &Major, unsigned &Minor, unsigned &Micro) { assert(define.startswith(SimulatorVersionDefineName())); - llvm::StringRef name, version; + StringRef name, version; llvm::tie(name, version) = define.split('='); if (version.empty()) return false; @@ -154,7 +159,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) { continue; if (!define.startswith(SimulatorVersionDefineName())) continue; - unsigned Major, Minor, Micro; + unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) return Major >= 5; @@ -177,7 +182,8 @@ static bool HasARCRuntime(CompilerInvocation &origCI) { return false; } -CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { +static CompilerInvocation * +createInvocationForMigration(CompilerInvocation &origCI) { llvm::OwningPtr<CompilerInvocation> CInvok; CInvok.reset(new CompilerInvocation(origCI)); CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); @@ -194,13 +200,29 @@ CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { return CInvok.take(); } +static void emitPremigrationErrors(const CapturedDiagList &arcDiags, + const DiagnosticOptions &diagOpts, + Preprocessor &PP) { + TextDiagnosticPrinter printer(llvm::errs(), diagOpts); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false)); + Diags->setSourceManager(&PP.getSourceManager()); + + printer.BeginSourceFile(PP.getLangOptions(), &PP); + arcDiags.reportDiagnostics(*Diags); + printer.EndSourceFile(); +} + //===----------------------------------------------------------------------===// // checkForManualIssues. //===----------------------------------------------------------------------===// bool arcmt::checkForManualIssues(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + bool emitPremigrationARCErrors, + StringRef plistOut) { if (!origCI.getLangOpts().ObjC1) return false; @@ -216,11 +238,11 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, assert(DiagClient); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. - CaptureDiagnosticClient errRec(*Diags, capturedDiags); + CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); llvm::OwningPtr<ASTUnit> Unit( @@ -241,9 +263,21 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, return true; } + if (emitPremigrationARCErrors) + emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(), + Unit->getPreprocessor()); + if (!plistOut.empty()) { + SmallVector<StoredDiagnostic, 8> arcDiags; + for (CapturedDiagList::iterator + I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) + arcDiags.push_back(*I); + writeARCDiagsToPlist(plistOut, arcDiags, + Ctx.getSourceManager(), Ctx.getLangOptions()); + } + // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. - // We call BeginSourceFile because DiagnosticClient requires that + // We call BeginSourceFile because DiagnosticConsumer requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); @@ -266,7 +300,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts().ObjCAutoRefCount = false; - return capturedDiags.hasErrors(); + return capturedDiags.hasErrors() || testAct.hasReportedErrors(); } //===----------------------------------------------------------------------===// @@ -274,15 +308,18 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, //===----------------------------------------------------------------------===// static bool applyTransforms(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient, - llvm::StringRef outputDir) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + StringRef outputDir, + bool emitPremigrationARCErrors, + StringRef plistOut) { if (!origCI.getLangOpts().ObjC1) return false; // Make sure checking is successful first. CompilerInvocation CInvokForCheck(origCI); - if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient)) + if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient, + emitPremigrationARCErrors, plistOut)) return true; CompilerInvocation CInvok(origCI); @@ -300,8 +337,8 @@ static bool applyTransforms(CompilerInvocation &origCI, } llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); if (outputDir.empty()) { origCI.getLangOpts().ObjCAutoRefCount = true; @@ -315,28 +352,32 @@ static bool applyTransforms(CompilerInvocation &origCI, } bool arcmt::applyTransformations(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient) { - return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef()); + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient) { + return applyTransforms(origCI, Filename, Kind, DiagClient, + StringRef(), false, StringRef()); } bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient, - llvm::StringRef outputDir) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + StringRef outputDir, + bool emitPremigrationARCErrors, + StringRef plistOut) { assert(!outputDir.empty() && "Expected output directory path"); - return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir); + return applyTransforms(origCI, Filename, Kind, DiagClient, + outputDir, emitPremigrationARCErrors, plistOut); } bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & remap, - llvm::StringRef outputDir, - DiagnosticClient *DiagClient) { + StringRef outputDir, + DiagnosticConsumer *DiagClient) { assert(!outputDir.empty()); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); FileRemapper remapper; bool err = remapper.initFromDisk(outputDir, *Diags, @@ -364,7 +405,8 @@ public: ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) : ARCMTMacroLocs(ARCMTMacroLocs) { } - virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) { + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI, + SourceRange Range) { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); } @@ -378,7 +420,7 @@ public: : ARCMTMacroLocs(ARCMTMacroLocs) { } virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { CI.getPreprocessor().addPPCallbacks( new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); return new ASTConsumer(); @@ -402,7 +444,7 @@ public: Listener->finish(); } - virtual void insert(SourceLocation loc, llvm::StringRef text) { + virtual void insert(SourceLocation loc, StringRef text) { bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, /*indentNewLines=*/true); if (!err && Listener) @@ -432,13 +474,13 @@ public: MigrationProcess::RewriteListener::~RewriteListener() { } MigrationProcess::MigrationProcess(const CompilerInvocation &CI, - DiagnosticClient *diagClient, - llvm::StringRef outputDir) + DiagnosticConsumer *diagClient, + StringRef outputDir) : OrigCI(CI), DiagClient(diagClient) { if (!outputDir.empty()) { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); } } @@ -456,11 +498,11 @@ bool MigrationProcess::applyTransform(TransformFn trans, assert(DiagClient); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. - CaptureDiagnosticClient errRec(*Diags, capturedDiags); + CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction; @@ -488,7 +530,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. - // We call BeginSourceFile because DiagnosticClient requires that + // We call BeginSourceFile because DiagnosticConsumer requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); @@ -522,7 +564,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, buf.write(vecOS); vecOS.flush(); llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( - llvm::StringRef(newText.data(), newText.size()), newFname); + StringRef(newText.data(), newText.size()), newFname); llvm::SmallString<64> filePath(file->getName()); Unit->getFileManager().FixupRelativePath(filePath); Remapper.remap(filePath.str(), memBuf); @@ -535,7 +577,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, // isARCDiagnostic. //===----------------------------------------------------------------------===// -bool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) { +bool arcmt::isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag) { return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) == diag::DiagCat_Automatic_Reference_Counting_Issue; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp index 345c745..dea867a 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp @@ -38,16 +38,26 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction) : WrapperFrontendAction(WrappedAction) {} bool MigrateAction::BeginInvocation(CompilerInstance &CI) { - return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(), + if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(), getCurrentFile(), getCurrentFileKind(), CI.getDiagnostics().getClient(), - MigrateDir); + MigrateDir, + EmitPremigrationARCErros, + PlistOut)) + return false; // errors, stop the action. + + // We only want to see diagnostics emitted by migrateWithTemporaryFiles. + CI.getDiagnostics().setIgnoreAllWarnings(true); + return true; } MigrateAction::MigrateAction(FrontendAction *WrappedAction, - llvm::StringRef migrateDir) - : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) { + StringRef migrateDir, + StringRef plistOut, + bool emitPremigrationARCErrors) + : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), + PlistOut(plistOut), EmitPremigrationARCErros(emitPremigrationARCErrors) { if (MigrateDir.empty()) MigrateDir = "."; // user current directory if none is given. } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt b/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt deleted file mode 100644 index 5f2711e..0000000 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(LLVM_USED_LIBS clangBasic clangAST clangParse clangFrontend clangRewrite) - -add_clang_library(clangARCMigrate - ARCMT.cpp - ARCMTActions.cpp - FileRemapper.cpp - TransARCAssign.cpp - TransAutoreleasePool.cpp - TransBlockObjCVariable.cpp - TransEmptyStatementsAndDealloc.cpp - TransformActions.cpp - Transforms.cpp - TransProperties.cpp - TransRetainReleaseDealloc.cpp - TransUnbridgedCasts.cpp - TransUnusedInitDelegate.cpp - TransZeroOutPropsInDealloc.cpp - ) - -add_dependencies(clangARCMigrate - ClangAttrClasses - ClangAttrList - ClangDeclNodes - ClangStmtNodes) diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp index db26c29..c6e6ce4 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp @@ -27,7 +27,7 @@ FileRemapper::~FileRemapper() { clear(); } -void FileRemapper::clear(llvm::StringRef outputDir) { +void FileRemapper::clear(StringRef outputDir) { for (MappingsTy::iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) resetTarget(I->second); @@ -40,7 +40,7 @@ void FileRemapper::clear(llvm::StringRef outputDir) { } } -std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) { +std::string FileRemapper::getRemapInfoFile(StringRef outputDir) { assert(!outputDir.empty()); llvm::sys::Path dir(outputDir); llvm::sys::Path infoFile = dir; @@ -48,7 +48,7 @@ std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) { return infoFile.str(); } -bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, +bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged) { assert(FromToMappings.empty() && "initFromDisk should be called before any remap calls"); @@ -59,38 +59,38 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, return false; std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs; - - std::ifstream fin(infoFile.c_str()); - if (!fin.good()) - return report(std::string("Error opening file: ") + infoFile, Diag); - - while (true) { - std::string fromFilename, toFilename; - uint64_t timeModified; - - fin >> fromFilename >> timeModified >> toFilename; - if (fin.eof()) - break; - if (!fin.good()) - return report(std::string("Error in format of file: ") + infoFile, Diag); - + + llvm::OwningPtr<llvm::MemoryBuffer> fileBuf; + if (llvm::error_code ec = llvm::MemoryBuffer::getFile(infoFile.c_str(), + fileBuf)) + return report("Error opening file: " + infoFile, Diag); + + SmallVector<StringRef, 64> lines; + fileBuf->getBuffer().split(lines, "\n"); + + for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) { + StringRef fromFilename = lines[idx]; + unsigned long long timeModified; + lines[idx+1].getAsInteger(10, timeModified); + StringRef toFilename = lines[idx+2]; + const FileEntry *origFE = FileMgr->getFile(fromFilename); if (!origFE) { if (ignoreIfFilesChanged) continue; - return report(std::string("File does not exist: ") + fromFilename, Diag); + return report("File does not exist: " + fromFilename, Diag); } const FileEntry *newFE = FileMgr->getFile(toFilename); if (!newFE) { if (ignoreIfFilesChanged) continue; - return report(std::string("File does not exist: ") + toFilename, Diag); + return report("File does not exist: " + toFilename, Diag); } if ((uint64_t)origFE->getModificationTime() != timeModified) { if (ignoreIfFilesChanged) continue; - return report(std::string("File was modified: ") + fromFilename, Diag); + return report("File was modified: " + fromFilename, Diag); } pairs.push_back(std::make_pair(origFE, newFE)); @@ -102,13 +102,12 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, return false; } -bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { +bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) { using namespace llvm::sys; bool existed; if (fs::create_directory(outputDir, existed) != llvm::errc::success) - return report(std::string("Could not create directory: ") + outputDir.str(), - Diag); + return report("Could not create directory: " + outputDir, Diag); std::string errMsg; std::string infoFile = getRemapInfoFile(outputDir); @@ -121,13 +120,13 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { const FileEntry *origFE = I->first; - llvm::SmallString<200> origPath = llvm::StringRef(origFE->getName()); + llvm::SmallString<200> origPath = StringRef(origFE->getName()); fs::make_absolute(origPath); infoOut << origPath << '\n'; infoOut << (uint64_t)origFE->getModificationTime() << '\n'; if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) { - llvm::SmallString<200> newPath = llvm::StringRef(FE->getName()); + llvm::SmallString<200> newPath = StringRef(FE->getName()); fs::make_absolute(newPath); infoOut << newPath << '\n'; } else { @@ -138,8 +137,7 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { tempPath += path::extension(origFE->getName()); int fd; if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success) - return report(std::string("Could not create file: ") + tempPath.c_str(), - Diag); + return report("Could not create file: " + tempPath.str(), Diag); llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true); llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>(); @@ -156,8 +154,8 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { return false; } -bool FileRemapper::overwriteOriginal(Diagnostic &Diag, - llvm::StringRef outputDir) { +bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag, + StringRef outputDir) { using namespace llvm::sys; for (MappingsTy::iterator @@ -165,20 +163,15 @@ bool FileRemapper::overwriteOriginal(Diagnostic &Diag, const FileEntry *origFE = I->first; if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) { if (fs::copy_file(newFE->getName(), origFE->getName(), - fs::copy_option::overwrite_if_exists) != llvm::errc::success) { - std::string err = "Could not copy file '"; - llvm::raw_string_ostream os(err); - os << "Could not copy file '" << newFE->getName() << "' to file '" - << origFE->getName() << "'"; - os.flush(); - return report(err, Diag); - } + fs::copy_option::overwrite_if_exists) != llvm::errc::success) + return report(StringRef("Could not copy file '") + newFE->getName() + + "' to file '" + origFE->getName() + "'", Diag); } else { bool fileExists = false; fs::exists(origFE->getName(), fileExists); if (!fileExists) - return report(std::string("File does not exist: ") + origFE->getName(), + return report(StringRef("File does not exist: ") + origFE->getName(), Diag); std::string errMsg; @@ -229,11 +222,11 @@ void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) { clear(); } -void FileRemapper::remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf) { +void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) { remap(getOriginalFile(filePath), memBuf); } -void FileRemapper::remap(llvm::StringRef filePath, llvm::StringRef newPath) { +void FileRemapper::remap(StringRef filePath, StringRef newPath) { const FileEntry *file = getOriginalFile(filePath); const FileEntry *newfile = FileMgr->getFile(newPath); remap(file, newfile); @@ -254,7 +247,7 @@ void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) { ToFromMappings[newfile] = file; } -const FileEntry *FileRemapper::getOriginalFile(llvm::StringRef filePath) { +const FileEntry *FileRemapper::getOriginalFile(StringRef filePath) { const FileEntry *file = FileMgr->getFile(filePath); // If we are updating a file that overriden an original file, // actually update the original file. @@ -283,9 +276,10 @@ void FileRemapper::resetTarget(Target &targ) { } } -bool FileRemapper::report(const std::string &err, Diagnostic &Diag) { +bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) { + llvm::SmallString<128> buf; unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, - err); + err.toStringRef(buf)); Diag.Report(ID); return true; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h index 4f9b138..46f3bb6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h @@ -26,21 +26,30 @@ class CapturedDiagList { public: void push_back(const StoredDiagnostic &diag) { List.push_back(diag); } - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); - bool hasDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range) const; + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); + bool hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const; - void reportDiagnostics(Diagnostic &diags) const; + void reportDiagnostics(DiagnosticsEngine &diags) const; bool hasErrors() const; + + typedef ListTy::const_iterator iterator; + iterator begin() const { return List.begin(); } + iterator end() const { return List.end(); } }; +void writeARCDiagsToPlist(const std::string &outPath, + ArrayRef<StoredDiagnostic> diags, + SourceManager &SM, const LangOptions &LangOpts); + class TransformActions { - Diagnostic &Diags; + DiagnosticsEngine &Diags; CapturedDiagList &CapturedDiags; + bool ReportedErrors; void *Impl; // TransformActionsImpl. public: - TransformActions(Diagnostic &diag, CapturedDiagList &capturedDiags, + TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags, ASTContext &ctx, Preprocessor &PP); ~TransformActions(); @@ -48,21 +57,21 @@ public: bool commitTransaction(); void abortTransaction(); - void insert(SourceLocation loc, llvm::StringRef text); - void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void insert(SourceLocation loc, StringRef text); + void insertAfterToken(SourceLocation loc, StringRef text); void remove(SourceRange range); void removeStmt(Stmt *S); - void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, StringRef text); void replace(SourceRange range, SourceRange replacementRange); - void replaceStmt(Stmt *S, llvm::StringRef text); - void replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void replaceStmt(Stmt *S, StringRef text); + void replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void increaseIndentation(SourceRange range, SourceLocation parentIndent); - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); bool clearAllDiagnostics(SourceRange range) { - return clearDiagnostic(llvm::ArrayRef<unsigned>(), range); + return clearDiagnostic(ArrayRef<unsigned>(), range); } bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { unsigned IDs[] = { ID1, ID2 }; @@ -83,16 +92,18 @@ public: return CapturedDiags.hasDiagnostic(IDs, range); } - void reportError(llvm::StringRef error, SourceLocation loc, + void reportError(StringRef error, SourceLocation loc, SourceRange range = SourceRange()); - void reportNote(llvm::StringRef note, SourceLocation loc, + void reportNote(StringRef note, SourceLocation loc, SourceRange range = SourceRange()); + bool hasReportedErrors() const { return ReportedErrors; } + class RewriteReceiver { public: virtual ~RewriteReceiver(); - virtual void insert(SourceLocation loc, llvm::StringRef text) = 0; + virtual void insert(SourceLocation loc, StringRef text) = 0; virtual void remove(CharSourceRange range) = 0; virtual void increaseIndentation(CharSourceRange range, SourceLocation parentIndent) = 0; @@ -135,9 +146,9 @@ public: : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { } }; -bool isARCDiagnostic(unsigned diagID, Diagnostic &Diag); +bool isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag); -static inline llvm::StringRef getARCMTMacroName() { +static inline StringRef getARCMTMacroName() { return "__IMPL_ARCMT_REMOVED_EXPR__"; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile b/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile deleted file mode 100644 index 5232c5e..0000000 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/ARCMigrate/Makefile --------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements code transformation to ARC mode. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../.. -LIBRARYNAME := clangARCMigrate - -include $(CLANG_LEVEL)/Makefile - diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp new file mode 100644 index 0000000..d1bc90f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp @@ -0,0 +1,195 @@ +//===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Internals.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +using namespace clang; +using namespace arcmt; + +// FIXME: This duplicates significant functionality from PlistDiagnostics.cpp, +// it would be jolly good if there was a reusable PlistWriter or something. + +typedef llvm::DenseMap<FileID, unsigned> FIDMap; + +static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, + const SourceManager &SM, SourceLocation L) { + + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::iterator I = FIDs.find(FID); + if (I != FIDs.end()) return; + FIDs[FID] = V.size(); + V.push_back(FID); +} + +static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, + SourceLocation L) { + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::const_iterator I = FIDs.find(FID); + assert(I != FIDs.end()); + return I->second; +} + +static raw_ostream& Indent(raw_ostream& o, const unsigned indent) { + for (unsigned i = 0; i < indent; ++i) o << ' '; + return o; +} + +static void EmitLocation(raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation L, const FIDMap &FM, + unsigned indent, bool extend = false) { + + FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); + + // Add in the length of the token, so that we cover multi-char tokens. + unsigned offset = + extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; + + Indent(o, indent) << "<dict>\n"; + Indent(o, indent) << " <key>line</key><integer>" + << Loc.getExpansionLineNumber() << "</integer>\n"; + Indent(o, indent) << " <key>col</key><integer>" + << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; + Indent(o, indent) << " <key>file</key><integer>" + << GetFID(FM, SM, Loc) << "</integer>\n"; + Indent(o, indent) << "</dict>\n"; +} + +static void EmitRange(raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + CharSourceRange R, const FIDMap &FM, + unsigned indent) { + Indent(o, indent) << "<array>\n"; + EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); + EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange()); + Indent(o, indent) << "</array>\n"; +} + +static raw_ostream& EmitString(raw_ostream& o, + StringRef s) { + o << "<string>"; + for (StringRef::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { + char c = *I; + switch (c) { + default: o << c; break; + case '&': o << "&"; break; + case '<': o << "<"; break; + case '>': o << ">"; break; + case '\'': o << "'"; break; + case '\"': o << """; break; + } + } + o << "</string>"; + return o; +} + +void arcmt::writeARCDiagsToPlist(const std::string &outPath, + ArrayRef<StoredDiagnostic> diags, + SourceManager &SM, + const LangOptions &LangOpts) { + DiagnosticIDs DiagIDs; + + // Build up a set of FIDs that we use by scanning the locations and + // ranges of the diagnostics. + FIDMap FM; + SmallVector<FileID, 10> Fids; + + for (ArrayRef<StoredDiagnostic>::iterator + I = diags.begin(), E = diags.end(); I != E; ++I) { + const StoredDiagnostic &D = *I; + + AddFID(FM, Fids, SM, D.getLocation()); + + for (StoredDiagnostic::range_iterator + RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) { + AddFID(FM, Fids, SM, RI->getBegin()); + AddFID(FM, Fids, SM, RI->getEnd()); + } + } + + std::string errMsg; + llvm::raw_fd_ostream o(outPath.c_str(), errMsg); + if (!errMsg.empty()) { + llvm::errs() << "error: could not create file: " << outPath << '\n'; + return; + } + + // Write the plist header. + o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n"; + + // Write the root object: a <dict> containing... + // - "files", an <array> mapping from FIDs to file names + // - "diagnostics", an <array> containing the diagnostics + o << "<dict>\n" + " <key>files</key>\n" + " <array>\n"; + + for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); + I!=E; ++I) { + o << " "; + EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n'; + } + + o << " </array>\n" + " <key>diagnostics</key>\n" + " <array>\n"; + + for (ArrayRef<StoredDiagnostic>::iterator + DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) { + + const StoredDiagnostic &D = *DI; + + if (D.getLevel() == DiagnosticsEngine::Ignored) + continue; + + o << " <dict>\n"; + + // Output the diagnostic. + o << " <key>description</key>"; + EmitString(o, D.getMessage()) << '\n'; + o << " <key>category</key>"; + EmitString(o, DiagIDs.getCategoryNameFromID( + DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n'; + o << " <key>type</key>"; + if (D.getLevel() >= DiagnosticsEngine::Error) + EmitString(o, "error") << '\n'; + else if (D.getLevel() == DiagnosticsEngine::Warning) + EmitString(o, "warning") << '\n'; + else + EmitString(o, "note") << '\n'; + + // Output the location of the bug. + o << " <key>location</key>\n"; + EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2); + + // Output the ranges (if any). + StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end(); + + if (RI != RE) { + o << " <key>ranges</key>\n"; + o << " <array>\n"; + for (; RI != RE; ++RI) + EmitRange(o, SM, LangOpts, *RI, FM, 4); + o << " </array>\n"; + } + + // Close up the entry. + o << " </dict>\n"; + } + + o << " </array>\n"; + + // Finish. + o << "</dict>\n</plist>"; +} diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp new file mode 100644 index 0000000..aaa82d8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp @@ -0,0 +1,109 @@ +//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// checkAPIUses: +// +// Emits error/fix with some API uses that are obsolete or not safe in ARC mode: +// +// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe +// with __unsafe_unretained objects. +// - Calling -zone gets replaced with 'nil'. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +namespace { + +class APIChecker : public RecursiveASTVisitor<APIChecker> { + MigrationPass &Pass; + + Selector getReturnValueSel, setReturnValueSel; + Selector getArgumentSel, setArgumentSel; + + Selector zoneSel; +public: + APIChecker(MigrationPass &pass) : Pass(pass) { + SelectorTable &sels = Pass.Ctx.Selectors; + IdentifierTable &ids = Pass.Ctx.Idents; + getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); + setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); + + IdentifierInfo *selIds[2]; + selIds[0] = &ids.get("getArgument"); + selIds[1] = &ids.get("atIndex"); + getArgumentSel = sels.getSelector(2, selIds); + selIds[0] = &ids.get("setArgument"); + setArgumentSel = sels.getSelector(2, selIds); + + zoneSel = sels.getNullarySelector(&ids.get("zone")); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + // NSInvocation. + if (E->isInstanceMessage() && + E->getReceiverInterface() && + E->getReceiverInterface()->getName() == "NSInvocation") { + StringRef selName; + if (E->getSelector() == getReturnValueSel) + selName = "getReturnValue"; + else if (E->getSelector() == setReturnValueSel) + selName = "setReturnValue"; + else if (E->getSelector() == getArgumentSel) + selName = "getArgument"; + else if (E->getSelector() == setArgumentSel) + selName = "setArgument"; + + if (selName.empty()) + return true; + + Expr *parm = E->getArg(0)->IgnoreParenCasts(); + QualType pointee = parm->getType()->getPointeeType(); + if (pointee.isNull()) + return true; + + if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { + std::string err = "NSInvocation's "; + err += selName; + err += " is not safe to be used with an object with ownership other " + "than __unsafe_unretained"; + Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); + } + return true; + } + + // -zone. + if (E->isInstanceMessage() && + E->getInstanceReceiver() && + E->getSelector() == zoneSel && + Pass.TA.hasDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + E->getInstanceReceiver()->getExprLoc())) { + // Calling -zone is meaningless in ARC, change it to nil. + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + E->getInstanceReceiver()->getExprLoc()); + Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); + } + return true; + } +}; + +} // anonymous namespace + +void trans::checkAPIUses(MigrationPass &pass) { + APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp index 8c00df5..1f10196 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp @@ -28,7 +28,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp index 5b84854..08561f9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -36,16 +36,15 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> { Decl *Dcl; - llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases; + SmallVectorImpl<ObjCMessageExpr *> &Releases; public: - ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases) + ReleaseCollector(Decl *D, SmallVectorImpl<ObjCMessageExpr *> &releases) : Dcl(D), Releases(releases) { } bool VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -82,7 +81,7 @@ public: } ~AutoreleasePoolRewriter() { - llvm::SmallVector<VarDecl *, 8> VarsToHandle; + SmallVector<VarDecl *, 8> VarsToHandle; for (std::map<VarDecl *, PoolVarInfo>::iterator I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) { @@ -92,7 +91,7 @@ public: // Check that we can handle/rewrite all references of the pool. clearRefsIn(info.Dcl, info.Refs); - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; @@ -116,7 +115,7 @@ public: Pass.TA.removeStmt(info.Dcl); // Add "@autoreleasepool { }" - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; @@ -147,11 +146,11 @@ public: } // Remove rest of pool var references. - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; - for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator + for (SmallVectorImpl<ObjCMessageExpr *>::iterator relI = scope.Releases.begin(), relE = scope.Releases.end(); relI != relE; ++relI) { clearUnavailableDiags(*relI); @@ -162,7 +161,7 @@ public: } bool VisitCompoundStmt(CompoundStmt *S) { - llvm::SmallVector<PoolScope, 4> Scopes; + SmallVector<PoolScope, 4> Scopes; for (Stmt::child_iterator I = S->body_begin(), E = S->body_end(); I != E; ++I) { @@ -228,7 +227,7 @@ private: Stmt::child_iterator Begin; Stmt::child_iterator End; bool IsFollowedBySimpleReturnStmt; - llvm::SmallVector<ObjCMessageExpr *, 4> Releases; + SmallVector<ObjCMessageExpr *, 4> Releases; PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(), IsFollowedBySimpleReturnStmt(false) { } @@ -287,6 +286,9 @@ private: } bool isInScope(SourceLocation loc) { + if (loc.isInvalid()) + return false; + SourceManager &SM = Ctx.getSourceManager(); if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin())) return false; @@ -420,7 +422,7 @@ private: struct PoolVarInfo { DeclStmt *Dcl; ExprSet Refs; - llvm::SmallVector<PoolScope, 2> Scopes; + SmallVector<PoolScope, 2> Scopes; PoolVarInfo() : Dcl(0) { } }; diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp index 0e342b7..48c0ca9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -32,7 +32,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { @@ -75,7 +74,7 @@ public: RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } bool VisitBlockDecl(BlockDecl *block) { - llvm::SmallVector<VarDecl *, 4> BlockVars; + SmallVector<VarDecl *, 4> BlockVars; for (BlockDecl::capture_iterator I = block->capture_begin(), E = block->capture_end(); I != E; ++I) { @@ -101,7 +100,7 @@ public: bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); SourceManager &SM = Pass.Ctx.getSourceManager(); Transaction Trans(Pass.TA); - Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()), + Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()), "__block", useWeak ? "__weak" : "__unsafe_unretained"); } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp index d0bc332..3ad05e6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -22,11 +22,53 @@ #include "Transforms.h" #include "Internals.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; + +static bool isEmptyARCMTMacroStatement(NullStmt *S, + std::vector<SourceLocation> &MacroLocs, + ASTContext &Ctx) { + if (!S->hasLeadingEmptyMacro()) + return false; + + SourceLocation SemiLoc = S->getSemiLoc(); + if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) + return false; + + if (MacroLocs.empty()) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + std::vector<SourceLocation>::iterator + I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, + SourceManager::LocBeforeThanCompare(SM)); + --I; + SourceLocation + AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); + assert(AfterMacroLoc.isFileID()); + + if (AfterMacroLoc == SemiLoc) + return true; + + int RelOffs = 0; + if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) + return false; + if (RelOffs < 0) + return false; + + // We make the reasonable assumption that a semicolon after 100 characters + // means that it is not the next token after our macro. If this assumption + // fails it is not critical, we will just fail to clear out, e.g., an empty + // 'if'. + if (RelOffs - getARCMTMacroName().size() > 100) + return false; + + SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); + return AfterMacroSemiLoc == SemiLoc; +} namespace { @@ -34,14 +76,14 @@ namespace { /// transformations. class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { ASTContext &Ctx; - llvm::DenseSet<unsigned> &MacroLocs; + std::vector<SourceLocation> &MacroLocs; public: - EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> ¯oLocs) + EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) : Ctx(ctx), MacroLocs(macroLocs) { } bool VisitNullStmt(NullStmt *S) { - return isMacroLoc(S->getLeadingEmptyMacroLoc()); + return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); } bool VisitCompoundStmt(CompoundStmt *S) { if (S->body_empty()) @@ -103,23 +145,14 @@ public: return false; return Visit(S->getSubStmt()); } - -private: - bool isMacroLoc(SourceLocation loc) { - if (loc.isInvalid()) return false; - return MacroLocs.count(loc.getRawEncoding()); - } }; class EmptyStatementsRemover : public RecursiveASTVisitor<EmptyStatementsRemover> { MigrationPass &Pass; - llvm::DenseSet<unsigned> &MacroLocs; public: - EmptyStatementsRemover(MigrationPass &pass, - llvm::DenseSet<unsigned> ¯oLocs) - : Pass(pass), MacroLocs(macroLocs) { } + EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { } bool TraverseStmtExpr(StmtExpr *E) { CompoundStmt *S = E->getSubStmt(); @@ -139,17 +172,12 @@ public: return true; } - bool isMacroLoc(SourceLocation loc) { - if (loc.isInvalid()) return false; - return MacroLocs.count(loc.getRawEncoding()); - } - ASTContext &getContext() { return Pass.Ctx; } private: void check(Stmt *S) { if (!S) return; - if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) { + if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { Transaction Trans(Pass.TA); Pass.TA.removeStmt(S); } @@ -158,8 +186,8 @@ private: } // anonymous namespace -static bool isBodyEmpty(CompoundStmt *body, - ASTContext &Ctx, llvm::DenseSet<unsigned> &MacroLocs) { +static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, + std::vector<SourceLocation> &MacroLocs) { for (CompoundStmt::body_iterator I = body->body_begin(), E = body->body_end(); I != E; ++I) if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) @@ -168,8 +196,7 @@ static bool isBodyEmpty(CompoundStmt *body, return true; } -static void removeDeallocMethod(MigrationPass &pass, - llvm::DenseSet<unsigned> &MacroLocs) { +static void removeDeallocMethod(MigrationPass &pass) { ASTContext &Ctx = pass.Ctx; TransformActions &TA = pass.TA; DeclContext *DC = Ctx.getTranslationUnitDecl(); @@ -184,7 +211,7 @@ static void removeDeallocMethod(MigrationPass &pass, ObjCMethodDecl *MD = *MI; if (MD->getMethodFamily() == OMF_dealloc) { if (MD->hasBody() && - isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) { + isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { Transaction Trans(TA); TA.remove(MD->getSourceRange()); } @@ -195,14 +222,9 @@ static void removeDeallocMethod(MigrationPass &pass, } void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) { - llvm::DenseSet<unsigned> MacroLocs; - for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) - MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding()); - - EmptyStatementsRemover(pass, MacroLocs) - .TraverseDecl(pass.Ctx.getTranslationUnitDecl()); + EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); - removeDeallocMethod(pass, MacroLocs); + removeDeallocMethod(pass); for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { Transaction Trans(pass.TA); diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp index 872c95e..ca845b6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp @@ -40,12 +40,12 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class PropertiesRewriter { MigrationPass &Pass; + ObjCImplementationDecl *CurImplD; struct PropData { ObjCPropertyDecl *PropD; @@ -55,7 +55,7 @@ class PropertiesRewriter { PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { } }; - typedef llvm::SmallVector<PropData, 2> PropsTy; + typedef SmallVector<PropData, 2> PropsTy; typedef std::map<unsigned, PropsTy> AtPropDeclsTy; AtPropDeclsTy AtProps; @@ -63,6 +63,7 @@ public: PropertiesRewriter(MigrationPass &pass) : Pass(pass) { } void doTransform(ObjCImplementationDecl *D) { + CurImplD = D; ObjCInterfaceDecl *iface = D->getClassInterface(); if (!iface) return; @@ -135,8 +136,16 @@ private: return; } - if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) + if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) { + if (hasIvarAssignedAPlusOneObject(props)) { + rewriteAttribute("assign", "strong", atLoc); + return; + } return rewriteAssign(props, atLoc); + } + + if (hasIvarAssignedAPlusOneObject(props)) + return maybeAddStrongAttr(props, atLoc); return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc); } @@ -163,15 +172,15 @@ private: void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props, SourceLocation atLoc) const { ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); - if ((propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) && - hasNoBackingIvars(props)) - return; bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); - bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", - atLoc); - if (!addedAttr) - canUseWeak = false; + if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || + !hasAllIvarsBacked(props)) { + bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", + atLoc); + if (!addedAttr) + canUseWeak = false; + } for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { if (isUserDeclared(I->IvarD)) @@ -187,7 +196,26 @@ private: } } - bool rewriteAttribute(llvm::StringRef fromAttr, llvm::StringRef toAttr, + void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const { + ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + + if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || + !hasAllIvarsBacked(props)) { + addAttribute("strong", atLoc); + } + + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (I->ImplD) { + Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, + I->ImplD->getLocation()); + Pass.TA.clearDiagnostic( + diag::err_arc_objc_property_default_assign_on_object, + I->ImplD->getLocation()); + } + } + } + + bool rewriteAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc) const { if (atLoc.isMacroID()) return false; @@ -199,7 +227,7 @@ private: // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -214,7 +242,7 @@ private: if (tok.isNot(tok::at)) return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::raw_identifier)) return false; - if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + if (StringRef(tok.getRawIdentifierData(), tok.getLength()) != "property") return false; lexer.LexFromRawLexer(tok); @@ -226,7 +254,7 @@ private: while (1) { if (tok.isNot(tok::raw_identifier)) return false; - llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength()); + StringRef ident(tok.getRawIdentifierData(), tok.getLength()); if (ident == fromAttr) { Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); return true; @@ -243,7 +271,7 @@ private: return false; } - bool addAttribute(llvm::StringRef attr, SourceLocation atLoc) const { + bool addAttribute(StringRef attr, SourceLocation atLoc) const { if (atLoc.isMacroID()) return false; @@ -254,7 +282,7 @@ private: // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -269,7 +297,7 @@ private: if (tok.isNot(tok::at)) return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::raw_identifier)) return false; - if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + if (StringRef(tok.getRawIdentifierData(), tok.getLength()) != "property") return false; lexer.LexFromRawLexer(tok); @@ -291,6 +319,45 @@ private: return true; } + class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> { + ObjCIvarDecl *Ivar; + public: + PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {} + + bool VisitBinAssign(BinaryOperator *E) { + Expr *lhs = E->getLHS()->IgnoreParenImpCasts(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) { + if (RE->getDecl() != Ivar) + return true; + + if (ObjCMessageExpr * + ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts())) + if (ME->getMethodFamily() == OMF_retain) + return false; + + ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS()); + while (implCE && implCE->getCastKind() == CK_BitCast) + implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr()); + + if (implCE && implCE->getCastKind() == CK_ARCConsumeObject) + return false; + } + + return true; + } + }; + + bool hasIvarAssignedAPlusOneObject(PropsTy &props) const { + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + PlusOneAssign oneAssign(I->IvarD); + bool notFound = oneAssign.TraverseDecl(CurImplD); + if (!notFound) + return true; + } + + return false; + } + bool hasIvarWithExplicitOwnership(PropsTy &props) const { for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { if (isUserDeclared(I->IvarD)) { @@ -305,9 +372,9 @@ private: return false; } - bool hasNoBackingIvars(PropsTy &props) const { + bool hasAllIvarsBacked(PropsTy &props) const { for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) - if (I->IvarD) + if (!isUserDeclared(I->IvarD)) return false; return true; diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index ed6ed0a..394f848 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -25,7 +25,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { @@ -130,10 +129,9 @@ public: // Change the -release to "receiver = nil" in a finally to avoid a leak // when an exception is thrown. Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); - if (Pass.Ctx.Idents.get("nil").hasMacroDefinition()) - Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil"); - else - Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0"); + std::string str = " = "; + str += getNilString(Pass.Ctx); + Pass.TA.insertAfterToken(rec->getLocEnd(), str); return true; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index 1cacd6d..69fb2e8 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -36,25 +36,32 @@ #include "Internals.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ MigrationPass &Pass; IdentifierInfo *SelfII; + llvm::OwningPtr<ParentMap> StmtMap; + public: UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) { SelfII = &Pass.Ctx.Idents.get("self"); } + void transformBody(Stmt *body) { + StmtMap.reset(new ParentMap(body)); + TraverseStmt(body); + } + bool VisitCastExpr(CastExpr *E) { - if (E->getCastKind() != CK_AnyPointerToObjCPointerCast + if (E->getCastKind() != CK_CPointerToObjCPointerCast && E->getCastKind() != CK_BitCast) return true; @@ -139,13 +146,21 @@ private: } void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { + Transaction Trans(Pass.TA); + rewriteToBridgedCast(E, Kind, Trans); + } + + void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, + Transaction &Trans) { TransformActions &TA = Pass.TA; // We will remove the compiler diagnostic. if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, diag::err_arc_cast_requires_bridge, - E->getLocStart())) + E->getLocStart())) { + Trans.abort(); return; + } StringRef bridge; switch(Kind) { @@ -157,7 +172,6 @@ private: bridge = "__bridge_retained "; break; } - Transaction Trans(TA); TA.clearDiagnostic(diag::err_arc_mismatched_cast, diag::err_arc_cast_requires_bridge, E->getLocStart()); @@ -168,7 +182,7 @@ private: llvm::SmallString<128> newCast; newCast += '('; newCast += bridge; - newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy); + newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); newCast += ')'; if (isa<ParenExpr>(E->getSubExpr())) { @@ -181,16 +195,111 @@ private: } } + void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { + Transaction Trans(Pass.TA); + Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); + rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); + } + void transformObjCToNonObjCCast(CastExpr *E) { if (isSelf(E->getSubExpr())) return rewriteToBridgedCast(E, OBC_Bridge); + + CallExpr *callE; + if (isPassedToCFRetain(E, callE)) + return rewriteCastForCFRetain(E, callE); + + ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); + if (family == OMF_retain) + return rewriteToBridgedCast(E, OBC_BridgeRetained); + + if (family == OMF_autorelease || family == OMF_release) { + std::string err = "it is not safe to cast to '"; + err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); + err += "' the result of '"; + err += family == OMF_autorelease ? "autorelease" : "release"; + err += "' message; a __bridge cast may result in a pointer to a " + "destroyed object and a __bridge_retained may leak the object"; + Pass.TA.reportError(err, E->getLocStart(), + E->getSubExpr()->getSourceRange()); + Stmt *parent = E; + do { + parent = StmtMap->getParentIgnoreParenImpCasts(parent); + } while (parent && isa<ExprWithCleanups>(parent)); + + if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { + std::string note = "remove the cast and change return type of function " + "to '"; + note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); + note += "' to have the object automatically autoreleased"; + Pass.TA.reportNote(note, retS->getLocStart()); + } + } + + if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){ + if (implCE->getCastKind() == CK_ARCConsumeObject) + return rewriteToBridgedCast(E, OBC_BridgeRetained); + if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) + return rewriteToBridgedCast(E, OBC_Bridge); + } + + bool isConsumed = false; + if (isPassedToCParamWithKnownOwnership(E, isConsumed)) + return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained + : OBC_Bridge); } - bool isSelf(Expr *E) { + static ObjCMethodFamily getFamilyOfMessage(Expr *E) { + E = E->IgnoreParenCasts(); + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) + return ME->getMethodFamily(); + + return OMF_None; + } + + bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { + if ((callE = dyn_cast_or_null<CallExpr>( + StmtMap->getParentIgnoreParenImpCasts(E)))) + if (FunctionDecl * + FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) + if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && + FD->getParent()->isTranslationUnit() && + FD->getLinkage() == ExternalLinkage) + return true; + + return false; + } + + bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { + if (CallExpr *callE = dyn_cast_or_null<CallExpr>( + StmtMap->getParentIgnoreParenImpCasts(E))) + if (FunctionDecl * + FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { + unsigned i = 0; + for (unsigned e = callE->getNumArgs(); i != e; ++i) { + Expr *arg = callE->getArg(i); + if (arg == E || arg->IgnoreParenImpCasts() == E) + break; + } + if (i < callE->getNumArgs()) { + ParmVarDecl *PD = FD->getParamDecl(i); + if (PD->getAttr<CFConsumedAttr>()) { + isConsumed = true; + return true; + } + } + } + + return false; + } + + bool isSelf(Expr *E) const { E = E->IgnoreParenLValueCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - if (DRE->getDecl()->getIdentifier() == SelfII) - return true; + if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) + if (IPD->getIdentifier() == SelfII) + return true; + return false; } }; @@ -198,6 +307,6 @@ private: } // end anonymous namespace void trans::rewriteUnbridgedCasts(MigrationPass &pass) { - UnbridgedCastRewriter trans(pass); + BodyTransform<UnbridgedCastRewriter> trans(pass); trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 1019ab4..e2aa6ff 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -27,7 +27,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp index 07ccf70..1dbe811 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -19,7 +19,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp index c99940b..ec676e9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp @@ -13,10 +13,8 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/DenseSet.h" #include <map> - using namespace clang; using namespace arcmt; -using llvm::StringRef; namespace { @@ -46,9 +44,9 @@ class TransformActionsImpl { ActionKind Kind; SourceLocation Loc; SourceRange R1, R2; - llvm::StringRef Text1, Text2; + StringRef Text1, Text2; Stmt *S; - llvm::SmallVector<unsigned, 2> DiagIDs; + SmallVector<unsigned, 2> DiagIDs; }; std::vector<ActionData> CachedActions; @@ -70,11 +68,11 @@ class TransformActionsImpl { SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); assert(beginLoc.isValid() && endLoc.isValid()); if (range.isTokenRange()) { - Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); + Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); } else { - Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); - End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr); + Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); + End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr); } assert(Begin.isValid() && End.isValid()); } @@ -104,7 +102,7 @@ class TransformActionsImpl { } }; - typedef llvm::SmallVector<StringRef, 2> TextsVec; + typedef SmallVector<StringRef, 2> TextsVec; typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare> InsertsMap; InsertsMap Inserts; @@ -130,19 +128,19 @@ public: bool isInTransaction() const { return IsInTransaction; } - void insert(SourceLocation loc, llvm::StringRef text); - void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void insert(SourceLocation loc, StringRef text); + void insertAfterToken(SourceLocation loc, StringRef text); void remove(SourceRange range); void removeStmt(Stmt *S); - void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, StringRef text); void replace(SourceRange range, SourceRange replacementRange); - void replaceStmt(Stmt *S, llvm::StringRef text); - void replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void replaceStmt(Stmt *S, StringRef text); + void replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void increaseIndentation(SourceRange range, SourceLocation parentIndent); - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); void applyRewrites(TransformActions::RewriteReceiver &receiver); @@ -151,17 +149,17 @@ private: bool canInsertAfterToken(SourceLocation loc); bool canRemoveRange(SourceRange range); bool canReplaceRange(SourceRange range, SourceRange replacementRange); - bool canReplaceText(SourceLocation loc, llvm::StringRef text); + bool canReplaceText(SourceLocation loc, StringRef text); void commitInsert(SourceLocation loc, StringRef text); void commitInsertAfterToken(SourceLocation loc, StringRef text); void commitRemove(SourceRange range); void commitRemoveStmt(Stmt *S); void commitReplace(SourceRange range, SourceRange replacementRange); - void commitReplaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void commitReplaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); - void commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); void addRemoval(CharSourceRange range); void addInsertion(SourceLocation loc, StringRef text); @@ -364,7 +362,7 @@ void TransformActionsImpl::increaseIndentation(SourceRange range, CachedActions.push_back(data); } -bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { assert(IsInTransaction && "Actions only allowed during a transaction"); if (!CapturedDiags.hasDiagnostic(IDs, range)) @@ -383,7 +381,7 @@ bool TransformActionsImpl::canInsert(SourceLocation loc) { return false; SourceManager &SM = Ctx.getSourceManager(); - if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) return false; if (loc.isFileID()) @@ -396,7 +394,7 @@ bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { return false; SourceManager &SM = Ctx.getSourceManager(); - if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) return false; if (loc.isFileID()) @@ -418,14 +416,14 @@ bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { return false; SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); // Break down the source location. std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -479,9 +477,9 @@ void TransformActionsImpl::commitReplaceText(SourceLocation loc, StringRef text, StringRef replacementText) { SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); // canReplaceText already checked if loc points at text. - SourceLocation afterText = loc.getFileLocWithOffset(text.size()); + SourceLocation afterText = loc.getLocWithOffset(text.size()); addRemoval(CharSourceRange::getCharRange(loc, afterText)); commitInsert(loc, replacementText); @@ -493,17 +491,17 @@ void TransformActionsImpl::commitIncreaseIndentation(SourceRange range, IndentationRanges.push_back( std::make_pair(CharRange(CharSourceRange::getTokenRange(range), SM, PP), - SM.getInstantiationLoc(parentIndent))); + SM.getExpansionLoc(parentIndent))); } -void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, +void TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { CapturedDiags.clearDiagnostic(IDs, range); } void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); for (std::list<CharRange>::reverse_iterator I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) { if (!SM.isBeforeInTranslationUnit(loc, I->End)) @@ -591,16 +589,16 @@ SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, SourceManager &SM, Preprocessor &PP) { if (loc.isMacroID()) - loc = SM.getInstantiationRange(loc).second; + loc = SM.getExpansionRange(loc).second; return PP.getLocForEndOfToken(loc); } TransformActions::RewriteReceiver::~RewriteReceiver() { } -TransformActions::TransformActions(Diagnostic &diag, +TransformActions::TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags, ASTContext &ctx, Preprocessor &PP) - : Diags(diag), CapturedDiags(capturedDiags) { + : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) { Impl = new TransformActionsImpl(capturedDiags, ctx, PP); } @@ -621,12 +619,12 @@ void TransformActions::abortTransaction() { } -void TransformActions::insert(SourceLocation loc, llvm::StringRef text) { +void TransformActions::insert(SourceLocation loc, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->insert(loc, text); } void TransformActions::insertAfterToken(SourceLocation loc, - llvm::StringRef text) { + StringRef text) { static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text); } @@ -638,7 +636,7 @@ void TransformActions::removeStmt(Stmt *S) { static_cast<TransformActionsImpl*>(Impl)->removeStmt(S); } -void TransformActions::replace(SourceRange range, llvm::StringRef text) { +void TransformActions::replace(SourceRange range, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->replace(range, text); } @@ -647,12 +645,12 @@ void TransformActions::replace(SourceRange range, static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange); } -void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) { +void TransformActions::replaceStmt(Stmt *S, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text); } -void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText) { +void TransformActions::replaceText(SourceLocation loc, StringRef text, + StringRef replacementText) { static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text, replacementText); } @@ -663,7 +661,7 @@ void TransformActions::increaseIndentation(SourceRange range, parentIndent); } -bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range); } @@ -672,7 +670,7 @@ void TransformActions::applyRewrites(RewriteReceiver &receiver) { static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver); } -void TransformActions::reportError(llvm::StringRef error, SourceLocation loc, +void TransformActions::reportError(StringRef error, SourceLocation loc, SourceRange range) { assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && "Errors should be emitted out of a transaction"); @@ -683,9 +681,10 @@ void TransformActions::reportError(llvm::StringRef error, SourceLocation loc, = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, rewriteErr); Diags.Report(loc, diagID) << range; + ReportedErrors = true; } -void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc, +void TransformActions::reportNote(StringRef note, SourceLocation loc, SourceRange range) { assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && "Errors should be emitted out of a transaction"); diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp index 7bd95e5..4244faf 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp @@ -23,7 +23,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; //===----------------------------------------------------------------------===// // Helpers. @@ -92,11 +91,23 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { /// source location will be invalid. SourceLocation trans::findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx) { + SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); + if (SemiLoc.isInvalid()) + return SourceLocation(); + return SemiLoc.getLocWithOffset(1); +} + +/// \brief \arg Loc is the end of a statement range. This returns the location +/// of the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation trans::findSemiAfterLocation(SourceLocation loc, + ASTContext &Ctx) { SourceManager &SM = Ctx.getSourceManager(); if (loc.isMacroID()) { if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) return SourceLocation(); - loc = SM.getInstantiationRange(loc).second; + loc = SM.getExpansionRange(loc).second; } loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); @@ -105,7 +116,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc, // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return SourceLocation(); @@ -120,7 +131,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc, if (tok.isNot(tok::semi)) return SourceLocation(); - return tok.getLocation().getFileLocWithOffset(1); + return tok.getLocation(); } bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { @@ -155,7 +166,8 @@ bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return DRE->getDecl()->getDeclContext()->isFileContext(); + return DRE->getDecl()->getDeclContext()->isFileContext() && + DRE->getDecl()->getLinkage() == ExternalLinkage; if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); @@ -163,6 +175,13 @@ bool trans::isGlobalVar(Expr *E) { return false; } +StringRef trans::getNilString(ASTContext &Ctx) { + if (Ctx.Idents.get("nil").hasMacroDefinition()) + return "nil"; + else + return "0"; +} + namespace { class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { @@ -283,6 +302,7 @@ static void independentTransforms(MigrationPass &pass) { makeAssignARCSafe(pass); rewriteUnbridgedCasts(pass); rewriteBlockObjCVariable(pass); + checkAPIUses(pass); } std::vector<TransformFn> arcmt::getAllTransformations() { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h index b47d6d8..5e4db56 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h @@ -37,6 +37,7 @@ void removeZeroOutPropsInDealloc(MigrationPass &pass); void rewriteProperties(MigrationPass &pass); void rewriteBlockObjCVariable(MigrationPass &pass); void rewriteUnusedInitDelegate(MigrationPass &pass); +void checkAPIUses(MigrationPass &pass); void removeEmptyStatementsAndDealloc(MigrationPass &pass); @@ -53,9 +54,16 @@ bool canApplyWeak(ASTContext &Ctx, QualType type); /// source location will be invalid. SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); +/// \brief \arg Loc is the end of a statement range. This returns the location +/// of the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx); + bool hasSideEffects(Expr *E, ASTContext &Ctx); bool isGlobalVar(Expr *E); - +/// \brief Returns "nil" or "0" if 'nil' macro is not actually defined. +StringRef getNilString(ASTContext &Ctx); template <typename BODY_TRANS> class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { @@ -65,7 +73,8 @@ public: BodyTransform(MigrationPass &pass) : Pass(pass) { } bool TraverseStmt(Stmt *rootS) { - BODY_TRANS(Pass).transformBody(rootS); + if (rootS) + BODY_TRANS(Pass).transformBody(rootS); return true; } }; diff --git a/contrib/llvm/tools/clang/lib/AST/APValue.cpp b/contrib/llvm/tools/clang/lib/AST/APValue.cpp index ebe99b1..6f63a32 100644 --- a/contrib/llvm/tools/clang/lib/AST/APValue.cpp +++ b/contrib/llvm/tools/clang/lib/AST/APValue.cpp @@ -13,7 +13,10 @@ #include "clang/AST/APValue.h" #include "clang/AST/CharUnits.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; namespace { @@ -89,9 +92,9 @@ static double GetApproxValue(const llvm::APFloat &F) { return V.convertToDouble(); } -void APValue::print(llvm::raw_ostream &OS) const { +void APValue::print(raw_ostream &OS) const { switch (getKind()) { - default: assert(0 && "Unknown APValue kind!"); + default: llvm_unreachable("Unknown APValue kind!"); case Uninitialized: OS << "Uninitialized"; return; @@ -118,6 +121,49 @@ void APValue::print(llvm::raw_ostream &OS) const { } } +static void WriteShortAPValueToStream(raw_ostream& Out, + const APValue& V) { + switch (V.getKind()) { + default: llvm_unreachable("Unknown APValue kind!"); + case APValue::Uninitialized: + Out << "Uninitialized"; + break; + case APValue::Int: + Out << V.getInt(); + break; + case APValue::Float: + Out << GetApproxValue(V.getFloat()); + break; + case APValue::Vector: + Out << '['; + WriteShortAPValueToStream(Out, V.getVectorElt(0)); + for (unsigned i = 1; i != V.getVectorLength(); ++i) { + Out << ", "; + WriteShortAPValueToStream(Out, V.getVectorElt(i)); + } + Out << ']'; + break; + case APValue::ComplexInt: + Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i"; + break; + case APValue::ComplexFloat: + Out << GetApproxValue(V.getComplexFloatReal()) << "+" + << GetApproxValue(V.getComplexFloatImag()) << "i"; + break; + case APValue::LValue: + Out << "LValue: <todo>"; + break; + } +} + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + const APValue &V) { + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Out(Buffer); + WriteShortAPValueToStream(Out, V); + return DB << Out.str(); +} + const Expr* APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data)->Base; diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index 6eada6e..4624280 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Capacity.h" #include "CXXABI.h" #include <map> @@ -49,7 +50,7 @@ unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; enum FloatingRank { - FloatRank, DoubleRank, LongDoubleRank + HalfRank, FloatRank, DoubleRank, LongDoubleRank }; void @@ -104,7 +105,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( // Build a canonical template parameter list. TemplateParameterList *Params = TTP->getTemplateParameters(); - llvm::SmallVector<NamedDecl *, 4> CanonParams; + SmallVector<NamedDecl *, 4> CanonParams; CanonParams.reserve(Params->size()); for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); @@ -123,8 +124,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); NonTypeTemplateParmDecl *Param; if (NTTP->isExpandedParameterPack()) { - llvm::SmallVector<QualType, 2> ExpandedTypes; - llvm::SmallVector<TypeSourceInfo *, 2> ExpandedTInfos; + SmallVector<QualType, 2> ExpandedTypes; + SmallVector<TypeSourceInfo *, 2> ExpandedTInfos; for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { ExpandedTypes.push_back(getCanonicalType(NTTP->getExpansionType(I))); ExpandedTInfos.push_back( @@ -195,7 +196,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { return 0; } -static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T, +static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, const LangOptions &LOpts) { if (LOpts.FakeAddressSpaceMap) { // The fake address space map must have a distinct entry for each @@ -205,41 +206,46 @@ static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T, 2, // opencl_local 3 // opencl_constant }; - return FakeAddrSpaceMap; + return &FakeAddrSpaceMap; } else { - return T.getAddressSpaceMap(); + return &T.getAddressSpaceMap(); } } -ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, - const TargetInfo &t, +ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, + const TargetInfo *t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, - unsigned size_reserve) : - FunctionProtoTypes(this_()), - TemplateSpecializationTypes(this_()), - DependentTemplateSpecializationTypes(this_()), - SubstTemplateTemplateParmPacks(this_()), - GlobalNestedNameSpecifier(0), IsInt128Installed(false), - CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), - ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), - jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), - BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), - NullTypeSourceInfo(QualType()), - SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), - AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t), - Idents(idents), Selectors(sels), - BuiltinInfo(builtins), - DeclarationNames(*this), - ExternalSource(0), Listener(0), PrintingPolicy(LOpts), - LastSDM(0, 0), - UniqueBlockByRefTypeID(0) { - ObjCIdRedefinitionType = QualType(); - ObjCClassRedefinitionType = QualType(); - ObjCSelRedefinitionType = QualType(); + unsigned size_reserve, + bool DelayInitialization) + : FunctionProtoTypes(this_()), + TemplateSpecializationTypes(this_()), + DependentTemplateSpecializationTypes(this_()), + SubstTemplateTemplateParmPacks(this_()), + GlobalNestedNameSpecifier(0), + Int128Decl(0), UInt128Decl(0), + ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), + CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0), + FILEDecl(0), + jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), + BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), + NullTypeSourceInfo(QualType()), + SourceMgr(SM), LangOpts(LOpts), + AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts), + Idents(idents), Selectors(sels), + BuiltinInfo(builtins), + DeclarationNames(*this), + ExternalSource(0), Listener(0), + LastSDM(0, 0), + UniqueBlockByRefTypeID(0) +{ if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); - InitBuiltinTypes(); + + if (!DelayInitialization) { + assert(t && "No target supplied for ASTContext initialization"); + InitBuiltinTypes(*t); + } } ASTContext::~ASTContext() { @@ -347,6 +353,33 @@ void ASTContext::PrintStats() const { BumpAlloc.PrintStats(); } +TypedefDecl *ASTContext::getInt128Decl() const { + if (!Int128Decl) { + TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(Int128Ty); + Int128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this), + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("__int128_t"), + TInfo); + } + + return Int128Decl; +} + +TypedefDecl *ASTContext::getUInt128Decl() const { + if (!UInt128Decl) { + TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(UnsignedInt128Ty); + UInt128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this), + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("__uint128_t"), + TInfo); + } + + return UInt128Decl; +} void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); @@ -354,9 +387,16 @@ void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { Types.push_back(Ty); } -void ASTContext::InitBuiltinTypes() { +void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { + assert((!this->Target || this->Target == &Target) && + "Incorrect target reinitialization"); assert(VoidTy.isNull() && "Context reinitialized?"); + this->Target = &Target; + + ABI.reset(createCXXABI(Target)); + AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); + // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); @@ -431,11 +471,6 @@ void ASTContext::InitBuiltinTypes() { BuiltinVaListType = QualType(); - // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). - ObjCIdTypedefType = QualType(); - ObjCClassTypedefType = QualType(); - ObjCSelTypedefType = QualType(); - // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); @@ -448,9 +483,12 @@ void ASTContext::InitBuiltinTypes() { // nullptr type (C++0x 2.14.7) InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); + + // half type (OpenCL 6.1.1.1) / ARM NEON __fp16 + InitBuiltinType(HalfTy, BuiltinType::Half); } -Diagnostic &ASTContext::getDiagnostics() const { +DiagnosticsEngine &ASTContext::getDiagnostics() const { return SourceMgr.getDiagnostics(); } @@ -496,6 +534,24 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); } +FunctionDecl *ASTContext::getClassScopeSpecializationPattern( + const FunctionDecl *FD){ + assert(FD && "Specialization is 0"); + llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos + = ClassScopeSpecializationPattern.find(FD); + if (Pos == ClassScopeSpecializationPattern.end()) + return 0; + + return Pos->second; +} + +void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD, + FunctionDecl *Pattern) { + assert(FD && "Specialization is 0"); + assert(Pattern && "Class scope specialization pattern is 0"); + ClassScopeSpecializationPattern[FD] = Pattern; +} + NamedDecl * ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos @@ -555,35 +611,33 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0); - + FD->getBitWidthValue(*this) == 0); } bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 && - LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0); - + FD->getBitWidthValue(*this) == 0 && + LastFD->getBitWidthValue(*this) != 0); } bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() && - LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); + FD->getBitWidthValue(*this) && + LastFD->getBitWidthValue(*this)); } -bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD, +bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (!FD->isBitField() && LastFD && LastFD->isBitField() && - LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); + LastFD->getBitWidthValue(*this)); } -bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD, +bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); + FD->getBitWidthValue(*this)); } ASTContext::overridden_cxx_method_iterator @@ -631,10 +685,11 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { const BuiltinType *BT = T->getAs<BuiltinType>(); assert(BT && "Not a floating point type!"); switch (BT->getKind()) { - default: assert(0 && "Not a floating point type!"); - case BuiltinType::Float: return Target.getFloatFormat(); - case BuiltinType::Double: return Target.getDoubleFormat(); - case BuiltinType::LongDouble: return Target.getLongDoubleFormat(); + default: llvm_unreachable("Not a floating point type!"); + case BuiltinType::Half: return Target->getHalfFormat(); + case BuiltinType::Float: return Target->getFloatFormat(); + case BuiltinType::Double: return Target->getDoubleFormat(); + case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); } } @@ -644,7 +699,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { /// If @p RefAsPointee, references are treated like their underlying type /// (for alignof), else they're treated like pointers (for CodeGen). CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { - unsigned Align = Target.getCharWidth(); + unsigned Align = Target->getCharWidth(); bool UseAlignAttrOnly = false; if (unsigned AlignFromAttr = D->getMaxAlignment()) { @@ -654,7 +709,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { // *except* on a struct or struct member, where it only increases // alignment unless 'packed' is also specified. // - // It is an error for [[align]] to decrease alignment, so we can + // It is an error for alignas to decrease alignment, so we can // ignore that possibility; Sema should diagnose it. if (isa<FieldDecl>(D)) { UseAlignAttrOnly = D->hasAttr<PackedAttr>() || @@ -684,14 +739,14 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { if (!T->isIncompleteType() && !T->isFunctionType()) { // Adjust alignments of declarations with array type by the // large-array alignment on the target. - unsigned MinWidth = Target.getLargeArrayMinWidth(); + unsigned MinWidth = Target->getLargeArrayMinWidth(); const ArrayType *arrayType; if (MinWidth && (arrayType = getAsArrayType(T))) { if (isa<VariableArrayType>(arrayType)) - Align = std::max(Align, Target.getLargeArrayAlign()); + Align = std::max(Align, Target->getLargeArrayAlign()); else if (isa<ConstantArrayType>(arrayType) && MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) - Align = std::max(Align, Target.getLargeArrayAlign()); + Align = std::max(Align, Target->getLargeArrayAlign()); // Walk through any array types while we're at it. T = getBaseElementType(arrayType); @@ -798,7 +853,7 @@ ASTContext::getTypeInfo(const Type *T) const { case Type::Builtin: switch (cast<BuiltinType>(T)->getKind()) { - default: assert(0 && "Unknown builtin type!"); + default: llvm_unreachable("Unknown builtin type!"); case BuiltinType::Void: // GCC extension: alignof(void) = 8 bits. Width = 0; @@ -806,87 +861,91 @@ ASTContext::getTypeInfo(const Type *T) const { break; case BuiltinType::Bool: - Width = Target.getBoolWidth(); - Align = Target.getBoolAlign(); + Width = Target->getBoolWidth(); + Align = Target->getBoolAlign(); break; case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::SChar: - Width = Target.getCharWidth(); - Align = Target.getCharAlign(); + Width = Target->getCharWidth(); + Align = Target->getCharAlign(); break; case BuiltinType::WChar_S: case BuiltinType::WChar_U: - Width = Target.getWCharWidth(); - Align = Target.getWCharAlign(); + Width = Target->getWCharWidth(); + Align = Target->getWCharAlign(); break; case BuiltinType::Char16: - Width = Target.getChar16Width(); - Align = Target.getChar16Align(); + Width = Target->getChar16Width(); + Align = Target->getChar16Align(); break; case BuiltinType::Char32: - Width = Target.getChar32Width(); - Align = Target.getChar32Align(); + Width = Target->getChar32Width(); + Align = Target->getChar32Align(); break; case BuiltinType::UShort: case BuiltinType::Short: - Width = Target.getShortWidth(); - Align = Target.getShortAlign(); + Width = Target->getShortWidth(); + Align = Target->getShortAlign(); break; case BuiltinType::UInt: case BuiltinType::Int: - Width = Target.getIntWidth(); - Align = Target.getIntAlign(); + Width = Target->getIntWidth(); + Align = Target->getIntAlign(); break; case BuiltinType::ULong: case BuiltinType::Long: - Width = Target.getLongWidth(); - Align = Target.getLongAlign(); + Width = Target->getLongWidth(); + Align = Target->getLongAlign(); break; case BuiltinType::ULongLong: case BuiltinType::LongLong: - Width = Target.getLongLongWidth(); - Align = Target.getLongLongAlign(); + Width = Target->getLongLongWidth(); + Align = Target->getLongLongAlign(); break; case BuiltinType::Int128: case BuiltinType::UInt128: Width = 128; Align = 128; // int128_t is 128-bit aligned on all targets. break; + case BuiltinType::Half: + Width = Target->getHalfWidth(); + Align = Target->getHalfAlign(); + break; case BuiltinType::Float: - Width = Target.getFloatWidth(); - Align = Target.getFloatAlign(); + Width = Target->getFloatWidth(); + Align = Target->getFloatAlign(); break; case BuiltinType::Double: - Width = Target.getDoubleWidth(); - Align = Target.getDoubleAlign(); + Width = Target->getDoubleWidth(); + Align = Target->getDoubleAlign(); break; case BuiltinType::LongDouble: - Width = Target.getLongDoubleWidth(); - Align = Target.getLongDoubleAlign(); + Width = Target->getLongDoubleWidth(); + Align = Target->getLongDoubleAlign(); break; case BuiltinType::NullPtr: - Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) - Align = Target.getPointerAlign(0); // == sizeof(void*) + Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) + Align = Target->getPointerAlign(0); // == sizeof(void*) break; case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: - Width = Target.getPointerWidth(0); - Align = Target.getPointerAlign(0); + Width = Target->getPointerWidth(0); + Align = Target->getPointerAlign(0); break; } break; case Type::ObjCObjectPointer: - Width = Target.getPointerWidth(0); - Align = Target.getPointerAlign(0); + Width = Target->getPointerWidth(0); + Align = Target->getPointerAlign(0); break; case Type::BlockPointer: { unsigned AS = getTargetAddressSpace( cast<BlockPointerType>(T)->getPointeeType()); - Width = Target.getPointerWidth(AS); - Align = Target.getPointerAlign(AS); + Width = Target->getPointerWidth(AS); + Align = Target->getPointerAlign(AS); break; } case Type::LValueReference: @@ -895,14 +954,14 @@ ASTContext::getTypeInfo(const Type *T) const { // the pointer route. unsigned AS = getTargetAddressSpace( cast<ReferenceType>(T)->getPointeeType()); - Width = Target.getPointerWidth(AS); - Align = Target.getPointerAlign(AS); + Width = Target->getPointerWidth(AS); + Align = Target->getPointerAlign(AS); break; } case Type::Pointer: { unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); - Width = Target.getPointerWidth(AS); - Align = Target.getPointerAlign(AS); + Width = Target->getPointerWidth(AS); + Align = Target->getPointerAlign(AS); break; } case Type::MemberPointer: { @@ -1012,9 +1071,26 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo(getCanonicalType(T)); } + case Type::Atomic: { + std::pair<uint64_t, unsigned> Info + = getTypeInfo(cast<AtomicType>(T)->getValueType()); + Width = Info.first; + Align = Info.second; + if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() && + llvm::isPowerOf2_64(Width)) { + // We can potentially perform lock-free atomic operations for this + // type; promote the alignment appropriately. + // FIXME: We could potentially promote the width here as well... + // is that worthwhile? (Non-struct atomic types generally have + // power-of-two size anyway, but structs might not. Requires a bit + // of implementation work to make sure we zero out the extra bits.) + Align = static_cast<unsigned>(Width); + } + } + } - assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); + assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); return std::make_pair(Width, Align); } @@ -1063,19 +1139,6 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; } -/// ShallowCollectObjCIvars - -/// Collect all ivars, including those synthesized, in the current class. -/// -void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { - // FIXME. This need be removed but there are two many places which - // assume const-ness of ObjCInterfaceDecl - ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI); - for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; - Iv= Iv->getNextIvar()) - Ivars.push_back(Iv); -} - /// DeepCollectObjCIvars - /// This routine first collects all declared, but not synthesized, ivars in /// super class and then collects all ivars, including those synthesized for @@ -1084,17 +1147,16 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, /// void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { + SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const { if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) DeepCollectObjCIvars(SuperClass, false, Ivars); if (!leafClass) { for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), E = OI->ivar_end(); I != E; ++I) Ivars.push_back(*I); - } - else { + } else { ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI); - for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; + for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; Iv= Iv->getNextIvar()) Ivars.push_back(Iv); } @@ -1562,7 +1624,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // the target. llvm::APInt ArySize(ArySizeIn); ArySize = - ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy))); + ArySize.zextOrTrunc(Target->getPointerWidth(getTargetAddressSpace(EltTy))); llvm::FoldingSetNodeID ID; ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals); @@ -1670,6 +1732,12 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { break; } + case Type::Atomic: { + const AtomicType *at = cast<AtomicType>(ty); + result = getAtomicType(getVariableArrayDecayedType(at->getValueType())); + break; + } + case Type::ConstantArray: { const ConstantArrayType *cat = cast<ConstantArrayType>(ty); result = getConstantArrayType( @@ -2026,7 +2094,7 @@ ASTContext::getFunctionType(QualType ResultTy, // The exception spec is not part of the canonical type. QualType Canonical; if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { - llvm::SmallVector<QualType, 16> CanonicalArgs; + SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); @@ -2322,7 +2390,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, unsigned NumArgs = Args.size(); - llvm::SmallVector<TemplateArgument, 4> ArgVec; + SmallVector<TemplateArgument, 4> ArgVec; ArgVec.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); @@ -2389,7 +2457,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); - llvm::SmallVector<TemplateArgument, 4> CanonArgs; + SmallVector<TemplateArgument, 4> CanonArgs; CanonArgs.reserve(NumArgs); for (unsigned I = 0; I != NumArgs; ++I) CanonArgs.push_back(getCanonicalTemplateArgument(Args[I])); @@ -2509,7 +2577,7 @@ ASTContext::getDependentTemplateSpecializationType( const IdentifierInfo *Name, const TemplateArgumentListInfo &Args) const { // TODO: avoid this copy - llvm::SmallVector<TemplateArgument, 16> ArgCopy; + SmallVector<TemplateArgument, 16> ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) ArgCopy.push_back(Args[I].getArgument()); return getDependentTemplateSpecializationType(Keyword, NNS, Name, @@ -2543,7 +2611,7 @@ ASTContext::getDependentTemplateSpecializationType( if (Keyword == ETK_None) CanonKeyword = ETK_Typename; bool AnyNonCanonArgs = false; - llvm::SmallVector<TemplateArgument, 16> CanonArgs(NumArgs); + SmallVector<TemplateArgument, 16> CanonArgs(NumArgs); for (unsigned I = 0; I != NumArgs; ++I) { CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); if (!CanonArgs[I].structurallyEquals(Args[I])) @@ -2647,7 +2715,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType, bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); if (!ProtocolsSorted || !BaseType.isCanonical()) { if (!ProtocolsSorted) { - llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, + SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; @@ -2737,8 +2805,7 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const { // typeof(expr) type. Use that as our canonical type. toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, QualType((TypeOfExprType*)Canon, 0)); - } - else { + } else { // Build a new, canonical typeof(expr) type. Canon = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr); @@ -2821,8 +2888,7 @@ QualType ASTContext::getDecltypeType(Expr *e) const { // decltype type. Use that as our canonical type. dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy, QualType((DecltypeType*)Canon, 0)); - } - else { + } else { // Build a new, canonical typeof(expr) type. Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); DependentDecltypeTypes.InsertNode(Canon, InsertPos); @@ -2869,6 +2935,34 @@ QualType ASTContext::getAutoType(QualType DeducedType) const { return QualType(AT, 0); } +/// getAtomicType - Return the uniqued reference to the atomic type for +/// the given value type. +QualType ASTContext::getAtomicType(QualType T) const { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + AtomicType::Profile(ID, T); + + void *InsertPos = 0; + if (AtomicType *AT = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); + + // If the atomic value type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T.isCanonical()) { + Canonical = getAtomicType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; + } + AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical); + Types.push_back(New); + AtomicTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) @@ -2898,7 +2992,7 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in <stddef.h>. CanQualType ASTContext::getSizeType() const { - return getFromTargetType(Target.getSizeType()); + return getFromTargetType(Target->getSizeType()); } /// getSignedWCharType - Return the type of "signed wchar_t". @@ -2918,7 +3012,7 @@ QualType ASTContext::getUnsignedWCharType() const { /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType ASTContext::getPointerDiffType() const { - return getFromTargetType(Target.getPtrDiffType(0)); + return getFromTargetType(Target->getPtrDiffType(0)); } //===----------------------------------------------------------------------===// @@ -3183,8 +3277,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { } // Silence GCC warning - assert(false && "Unhandled template argument kind"); - return TemplateArgument(); + llvm_unreachable("Unhandled template argument kind"); } NestedNameSpecifier * @@ -3397,7 +3490,8 @@ static FloatingRank getFloatingRank(QualType T) { assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type"); switch (T->getAs<BuiltinType>()->getKind()) { - default: assert(0 && "getFloatingRank(): not a floating type"); + default: llvm_unreachable("getFloatingRank(): not a floating type"); + case BuiltinType::Half: return HalfRank; case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; case BuiltinType::LongDouble: return LongDoubleRank; @@ -3413,7 +3507,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, FloatingRank EltRank = getFloatingRank(Size); if (Domain->isComplexType()) { switch (EltRank) { - default: assert(0 && "getFloatingRank(): illegal value for rank"); + default: llvm_unreachable("getFloatingRank(): illegal value for rank"); case FloatRank: return FloatComplexTy; case DoubleRank: return DoubleComplexTy; case LongDoubleRank: return LongDoubleComplexTy; @@ -3422,7 +3516,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, assert(Domain->isRealFloatingType() && "Unknown domain!"); switch (EltRank) { - default: assert(0 && "getFloatingRank(): illegal value for rank"); + default: llvm_unreachable("getFloatingRank(): illegal value for rank"); case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; @@ -3454,16 +3548,16 @@ unsigned ASTContext::getIntegerRank(const Type *T) const { if (T->isSpecificBuiltinType(BuiltinType::WChar_S) || T->isSpecificBuiltinType(BuiltinType::WChar_U)) - T = getFromTargetType(Target.getWCharType()).getTypePtr(); + T = getFromTargetType(Target->getWCharType()).getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Char16)) - T = getFromTargetType(Target.getChar16Type()).getTypePtr(); + T = getFromTargetType(Target->getChar16Type()).getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Char32)) - T = getFromTargetType(Target.getChar32Type()).getTypePtr(); + T = getFromTargetType(Target->getChar32Type()).getTypePtr(); switch (cast<BuiltinType>(T)->getKind()) { - default: assert(0 && "getIntegerRank(): not a built-in integer"); + default: llvm_unreachable("getIntegerRank(): not a built-in integer"); case BuiltinType::Bool: return 1 + (getIntWidth(BoolTy) << 3); case BuiltinType::Char_S: @@ -3504,8 +3598,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { QualType FT = Field->getType(); - llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this); - uint64_t BitWidth = BitWidthAP.getZExtValue(); + uint64_t BitWidth = Field->getBitWidthValue(*this); uint64_t IntSize = getTypeSize(IntTy); // GCC extension compatibility: if the bit-field size is less than or equal // to the size of int, it gets promoted no matter what its type is. @@ -3653,82 +3746,6 @@ void ASTContext::setCFConstantStringType(QualType T) { CFConstantStringTypeDecl = Rec->getDecl(); } -// getNSConstantStringType - Return the type used for constant NSStrings. -QualType ASTContext::getNSConstantStringType() const { - if (!NSConstantStringTypeDecl) { - NSConstantStringTypeDecl = - CreateRecordDecl(*this, TTK_Struct, TUDecl, - &Idents.get("__builtin_NSString")); - NSConstantStringTypeDecl->startDefinition(); - - QualType FieldTypes[3]; - - // const int *isa; - FieldTypes[0] = getPointerType(IntTy.withConst()); - // const char *str; - FieldTypes[1] = getPointerType(CharTy.withConst()); - // unsigned int length; - FieldTypes[2] = UnsignedIntTy; - - // Create fields - for (unsigned i = 0; i < 3; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, - /*Mutable=*/false, - /*HasInit=*/false); - Field->setAccess(AS_public); - NSConstantStringTypeDecl->addDecl(Field); - } - - NSConstantStringTypeDecl->completeDefinition(); - } - - return getTagDeclType(NSConstantStringTypeDecl); -} - -void ASTContext::setNSConstantStringType(QualType T) { - const RecordType *Rec = T->getAs<RecordType>(); - assert(Rec && "Invalid NSConstantStringType"); - NSConstantStringTypeDecl = Rec->getDecl(); -} - -QualType ASTContext::getObjCFastEnumerationStateType() const { - if (!ObjCFastEnumerationStateTypeDecl) { - ObjCFastEnumerationStateTypeDecl = - CreateRecordDecl(*this, TTK_Struct, TUDecl, - &Idents.get("__objcFastEnumerationState")); - ObjCFastEnumerationStateTypeDecl->startDefinition(); - - QualType FieldTypes[] = { - UnsignedLongTy, - getPointerType(ObjCIdTypedefType), - getPointerType(UnsignedLongTy), - getConstantArrayType(UnsignedLongTy, - llvm::APInt(32, 5), ArrayType::Normal, 0) - }; - - for (size_t i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, - ObjCFastEnumerationStateTypeDecl, - SourceLocation(), - SourceLocation(), 0, - FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, - /*Mutable=*/false, - /*HasInit=*/false); - Field->setAccess(AS_public); - ObjCFastEnumerationStateTypeDecl->addDecl(Field); - } - - ObjCFastEnumerationStateTypeDecl->completeDefinition(); - } - - return getTagDeclType(ObjCFastEnumerationStateTypeDecl); -} - QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) return getTagDeclType(BlockDescriptorType); @@ -3768,12 +3785,6 @@ QualType ASTContext::getBlockDescriptorType() const { return getTagDeclType(BlockDescriptorType); } -void ASTContext::setBlockDescriptorType(QualType T) { - const RecordType *Rec = T->getAs<RecordType>(); - assert(Rec && "Invalid BlockDescriptorType"); - BlockDescriptorType = Rec->getDecl(); -} - QualType ASTContext::getBlockDescriptorExtendedType() const { if (BlockDescriptorExtendedType) return getTagDeclType(BlockDescriptorExtendedType); @@ -3817,12 +3828,6 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { return getTagDeclType(BlockDescriptorExtendedType); } -void ASTContext::setBlockDescriptorExtendedType(QualType T) { - const RecordType *Rec = T->getAs<RecordType>(); - assert(Rec && "Invalid BlockDescriptorType"); - BlockDescriptorExtendedType = Rec->getDecl(); -} - bool ASTContext::BlockRequiresCopying(QualType Ty) const { if (Ty->isObjCRetainableType()) return true; @@ -3837,7 +3842,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const { } QualType -ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { +ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { // type = struct __Block_byref_1_X { // void *__isa; // struct __Block_byref_1_X *__forwarding; @@ -3869,7 +3874,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { Ty }; - llvm::StringRef FieldNames[] = { + StringRef FieldNames[] = { "__isa", "__forwarding", "__flags", @@ -3897,10 +3902,15 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { return getPointerType(getTagDeclType(T)); } -void ASTContext::setObjCFastEnumerationStateType(QualType T) { - const RecordType *Rec = T->getAs<RecordType>(); - assert(Rec && "Invalid ObjCFAstEnumerationStateType"); - ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); +TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { + if (!ObjCInstanceTypeDecl) + ObjCInstanceTypeDecl = TypedefDecl::Create(*this, + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("instancetype"), + getTrivialTypeSourceInfo(getObjCIdType())); + return ObjCInstanceTypeDecl; } // This returns true if a type has been typedefed to BOOL: @@ -3962,7 +3972,6 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { S += charUnitsToString(ParmOffset); // Block pointer and offset. S += "@?0"; - ParmOffset = PtrSize; // Argument types. ParmOffset = PtrSize; @@ -4044,7 +4053,7 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // The first two arguments (self and _cmd) are pointers; account for // their size. CharUnits ParmOffset = 2 * PtrSize; - for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + for (ObjCMethodDecl::param_const_iterator PI = Decl->param_begin(), E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); @@ -4061,9 +4070,9 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Argument types. ParmOffset = 2 * PtrSize; - for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + for (ObjCMethodDecl::param_const_iterator PI = Decl->param_begin(), E = Decl->sel_param_end(); PI != E; ++PI) { - ParmVarDecl *PVDecl = *PI; + const ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { @@ -4166,6 +4175,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, case ObjCPropertyDecl::Assign: break; case ObjCPropertyDecl::Copy: S += ",C"; break; case ObjCPropertyDecl::Retain: S += ",&"; break; + case ObjCPropertyDecl::Weak: S += ",W"; break; } } @@ -4225,7 +4235,7 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { switch (T->getAs<BuiltinType>()->getKind()) { - default: assert(0 && "Unhandled builtin type kind"); + default: llvm_unreachable("Unhandled builtin type kind"); case BuiltinType::Void: return 'v'; case BuiltinType::Bool: return 'B'; case BuiltinType::Char_U: @@ -4252,10 +4262,20 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { } } +static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { + EnumDecl *Enum = ET->getDecl(); + + // The encoding of an non-fixed enum type is always 'i', regardless of size. + if (!Enum->isFixed()) + return 'i'; + + // The encoding of a fixed enum type matches its fixed underlying type. + return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType()); +} + static void EncodeBitField(const ASTContext *Ctx, std::string& S, QualType T, const FieldDecl *FD) { - const Expr *E = FD->getBitWidth(); - assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); + assert(FD->isBitField() && "not a bitfield - getObjCEncodingForTypeImpl"); S += 'b'; // The NeXT runtime encodes bit fields as b followed by the number of bits. // The GNU runtime requires more information; bitfields are encoded as b, @@ -4276,13 +4296,12 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, const RecordDecl *RD = FD->getParent(); const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); - if (T->isEnumeralType()) - S += 'i'; + if (const EnumType *ET = T->getAs<EnumType>()) + S += ObjCEncodingForEnumType(Ctx, ET); else S += ObjCEncodingForPrimitiveKind(Ctx, T); } - unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue(); - S += llvm::utostr(N); + S += llvm::utostr(FD->getBitWidthValue(*Ctx)); } // FIXME: Use SmallString for accumulating string. @@ -4342,7 +4361,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Another legacy compatibility encoding. Some ObjC qualifier and type // combinations need to be rearranged. // Rewrite "in const" from "nr" to "rn" - if (llvm::StringRef(S).endswith("nr")) + if (StringRef(S).endswith("nr")) S.replace(S.end()-2, S.end(), "rn"); } @@ -4423,7 +4442,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.data(), TemplateArgs.size(), - (*this).PrintingPolicy); + (*this).getPrintingPolicy()); S += TemplateArgsStr; } @@ -4463,11 +4482,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - if (T->isEnumeralType()) { + if (const EnumType *ET = T->getAs<EnumType>()) { if (FD && FD->isBitField()) EncodeBitField(this, S, T, FD); else - S += 'i'; + S += ObjCEncodingForEnumType(this, ET); return; } @@ -4487,10 +4506,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const IdentifierInfo *II = OI->getIdentifier(); S += II->getName(); S += '='; - llvm::SmallVector<ObjCIvarDecl*, 32> Ivars; + SmallVector<const ObjCIvarDecl*, 32> Ivars; DeepCollectObjCIvars(OI, true, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { - FieldDecl *Field = cast<FieldDecl>(Ivars[i]); + const FieldDecl *Field = cast<FieldDecl>(Ivars[i]); if (Field->isBitField()) getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); else @@ -4573,7 +4592,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - assert(0 && "@encode for type not implemented!"); + llvm_unreachable("@encode for type not implemented!"); } void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, @@ -4621,8 +4640,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (base->isEmpty()) continue; uint64_t offs = layout.getVBaseClassOffsetInBits(base); - FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), - std::make_pair(offs, base)); + if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end()) + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(), + std::make_pair(offs, base)); } } @@ -4637,7 +4657,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, std::multimap<uint64_t, NamedDecl *>::iterator CurLayObj = FieldOrBaseOffsets.begin(); - if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) { + if ((CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) || + (CurLayObj == FieldOrBaseOffsets.end() && + CXXRec && CXXRec->isDynamicClass())) { assert(CXXRec && CXXRec->isDynamicClass() && "Offset 0 was empty but no VTable ?"); if (FD) { @@ -4695,7 +4717,7 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (field->isBitField()) { EncodeBitField(this, S, field->getType(), field); - CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue(); + CurOffs += field->getBitWidthValue(*this); } else { QualType qt = field->getType(); getLegacyIntegralTypeEncoding(qt); @@ -4731,20 +4753,48 @@ void ASTContext::setBuiltinVaListType(QualType T) { BuiltinVaListType = T; } -void ASTContext::setObjCIdType(QualType T) { - ObjCIdTypedefType = T; +TypedefDecl *ASTContext::getObjCIdDecl() const { + if (!ObjCIdDecl) { + QualType T = getObjCObjectType(ObjCBuiltinIdTy, 0, 0); + T = getObjCObjectPointerType(T); + TypeSourceInfo *IdInfo = getTrivialTypeSourceInfo(T); + ObjCIdDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this), + getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Idents.get("id"), IdInfo); + } + + return ObjCIdDecl; } -void ASTContext::setObjCSelType(QualType T) { - ObjCSelTypedefType = T; +TypedefDecl *ASTContext::getObjCSelDecl() const { + if (!ObjCSelDecl) { + QualType SelT = getPointerType(ObjCBuiltinSelTy); + TypeSourceInfo *SelInfo = getTrivialTypeSourceInfo(SelT); + ObjCSelDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this), + getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Idents.get("SEL"), SelInfo); + } + return ObjCSelDecl; } void ASTContext::setObjCProtoType(QualType QT) { ObjCProtoType = QT; } -void ASTContext::setObjCClassType(QualType T) { - ObjCClassTypedefType = T; +TypedefDecl *ASTContext::getObjCClassDecl() const { + if (!ObjCClassDecl) { + QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0); + T = getObjCObjectPointerType(T); + TypeSourceInfo *ClassInfo = getTrivialTypeSourceInfo(T); + ObjCClassDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this), + getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Idents.get("Class"), ClassInfo); + } + + return ObjCClassDecl; } void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { @@ -4925,8 +4975,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { case TargetInfo::UnsignedLongLong: return UnsignedLongLongTy; } - assert(false && "Unhandled TargetInfo::IntType value"); - return CanQualType(); + llvm_unreachable("Unhandled TargetInfo::IntType value"); } //===----------------------------------------------------------------------===// @@ -4937,7 +4986,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { /// garbage collection attribute. /// Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const { - if (getLangOptions().getGCMode() == LangOptions::NonGC) + if (getLangOptions().getGC() == LangOptions::NonGC) return Qualifiers::GCNone; assert(getLangOptions().ObjC1); @@ -5261,7 +5310,7 @@ static void getIntersectionOfProtocols(ASTContext &Context, const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT, - llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { const ObjCObjectType* LHS = LHSOPT->getObjectType(); const ObjCObjectType* RHS = RHSOPT->getObjectType(); @@ -5287,8 +5336,7 @@ void getIntersectionOfProtocols(ASTContext &Context, for (unsigned i = 0; i < RHSNumProtocols; ++i) if (InheritedProtocolSet.count(RHSProtocols[i])) IntersectionOfProtocols.push_back(RHSProtocols[i]); - } - else { + } else { llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; Context.CollectInheritedProtocols(RHS->getInterface(), RHSInheritedProtocols); @@ -5317,7 +5365,7 @@ QualType ASTContext::areCommonBaseCompatible( do { LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); if (canAssignObjCInterfaces(LHS, RHS)) { - llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols; + SmallVector<ObjCProtocolDecl *, 8> Protocols; getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); QualType Result = QualType(LHS, 0); @@ -5552,13 +5600,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) return QualType(); - // It's noreturn if either type is. - // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. - bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); - if (NoReturn != lbaseInfo.getNoReturn()) + // functypes which return are preferred over those that do not. + if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn()) allLTypes = false; - if (NoReturn != rbaseInfo.getNoReturn()) + else if (!lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn()) allRTypes = false; + // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. + bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); @@ -5579,8 +5627,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->getTypeQuals() != rproto->getTypeQuals()) return QualType(); + if (LangOpts.ObjCAutoRefCount && + !FunctionTypesMatchOnNSConsumedAttrs(rproto, lproto)) + return QualType(); + // Check argument compatibility - llvm::SmallVector<QualType, 10> types; + SmallVector<QualType, 10> types; for (unsigned i = 0; i < lproto_nargs; i++) { QualType largtype = lproto->getArgType(i).getUnqualifiedType(); QualType rargtype = rproto->getArgType(i).getUnqualifiedType(); @@ -5603,6 +5655,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (getCanonicalType(argtype) != getCanonicalType(rargtype)) allRTypes = false; } + if (allLTypes) return lhs; if (allRTypes) return rhs; @@ -5756,22 +5809,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Non-canonical and dependent types shouldn't get here"); - return QualType(); + llvm_unreachable("Non-canonical and dependent types shouldn't get here"); case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: - assert(false && "C++ should never be in mergeTypes"); - return QualType(); + llvm_unreachable("C++ should never be in mergeTypes"); case Type::ObjCInterface: case Type::IncompleteArray: case Type::VariableArray: case Type::FunctionProto: case Type::ExtVector: - assert(false && "Types are eliminated above"); - return QualType(); + llvm_unreachable("Types are eliminated above"); case Type::Pointer: { @@ -5809,6 +5859,24 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return RHS; return getBlockPointerType(ResultType); } + case Type::Atomic: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSValue = LHS->getAs<AtomicType>()->getValueType(); + QualType RHSValue = RHS->getAs<AtomicType>()->getValueType(); + if (Unqualified) { + LHSValue = LHSValue.getUnqualifiedType(); + RHSValue = RHSValue.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSValue, RHSValue, false, + Unqualified); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSValue) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSValue) == getCanonicalType(ResultType)) + return RHS; + return getAtomicType(ResultType); + } case Type::ConstantArray: { const ConstantArrayType* LCAT = getAsConstantArrayType(LHS); @@ -5904,6 +5972,26 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return QualType(); } +bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs( + const FunctionProtoType *FromFunctionType, + const FunctionProtoType *ToFunctionType) { + if (FromFunctionType->hasAnyConsumedArgs() != + ToFunctionType->hasAnyConsumedArgs()) + return false; + FunctionProtoType::ExtProtoInfo FromEPI = + FromFunctionType->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo ToEPI = + ToFunctionType->getExtProtoInfo(); + if (FromEPI.ConsumedArguments && ToEPI.ConsumedArguments) + for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs(); + ArgIdx != NumArgs; ++ArgIdx) { + if (FromEPI.ConsumedArguments[ArgIdx] != + ToEPI.ConsumedArguments[ArgIdx]) + return false; + } + return true; +} + /// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and /// 'RHS' attributes and returns the merged version; including for function /// return types. @@ -6022,8 +6110,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) { case BuiltinType::Int128: return UnsignedInt128Ty; default: - assert(0 && "Unexpected signed integer type"); - return QualType(); + llvm_unreachable("Unexpected signed integer type"); } } @@ -6080,7 +6167,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // Read the base type. switch (*Str++) { - default: assert(0 && "Unknown builtin type letter!"); + default: llvm_unreachable("Unknown builtin type letter!"); case 'v': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); @@ -6183,7 +6270,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, assert(!RequiresICE && "Can't require complex ICE"); Type = Context.getComplexType(ElementType); break; - } + } + case 'Y' : { + Type = Context.getPointerDiffType(); + break; + } case 'P': Type = Context.getFILEType(); if (Type.isNull()) { @@ -6247,7 +6338,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, unsigned *IntegerConstantArgs) const { const char *TypeStr = BuiltinInfo.GetTypeString(Id); - llvm::SmallVector<QualType, 8> ArgTypes; + SmallVector<QualType, 8> ArgTypes; bool RequiresICE = false; Error = GE_None; @@ -6405,7 +6496,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // Forward declarations aren't required. if (!FD->doesThisDeclarationHaveABody()) - return false; + return FD->doesDeclarationForceExternallyVisibleDefinition(); // Constructors and destructors are required. if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) @@ -6431,7 +6522,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; return true; } - + const VarDecl *VD = cast<VarDecl>(D); assert(VD->isFileVarDecl() && "Expected file scoped var"); @@ -6472,30 +6563,42 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { } MangleContext *ASTContext::createMangleContext() { - switch (Target.getCXXABI()) { + switch (Target->getCXXABI()) { case CXXABI_ARM: case CXXABI_Itanium: return createItaniumMangleContext(*this, getDiagnostics()); case CXXABI_Microsoft: return createMicrosoftMangleContext(*this, getDiagnostics()); } - assert(0 && "Unsupported ABI"); - return 0; + llvm_unreachable("Unsupported ABI"); } CXXABI::~CXXABI() {} size_t ASTContext::getSideTableAllocatedMemory() const { - size_t bytes = 0; - bytes += ASTRecordLayouts.getMemorySize(); - bytes += ObjCLayouts.getMemorySize(); - bytes += KeyFunctions.getMemorySize(); - bytes += ObjCImpls.getMemorySize(); - bytes += BlockVarCopyInits.getMemorySize(); - bytes += DeclAttrs.getMemorySize(); - bytes += InstantiatedFromStaticDataMember.getMemorySize(); - bytes += InstantiatedFromUsingDecl.getMemorySize(); - bytes += InstantiatedFromUsingShadowDecl.getMemorySize(); - bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize(); - return bytes; + return ASTRecordLayouts.getMemorySize() + + llvm::capacity_in_bytes(ObjCLayouts) + + llvm::capacity_in_bytes(KeyFunctions) + + llvm::capacity_in_bytes(ObjCImpls) + + llvm::capacity_in_bytes(BlockVarCopyInits) + + llvm::capacity_in_bytes(DeclAttrs) + + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember) + + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) + + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) + + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + + llvm::capacity_in_bytes(OverriddenMethods) + + llvm::capacity_in_bytes(Types) + + llvm::capacity_in_bytes(VariableArrayTypes) + + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); +} + +void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { + ParamIndices[D] = index; +} + +unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const { + ParameterIndexTable::const_iterator I = ParamIndices.find(D); + assert(I != ParamIndices.end() && + "ParmIndices lacks entry set by ParmVarDecl"); + return I->second; } diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp index 7c91b5c..07820dc 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp @@ -152,16 +152,16 @@ break; \ /// diagnostic message static std::string ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, - const Diagnostic::ArgumentValue *PrevArgs, + const DiagnosticsEngine::ArgumentValue *PrevArgs, unsigned NumPrevArgs, - llvm::SmallVectorImpl<intptr_t> &QualTypeVals) { + SmallVectorImpl<intptr_t> &QualTypeVals) { // FIXME: Playing with std::string is really slow. bool ForceAKA = false; QualType CanTy = Ty.getCanonicalType(); - std::string S = Ty.getAsString(Context.PrintingPolicy); - std::string CanS = CanTy.getAsString(Context.PrintingPolicy); + std::string S = Ty.getAsString(Context.getPrintingPolicy()); + std::string CanS = CanTy.getAsString(Context.getPrintingPolicy()); - for (llvm::SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(), + for (SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(), E = QualTypeVals.end(); I != E; ++I) { QualType CompareTy = QualType::getFromOpaquePtr(reinterpret_cast<void*>(*I)); @@ -170,10 +170,10 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, QualType CompareCanTy = CompareTy.getCanonicalType(); if (CompareCanTy == CanTy) continue; // Same canonical types - std::string CompareS = CompareTy.getAsString(Context.PrintingPolicy); + std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy()); if (CompareS != S) continue; // Original strings are different - std::string CompareCanS = CompareCanTy.getAsString(Context.PrintingPolicy); + std::string CompareCanS = CompareCanTy.getAsString(Context.getPrintingPolicy()); if (CompareCanS == CanS) continue; // No new info from canonical type @@ -186,7 +186,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, bool Repeated = false; for (unsigned i = 0; i != NumPrevArgs; ++i) { // TODO: Handle ak_declcontext case. - if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + if (PrevArgs[i].first == DiagnosticsEngine::ak_qualtype) { void *Ptr = (void*)PrevArgs[i].second; QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); if (PrevTy == Ty) { @@ -205,7 +205,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, if (DesugaredTy == Ty) { DesugaredTy = Ty.getCanonicalType(); } - std::string akaStr = DesugaredTy.getAsString(Context.PrintingPolicy); + std::string akaStr = DesugaredTy.getAsString(Context.getPrintingPolicy()); if (akaStr != S) { S = "'" + S + "' (aka '" + akaStr + "')"; return S; @@ -218,25 +218,25 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, } void clang::FormatASTNodeDiagnosticArgument( - Diagnostic::ArgumentKind Kind, + DiagnosticsEngine::ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, - const Diagnostic::ArgumentValue *PrevArgs, + const DiagnosticsEngine::ArgumentValue *PrevArgs, unsigned NumPrevArgs, - llvm::SmallVectorImpl<char> &Output, + SmallVectorImpl<char> &Output, void *Cookie, - llvm::SmallVectorImpl<intptr_t> &QualTypeVals) { + SmallVectorImpl<intptr_t> &QualTypeVals) { ASTContext &Context = *static_cast<ASTContext*>(Cookie); std::string S; bool NeedQuotes = true; switch (Kind) { - default: assert(0 && "unknown ArgumentKind"); - case Diagnostic::ak_qualtype: { + default: llvm_unreachable("unknown ArgumentKind"); + case DiagnosticsEngine::ak_qualtype: { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); @@ -246,7 +246,7 @@ void clang::FormatASTNodeDiagnosticArgument( NeedQuotes = false; break; } - case Diagnostic::ak_declarationname: { + case DiagnosticsEngine::ak_declarationname: { DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); S = N.getAsString(); @@ -260,7 +260,7 @@ void clang::FormatASTNodeDiagnosticArgument( "Invalid modifier for DeclarationName argument"); break; } - case Diagnostic::ak_nameddecl: { + case DiagnosticsEngine::ak_nameddecl: { bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) Qualified = true; @@ -269,18 +269,18 @@ void clang::FormatASTNodeDiagnosticArgument( "Invalid modifier for NamedDecl* argument"); Qualified = false; } - reinterpret_cast<NamedDecl*>(Val)-> - getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); + const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val); + ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified); break; } - case Diagnostic::ak_nestednamespec: { + case DiagnosticsEngine::ak_nestednamespec: { llvm::raw_string_ostream OS(S); reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, - Context.PrintingPolicy); + Context.getPrintingPolicy()); NeedQuotes = false; break; } - case Diagnostic::ak_declcontext: { + case DiagnosticsEngine::ak_declcontext: { DeclContext *DC = reinterpret_cast<DeclContext *> (Val); assert(DC && "Should never have a null declaration context"); @@ -305,7 +305,7 @@ void clang::FormatASTNodeDiagnosticArgument( S += "function "; S += "'"; - ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true); S += "'"; } NeedQuotes = false; diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index f5e392f..af66b04 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -59,6 +59,7 @@ namespace { QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T); QualType VisitFunctionProtoType(const FunctionProtoType *T); // FIXME: UnresolvedUsingType + QualType VisitParenType(const ParenType *T); QualType VisitTypedefType(const TypedefType *T); QualType VisitTypeOfExprType(const TypeOfExprType *T); // FIXME: DependentTypeOfExprType @@ -83,16 +84,20 @@ namespace { bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, SourceLocation &Loc); + void ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = 0); void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); - bool ImportDefinition(RecordDecl *From, RecordDecl *To); + bool ImportDefinition(RecordDecl *From, RecordDecl *To, + bool ForceImport = false); + bool ImportDefinition(EnumDecl *From, EnumDecl *To, + bool ForceImport = false); TemplateParameterList *ImportTemplateParameterList( TemplateParameterList *Params); TemplateArgument ImportTemplateArgument(const TemplateArgument &From); bool ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, - llvm::SmallVectorImpl<TemplateArgument> &ToArgs); + SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); @@ -805,12 +810,74 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; } - + + case Type::Atomic: { + if (!IsStructurallyEquivalent(Context, + cast<AtomicType>(T1)->getValueType(), + cast<AtomicType>(T2)->getValueType())) + return false; + break; + } + } // end switch return true; } +/// \brief Determine structural equivalence of two fields. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FieldDecl *Field1, FieldDecl *Field2) { + RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); + + if (!IsStructurallyEquivalent(Context, + Field1->getType(), Field2->getType())) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + if (Field1->isBitField()) { + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Field1->getBitWidthValue(Context.C1); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Field2->getBitWidthValue(Context.C2); + Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + unsigned Bits1 = Field1->getBitWidthValue(Context.C1); + unsigned Bits2 = Field2->getBitWidthValue(Context.C2); + + if (Bits1 != Bits2) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() << Bits2; + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() << Bits1; + return false; + } + } + + return true; +} + /// \brief Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -928,61 +995,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } - if (!IsStructurallyEquivalent(Context, - Field1->getType(), Field2->getType())) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - return false; - } - - if (Field1->isBitField() != Field2->isBitField()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - if (Field1->isBitField()) { - llvm::APSInt Bits; - Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1); - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Bits.toString(10, false); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - llvm::APSInt Bits; - Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Bits.toString(10, false); - Context.Diag1(Field1->getLocation(), - diag::note_odr_not_bit_field) - << Field1->getDeclName(); - } - return false; - } - - if (Field1->isBitField()) { - // Make sure that the bit-fields are the same length. - llvm::APSInt Bits1, Bits2; - if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1)) - return false; - if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2)) - return false; - - if (!IsSameValue(Bits1, Bits2)) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Bits2.toString(10, false); - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Bits1.toString(10, false); - return false; - } - } + if (!IsStructurallyEquivalent(Context, *Field1, *Field2)) + return false; } if (Field2 != Field2End) { @@ -1360,6 +1374,7 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { case BuiltinType::Long : return Importer.getToContext().LongTy; case BuiltinType::LongLong : return Importer.getToContext().LongLongTy; case BuiltinType::Int128 : return Importer.getToContext().Int128Ty; + case BuiltinType::Half: return Importer.getToContext().HalfTy; case BuiltinType::Float: return Importer.getToContext().FloatTy; case BuiltinType::Double: return Importer.getToContext().DoubleTy; case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy; @@ -1518,7 +1533,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { return QualType(); // Import argument types - llvm::SmallVector<QualType, 4> ArgTypes; + SmallVector<QualType, 4> ArgTypes; for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), AEnd = T->arg_type_end(); A != AEnd; ++A) { @@ -1529,7 +1544,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { } // Import exception types - llvm::SmallVector<QualType, 4> ExceptionTypes; + SmallVector<QualType, 4> ExceptionTypes; for (FunctionProtoType::exception_iterator E = T->exception_begin(), EEnd = T->exception_end(); E != EEnd; ++E) { @@ -1546,6 +1561,14 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ArgTypes.size(), EPI); } +QualType ASTNodeImporter::VisitParenType(const ParenType *T) { + QualType ToInnerType = Importer.Import(T->getInnerType()); + if (ToInnerType.isNull()) + return QualType(); + + return Importer.getToContext().getParenType(ToInnerType); +} + QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { TypedefNameDecl *ToDecl = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl())); @@ -1628,7 +1651,7 @@ QualType ASTNodeImporter::VisitTemplateSpecializationType( if (ToTemplate.isNull()) return QualType(); - llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs; + SmallVector<TemplateArgument, 2> ToTemplateArgs; if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs)) return QualType(); @@ -1677,7 +1700,7 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { if (ToBaseType.isNull()) return QualType(); - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + SmallVector<ObjCProtocolDecl *, 4> Protocols; for (ObjCObjectType::qual_iterator P = T->qual_begin(), PEnd = T->qual_end(); P != PEnd; ++P) { @@ -1731,6 +1754,35 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, return false; } +void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { + if (!FromD) + return; + + if (!ToD) { + ToD = Importer.Import(FromD); + if (!ToD) + return; + } + + if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) { + if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) { + if (FromRecord->getDefinition() && !ToRecord->getDefinition()) { + ImportDefinition(FromRecord, ToRecord); + } + } + return; + } + + if (EnumDecl *FromEnum = dyn_cast<EnumDecl>(FromD)) { + if (EnumDecl *ToEnum = cast_or_null<EnumDecl>(ToD)) { + if (FromEnum->getDefinition() && !ToEnum->getDefinition()) { + ImportDefinition(FromEnum, ToEnum); + } + } + return; + } +} + void ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To) { @@ -1761,16 +1813,13 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, To.setNamedTypeInfo(Importer.Import(FromTInfo)); return; } - assert(0 && "Unknown name kind."); + llvm_unreachable("Unknown name kind."); } } void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { if (Importer.isMinimalImport() && !ForceImport) { - if (DeclContext *ToDC = Importer.ImportContext(FromDC)) { - ToDC->setHasExternalLexicalStorage(); - ToDC->setHasExternalVisibleStorage(); - } + Importer.ImportContext(FromDC); return; } @@ -1781,8 +1830,9 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { Importer.Import(*From); } -bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { - if (To->getDefinition()) +bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, + bool ForceImport) { + if (To->getDefinition() || To->isBeingDefined()) return false; To->startDefinition(); @@ -1791,7 +1841,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) { CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From); - llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + SmallVector<CXXBaseSpecifier *, 4> Bases; for (CXXRecordDecl::base_class_iterator Base1 = FromCXX->bases_begin(), FromBaseEnd = FromCXX->bases_end(); @@ -1804,7 +1854,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { SourceLocation EllipsisLoc; if (Base1->isPackExpansion()) EllipsisLoc = Importer.Import(Base1->getEllipsisLoc()); - + + // Ensure that we have a definition for the base. + ImportDefinitionIfNeeded(Base1->getType()->getAsCXXRecordDecl()); + Bases.push_back( new (Importer.getToContext()) CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), @@ -1818,14 +1871,39 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { ToCXX->setBases(Bases.data(), Bases.size()); } - ImportDeclContext(From); + ImportDeclContext(From, ForceImport); To->completeDefinition(); return false; } +bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, + bool ForceImport) { + if (To->getDefinition() || To->isBeingDefined()) + return false; + + To->startDefinition(); + + QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(From)); + if (T.isNull()) + return true; + + QualType ToPromotionType = Importer.Import(From->getPromotionType()); + if (ToPromotionType.isNull()) + return true; + + ImportDeclContext(From, ForceImport); + + // FIXME: we might need to merge the number of positive or negative bits + // if the enumerator lists don't match. + To->completeDefinition(T, ToPromotionType, + From->getNumPositiveBits(), + From->getNumNegativeBits()); + return false; +} + TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( TemplateParameterList *Params) { - llvm::SmallVector<NamedDecl *, 4> ToParams; + SmallVector<NamedDecl *, 4> ToParams; ToParams.reserve(Params->size()); for (TemplateParameterList::iterator P = Params->begin(), PEnd = Params->end(); @@ -1892,7 +1970,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { return TemplateArgument(); case TemplateArgument::Pack: { - llvm::SmallVector<TemplateArgument, 2> ToPack; + SmallVector<TemplateArgument, 2> ToPack; ToPack.reserve(From.pack_size()); if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack)) return TemplateArgument(); @@ -1910,7 +1988,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, - llvm::SmallVectorImpl<TemplateArgument> &ToArgs) { + SmallVectorImpl<TemplateArgument> &ToArgs) { for (unsigned I = 0; I != NumFromArgs; ++I) { TemplateArgument To = ImportTemplateArgument(FromArgs[I]); if (To.isNull() && !FromArgs[I].isNull()) @@ -1969,20 +2047,20 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { else MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace(); } else { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) + SmallVector<NamedDecl *, 4> ConflictingDecls; + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; - if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) { + if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(FoundDecls[I])) { MergeWithNamespace = FoundNS; ConflictingDecls.clear(); break; } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2029,21 +2107,21 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { // seen a typedef with the same name (that we can merge with) or any // other entity by that name (which name lookup could conflict with). if (!DC->isFunctionOrMethod()) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; if (TypedefNameDecl *FoundTypedef = - dyn_cast<TypedefNameDecl>(*Lookup.first)) { + dyn_cast<TypedefNameDecl>(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), FoundTypedef->getUnderlyingType())) return Importer.Imported(D, FoundTypedef); } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2065,15 +2143,16 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { SourceLocation StartL = Importer.Import(D->getLocStart()); TypedefNameDecl *ToTypedef; if (IsAlias) + ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, + StartL, Loc, + Name.getAsIdentifierInfo(), + TInfo); + else ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, StartL, Loc, Name.getAsIdentifierInfo(), TInfo); - else - ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, - StartL, Loc, - Name.getAsIdentifierInfo(), - TInfo); + ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); @@ -2109,14 +2188,14 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // We may already have an enum of the same name; try to find and match it. if (!DC->isFunctionOrMethod() && SearchName) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + SmallVector<NamedDecl *, 4> ConflictingDecls; + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(SearchName, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); @@ -2127,7 +2206,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { return Importer.Imported(D, FoundEnum); } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2157,25 +2236,9 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { D2->setIntegerType(ToIntegerType); // Import the definition - if (D->isDefinition()) { - QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D)); - if (T.isNull()) - return 0; + if (D->isCompleteDefinition() && ImportDefinition(D, D2)) + return 0; - QualType ToPromotionType = Importer.Import(D->getPromotionType()); - if (ToPromotionType.isNull()) - return 0; - - D2->startDefinition(); - ImportDeclContext(D); - - // FIXME: we might need to merge the number of positive or negative bits - // if the enumerator lists don't match. - D2->completeDefinition(T, ToPromotionType, - D->getNumPositiveBits(), - D->getNumNegativeBits()); - } - return D2; } @@ -2211,14 +2274,14 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // We may already have a record of the same name; try to find and match it. RecordDecl *AdoptDecl = 0; if (!DC->isFunctionOrMethod() && SearchName) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + SmallVector<NamedDecl *, 4> ConflictingDecls; + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(SearchName, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); @@ -2226,7 +2289,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { - if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + if (!D->isCompleteDefinition() || IsStructuralMatch(D, FoundDef)) { // The record types structurally match, or the "from" translation // unit only had a forward declaration anyway; call it the same // function. @@ -2241,7 +2304,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2274,7 +2337,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Importer.Imported(D, D2); - if (D->isDefinition() && ImportDefinition(D, D2)) + if (D->isCompleteDefinition() && ImportDefinition(D, D2)) return 0; return D2; @@ -2295,15 +2358,15 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { // Determine whether there are any other declarations with the same name and // in the same context. if (!LexicalDC->isFunctionOrMethod()) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2341,15 +2404,15 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. if (!LexicalDC->isFunctionOrMethod()) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) { + if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { if (isExternalLinkage(FoundFunction->getLinkage()) && isExternalLinkage(D->getLinkage())) { if (Importer.IsStructurallyEquivalent(D->getType(), @@ -2374,7 +2437,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -2396,7 +2459,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return 0; // Import the function parameters. - llvm::SmallVector<ParmVarDecl *, 8> Parameters; + SmallVector<ParmVarDecl *, 8> Parameters; for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) { ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P)); @@ -2416,7 +2479,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), - D->isImplicit()); + D->isImplicit(), + D->isConstexpr()); } else if (isa<CXXDestructorDecl>(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), @@ -2432,6 +2496,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, D->isInlineSpecified(), FromConversion->isExplicit(), + D->isConstexpr(), Importer.Import(D->getLocEnd())); } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ToFunction = CXXMethodDecl::Create(Importer.getToContext(), @@ -2441,6 +2506,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { Method->isStatic(), Method->getStorageClassAsWritten(), Method->isInlineSpecified(), + D->isConstexpr(), Importer.Import(D->getLocEnd())); } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, @@ -2448,7 +2514,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), - D->hasWrittenPrototype()); + D->hasWrittenPrototype(), + D->isConstexpr()); } // Import the qualifier, if any. @@ -2465,7 +2532,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { Parameters[I]->setOwningFunction(ToFunction); ToFunction->addDecl(Parameters[I]); } - ToFunction->setParams(Parameters.data(), Parameters.size()); + ToFunction->setParams(Parameters); // FIXME: Other bits to merge? @@ -2499,6 +2566,25 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; + // Determine whether we've already imported this field. + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundField->getType())) { + Importer.Imported(D, FoundField); + return FoundField; + } + + Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + << Name << D->getType() << FoundField->getType(); + Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) + << FoundField->getType(); + return 0; + } + } + // Import the type. QualType T = Importer.Import(D->getType()); if (T.isNull()) @@ -2531,6 +2617,26 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; + // Determine whether we've already imported this field. + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (IndirectFieldDecl *FoundField + = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundField->getType())) { + Importer.Imported(D, FoundField); + return FoundField; + } + + Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + << Name << D->getType() << FoundField->getType(); + Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) + << FoundField->getType(); + return 0; + } + } + // Import the type. QualType T = Importer.Import(D->getType()); if (T.isNull()) @@ -2568,10 +2674,10 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { return 0; // Determine whether we've already imported this ivar - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(*Lookup.first)) { + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { Importer.Imported(D, FoundIvar); @@ -2621,15 +2727,15 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { // in the same context as the variable we're importing. if (D->isFileVarDecl()) { VarDecl *MergeWithVar = 0; - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) { + if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. if (isExternalLinkage(FoundVar->getLinkage()) && isExternalLinkage(D->getLinkage())) { @@ -2668,7 +2774,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (MergeWithVar) { @@ -2794,10 +2900,10 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(*Lookup.first)) { + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) { if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) continue; @@ -2872,6 +2978,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { D->isInstanceMethod(), D->isVariadic(), D->isSynthesized(), + D->isImplicit(), D->isDefined(), D->getImplementationControl(), D->hasRelatedResultType()); @@ -2880,7 +2987,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // deal with implicit parameters. // Import the parameters - llvm::SmallVector<ParmVarDecl *, 5> ToParams; + SmallVector<ParmVarDecl *, 5> ToParams; for (ObjCMethodDecl::param_iterator FromP = D->param_begin(), FromPEnd = D->param_end(); FromP != FromPEnd; @@ -2897,9 +3004,9 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ToParams[I]->setOwningFunction(ToMethod); ToMethod->addDecl(ToParams[I]); } - ToMethod->setMethodParams(Importer.getToContext(), - ToParams.data(), ToParams.size(), - ToParams.size()); + SmallVector<SourceLocation, 12> SelLocs; + D->getSelectorLocs(SelLocs); + ToMethod->setMethodParams(Importer.getToContext(), ToParams, SelLocs); ToMethod->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToMethod); @@ -2926,21 +3033,18 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { ObjCCategoryDecl *ToCategory = MergeWithCategory; if (!ToCategory) { ToCategory = ObjCCategoryDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getAtLoc()), + Importer.Import(D->getAtStartLoc()), Loc, Importer.Import(D->getCategoryNameLoc()), - Name.getAsIdentifierInfo()); + Name.getAsIdentifierInfo(), + ToInterface); ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDecl(ToCategory); Importer.Imported(D, ToCategory); - // Link this category into its class's category list. - ToCategory->setClassInterface(ToInterface); - ToCategory->insertNextClassCategory(); - // Import protocols - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + SmallVector<ObjCProtocolDecl *, 4> Protocols; + SmallVector<SourceLocation, 4> ProtocolLocs; ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); for (ObjCCategoryDecl::protocol_iterator FromProto = D->protocol_begin(), @@ -2989,21 +3093,22 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { return 0; ObjCProtocolDecl *MergeWithProtocol = 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) continue; - if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(*Lookup.first))) + if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(FoundDecls[I]))) break; } ObjCProtocolDecl *ToProto = MergeWithProtocol; if (!ToProto || ToProto->isForwardDecl()) { if (!ToProto) { - ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo()); + ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, + Name.getAsIdentifierInfo(), Loc, + Importer.Import(D->getAtStartLoc())); ToProto->setForwardDecl(D->isForwardDecl()); ToProto->setLexicalDeclContext(LexicalDC); LexicalDC->addDecl(ToProto); @@ -3011,8 +3116,8 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { Importer.Imported(D, ToProto); // Import protocols - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + SmallVector<ObjCProtocolDecl *, 4> Protocols; + SmallVector<SourceLocation, 4> ProtocolLocs; ObjCProtocolDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(), @@ -3049,23 +3154,22 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { return 0; ObjCInterfaceDecl *MergeWithIface = 0; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first))) + if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(FoundDecls[I]))) break; } ObjCInterfaceDecl *ToIface = MergeWithIface; if (!ToIface || ToIface->isForwardDecl()) { if (!ToIface) { - ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), - DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getClassLoc()), + ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getAtStartLoc()), + Name.getAsIdentifierInfo(), Loc, D->isForwardDecl(), D->isImplicitInterfaceDecl()); ToIface->setForwardDecl(D->isForwardDecl()); @@ -3085,8 +3189,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { } // Import protocols - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + SmallVector<ObjCProtocolDecl *, 4> Protocols; + SmallVector<SourceLocation, 4> ProtocolLocs; ObjCInterfaceDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); @@ -3175,9 +3279,10 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { return 0; ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getLocation()), Importer.Import(D->getIdentifier()), - Category->getClassInterface()); + Category->getClassInterface(), + Importer.Import(D->getLocation()), + Importer.Import(D->getAtStartLoc())); DeclContext *LexicalDC = DC; if (D->getDeclContext() != D->getLexicalDeclContext()) { @@ -3219,8 +3324,9 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { // now. Impl = ObjCImplementationDecl::Create(Importer.getToContext(), Importer.ImportContext(D->getDeclContext()), + Iface, Super, Importer.Import(D->getLocation()), - Iface, Super); + Importer.Import(D->getAtStartLoc())); if (D->getDeclContext() != D->getLexicalDeclContext()) { DeclContext *LexicalDC @@ -3279,11 +3385,11 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return 0; // Check whether we have already imported this property. - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCPropertyDecl *FoundProp - = dyn_cast<ObjCPropertyDecl>(*Lookup.first)) { + = dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { @@ -3430,8 +3536,8 @@ ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { // Import the location of this declaration. SourceLocation Loc = Importer.Import(D->getLocation()); - llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; - llvm::SmallVector<SourceLocation, 4> Locations; + SmallVector<ObjCProtocolDecl *, 4> Protocols; + SmallVector<SourceLocation, 4> Locations; ObjCForwardProtocolDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); for (ObjCForwardProtocolDecl::protocol_iterator FromProto @@ -3472,25 +3578,14 @@ Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) { // Import the location of this declaration. SourceLocation Loc = Importer.Import(D->getLocation()); - - llvm::SmallVector<ObjCInterfaceDecl *, 4> Interfaces; - llvm::SmallVector<SourceLocation, 4> Locations; - for (ObjCClassDecl::iterator From = D->begin(), FromEnd = D->end(); - From != FromEnd; ++From) { - ObjCInterfaceDecl *ToIface - = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface())); - if (!ToIface) - continue; - - Interfaces.push_back(ToIface); - Locations.push_back(Importer.Import(From->getLocation())); - } - + ObjCClassDecl::ObjCClassRef *From = D->getForwardDecl(); + ObjCInterfaceDecl *ToIface + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface())); ObjCClassDecl *ToClass = ObjCClassDecl::Create(Importer.getToContext(), DC, - Loc, - Interfaces.data(), - Locations.data(), - Interfaces.size()); + Loc, + ToIface, + Importer.Import(From->getLocation())); + ToClass->setLexicalDeclContext(LexicalDC); LexicalDC->addDecl(ToClass); Importer.Imported(D, ToClass); @@ -3594,14 +3689,14 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // We may already have a template of the same name; try to find and match it. if (!DC->isFunctionOrMethod()) { - llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; - for (DeclContext::lookup_result Lookup = DC->lookup(Name); - Lookup.first != Lookup.second; - ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + SmallVector<NamedDecl *, 4> ConflictingDecls; + llvm::SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - Decl *Found = *Lookup.first; + Decl *Found = FoundDecls[I]; if (ClassTemplateDecl *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found)) { if (IsStructuralMatch(D, FoundTemplate)) { @@ -3614,7 +3709,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } - ConflictingDecls.push_back(*Lookup.first); + ConflictingDecls.push_back(FoundDecls[I]); } if (!ConflictingDecls.empty()) { @@ -3660,7 +3755,8 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { Importer.Imported(D, D2); Importer.Imported(DTemplated, D2Templated); - if (DTemplated->isDefinition() && !D2Templated->isDefinition()) { + if (DTemplated->isCompleteDefinition() && + !D2Templated->isCompleteDefinition()) { // FIXME: Import definition! } @@ -3704,7 +3800,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( SourceLocation IdLoc = Importer.Import(D->getLocation()); // Import template arguments. - llvm::SmallVector<TemplateArgument, 2> TemplateArgs; + SmallVector<TemplateArgument, 2> TemplateArgs; if (ImportTemplateArguments(D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) @@ -3722,7 +3818,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( // FIXME: Check for specialization vs. instantiation errors. if (RecordDecl *FoundDef = D2->getDefinition()) { - if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + if (!D->isCompleteDefinition() || IsStructuralMatch(D, FoundDef)) { // The record types structurally match, or the "from" translation // unit only had a forward declaration anyway; call it the same // function. @@ -3752,7 +3848,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( } Importer.Imported(D, D2); - if (D->isDefinition() && ImportDefinition(D, D2)) + if (D->isCompleteDefinition() && ImportDefinition(D, D2)) return 0; return D2; @@ -3792,14 +3888,17 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) return 0; - - return DeclRefExpr::Create(Importer.getToContext(), - Importer.Import(E->getQualifierLoc()), - ToD, - Importer.Import(E->getLocation()), - T, E->getValueKind(), - FoundD, - /*FIXME:TemplateArgs=*/0); + + DeclRefExpr *DRE = DeclRefExpr::Create(Importer.getToContext(), + Importer.Import(E->getQualifierLoc()), + ToD, + Importer.Import(E->getLocation()), + T, E->getValueKind(), + FoundD, + /*FIXME:TemplateArgs=*/0); + if (E->hadMultipleCandidates()) + DRE->setHadMultipleCandidates(true); + return DRE; } Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { @@ -3817,8 +3916,8 @@ Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) { if (T.isNull()) return 0; - return new (Importer.getToContext()) CharacterLiteral(E->getValue(), - E->isWide(), T, + return new (Importer.getToContext()) CharacterLiteral(E->getValue(), + E->getKind(), T, Importer.Import(E->getLocation())); } @@ -4024,13 +4123,17 @@ Decl *ASTImporter::Import(Decl *FromD) { if (!FromD) return 0; + ASTNodeImporter Importer(*this); + // Check whether we've already imported this declaration. llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); - if (Pos != ImportedDecls.end()) - return Pos->second; + if (Pos != ImportedDecls.end()) { + Decl *ToD = Pos->second; + Importer.ImportDefinitionIfNeeded(FromD, ToD); + return ToD; + } // Import the type - ASTNodeImporter Importer(*this); Decl *ToD = Importer.Visit(FromD); if (!ToD) return 0; @@ -4045,7 +4148,7 @@ Decl *ASTImporter::Import(Decl *FromD) { } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) { // When we've finished transforming a typedef, see whether it was the // typedef for an anonymous tag. - for (llvm::SmallVector<TagDecl *, 4>::iterator + for (SmallVector<TagDecl *, 4>::iterator FromTag = AnonTagsWithPendingTypedefs.begin(), FromTagEnd = AnonTagsWithPendingTypedefs.end(); FromTag != FromTagEnd; ++FromTag) { @@ -4252,7 +4355,7 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) { std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); SourceManager &ToSM = ToContext.getSourceManager(); return ToSM.getLocForStartOfFile(Import(Decomposed.first)) - .getFileLocWithOffset(Decomposed.second); + .getLocWithOffset(Decomposed.second); } SourceRange ASTImporter::Import(SourceRange FromRange) { @@ -4306,6 +4409,23 @@ void ASTImporter::ImportDefinition(Decl *From) { if (DeclContext *FromDC = cast<DeclContext>(From)) { ASTNodeImporter Importer(*this); + + if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(To)) { + if (!ToRecord->getDefinition()) { + Importer.ImportDefinition(cast<RecordDecl>(FromDC), ToRecord, + /*ForceImport=*/true); + return; + } + } + + if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(To)) { + if (!ToEnum->getDefinition()) { + Importer.ImportDefinition(cast<EnumDecl>(FromDC), ToEnum, + /*ForceImport=*/true); + return; + } + } + Importer.ImportDeclContext(FromDC, true); } } @@ -4378,7 +4498,7 @@ Selector ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) return Selector(); - llvm::SmallVector<IdentifierInfo *, 4> Idents; + SmallVector<IdentifierInfo *, 4> Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I) Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I))); diff --git a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp index 9ffe1f8..f29bfd1 100644 --- a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp +++ b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp @@ -119,7 +119,7 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, void *OpaqueData, bool AllowShortCircuit) const { - llvm::SmallVector<const CXXRecordDecl*, 8> Queue; + SmallVector<const CXXRecordDecl*, 8> Queue; const CXXRecordDecl *Record = this; bool AllMatches = true; @@ -425,7 +425,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { - llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides + SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides = Overrides[OverriddenSubobject]; if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), Overriding) == SubobjectOverrides.end()) @@ -556,7 +556,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, // overrides. typedef std::pair<CXXMethodDecl::method_iterator, CXXMethodDecl::method_iterator> OverriddenMethods; - llvm::SmallVector<OverriddenMethods, 4> Stack; + SmallVector<OverriddenMethods, 4> Stack; Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), CanonM->end_overridden_methods())); while (!Stack.empty()) { @@ -623,11 +623,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { SOEnd = OM->second.end(); SO != SOEnd; ++SO) { - llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; + SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; if (Overriding.size() < 2) continue; - for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVector<UniqueVirtualMethod, 4>::iterator Pos = Overriding.begin(), PosEnd = Overriding.end(); Pos != PosEnd; /* increment in loop */) { @@ -642,7 +642,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { // in a base class subobject that hides the virtual base class // subobject. bool Hidden = false; - for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVector<UniqueVirtualMethod, 4>::iterator OP = Overriding.begin(), OPEnd = Overriding.end(); OP != OPEnd && !Hidden; ++OP) { diff --git a/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp index 4c323da..95d52cb 100644 --- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Decl.cpp @@ -28,6 +28,8 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/Support/ErrorHandling.h" +#include <algorithm> + using namespace clang; //===----------------------------------------------------------------------===// @@ -51,7 +53,7 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) { // If we're on Mac OS X, an 'availability' for Mac OS X attribute // implies visibility(default). - if (D->getASTContext().Target.getTriple().isOSDarwin()) { + if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) { for (specific_attr_iterator<AvailabilityAttr> A = D->specific_attr_begin<AvailabilityAttr>(), AEnd = D->specific_attr_end<AvailabilityAttr>(); @@ -818,7 +820,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { if (Ctx->isFunctionOrMethod()) return getNameAsString(); - typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy; + typedef SmallVector<const DeclContext *, 8> ContextsTy; ContextsTy Contexts; // Collect contexts. @@ -845,18 +847,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { if (ND->isAnonymousNamespace()) OS << "<anonymous namespace>"; else - OS << ND; + OS << *ND; } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) { if (!RD->getIdentifier()) OS << "<anonymous " << RD->getKindName() << '>'; else - OS << RD; + OS << *RD; } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); - OS << FD << '('; + OS << *FD << '('; if (FT) { unsigned NumParams = FD->getNumParams(); for (unsigned i = 0; i < NumParams; ++i) { @@ -875,13 +877,13 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { } OS << ')'; } else { - OS << cast<NamedDecl>(*I); + OS << *cast<NamedDecl>(*I); } OS << "::"; } if (getDeclName()) - OS << this; + OS << *this; else OS << "<anonymous>"; @@ -1003,8 +1005,7 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { } // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; - } - else { + } else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { @@ -1120,15 +1121,16 @@ QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context, const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { switch (SC) { - case SC_None: break; - case SC_Auto: return "auto"; break; - case SC_Extern: return "extern"; break; - case SC_PrivateExtern: return "__private_extern__"; break; - case SC_Register: return "register"; break; - case SC_Static: return "static"; break; + case SC_None: break; + case SC_Auto: return "auto"; + case SC_Extern: return "extern"; + case SC_OpenCLWorkGroupLocal: return "<<work-group-local>>"; + case SC_PrivateExtern: return "__private_extern__"; + case SC_Register: return "register"; + case SC_Static: return "static"; } - assert(0 && "Invalid storage class"); + llvm_unreachable("Invalid storage class"); return 0; } @@ -1388,6 +1390,16 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, S, SCAsWritten, DefArg); } +SourceRange ParmVarDecl::getSourceRange() const { + if (!hasInheritedDefaultArg()) { + SourceRange ArgRange = getDefaultArgRange(); + if (ArgRange.isValid()) + return SourceRange(getOuterLocStart(), ArgRange.getEnd()); + } + + return DeclaratorDecl::getSourceRange(); +} + Expr *ParmVarDecl::getDefaultArg() { assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); assert(!hasUninstantiatedDefaultArg() && @@ -1429,6 +1441,15 @@ bool ParmVarDecl::isParameterPack() const { return isa<PackExpansionType>(getType()); } +void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) { + getASTContext().setParameterIndex(this, parameterIndex); + ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel; +} + +unsigned ParmVarDecl::getParameterIndexLarge() const { + return getASTContext().getParameterIndex(this); +} + //===----------------------------------------------------------------------===// // FunctionDecl Implementation //===----------------------------------------------------------------------===// @@ -1678,20 +1699,14 @@ unsigned FunctionDecl::getNumParams() const { } void FunctionDecl::setParams(ASTContext &C, - ParmVarDecl **NewParamInfo, unsigned NumParams) { + llvm::ArrayRef<ParmVarDecl *> NewParamInfo) { assert(ParamInfo == 0 && "Already has param info!"); - assert(NumParams == getNumParams() && "Parameter count mismatch!"); + assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!"); // Zero params -> null pointer. - if (NumParams) { - void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); - ParamInfo = new (Mem) ParmVarDecl*[NumParams]; - memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); - - // Update source range. The check below allows us to set EndRangeLoc before - // setting the parameters. - if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation()) - EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd(); + if (!NewParamInfo.empty()) { + ParamInfo = new (C) ParmVarDecl*[NewParamInfo.size()]; + std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); } } @@ -1762,6 +1777,33 @@ bool FunctionDecl::isInlined() const { return false; } +/// \brief For a function declaration in C or C++, determine whether this +/// declaration causes the definition to be externally visible. +/// +/// Determines whether this is the first non-inline redeclaration of an inline +/// function in a language where "inline" does not normally require an +/// externally visible definition. +bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { + assert(!doesThisDeclarationHaveABody() && + "Must have a declaration without a body."); + + ASTContext &Context = getASTContext(); + + // In C99 mode, a function may have an inline definition (causing it to + // be deferred) then redeclared later. As a special case, "extern inline" + // is not required to produce an external symbol. + if (Context.getLangOptions().GNUInline || !Context.getLangOptions().C99 || + Context.getLangOptions().CPlusPlus) + return false; + if (getLinkage() != ExternalLinkage || isInlineSpecified()) + return false; + const FunctionDecl *Definition = 0; + if (hasBody(Definition)) + return Definition->isInlined() && + Definition->isInlineDefinitionExternallyVisible(); + return false; +} + /// \brief For an inline function definition in C or C++, determine whether the /// definition will be externally visible. /// @@ -1814,7 +1856,12 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { // Only consider file-scope declarations in this test. if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) continue; - + + // Only consider explicit declarations; the presence of a builtin for a + // libcall shouldn't affect whether a definition is externally visible. + if (Redecl->isImplicit()) + continue; + if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern) return true; // Not an inline definition } @@ -1857,8 +1904,7 @@ FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { <DependentFunctionTemplateSpecializationInfo*>()) return TK_DependentFunctionTemplateSpecialization; - assert(false && "Did we miss a TemplateOrSpecialization type?"); - return TK_NonTemplate; + llvm_unreachable("Did we miss a TemplateOrSpecialization type?"); } FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { @@ -1890,13 +1936,17 @@ bool FunctionDecl::isImplicitlyInstantiable() const { switch (getTemplateSpecializationKind()) { case TSK_Undeclared: - case TSK_ExplicitSpecialization: case TSK_ExplicitInstantiationDefinition: return false; case TSK_ImplicitInstantiation: return true; + // It is possible to instantiate TSK_ExplicitSpecialization kind + // if the FunctionDecl has a class scope specialization pattern. + case TSK_ExplicitSpecialization: + return getClassScopeSpecializationPattern() != 0; + case TSK_ExplicitInstantiationDeclaration: // Handled below. break; @@ -1919,6 +1969,10 @@ bool FunctionDecl::isImplicitlyInstantiable() const { } FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { + // Handle class scope explicit specialization special case. + if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return getClassScopeSpecializationPattern(); + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { while (Primary->getInstantiatedFromMemberTemplate()) { // If we have hit a point where the user provided a specialization of @@ -1944,6 +1998,10 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { return 0; } +FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const { + return getASTContext().getClassScopeSpecializationPattern(this); +} + const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { if (FunctionTemplateSpecializationInfo *Info @@ -1954,7 +2012,7 @@ FunctionDecl::getTemplateSpecializationArgs() const { return 0; } -const TemplateArgumentListInfo * +const ASTTemplateArgumentListInfo * FunctionDecl::getTemplateSpecializationArgsAsWritten() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization @@ -2069,7 +2127,7 @@ FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(PointOfInstantiation); } else - assert(false && "Function cannot have a template specialization kind"); + llvm_unreachable("Function cannot have a template specialization kind"); } SourceLocation FunctionDecl::getPointOfInstantiation() const { @@ -2134,6 +2192,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; } +unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { + assert(isBitField() && "not a bitfield"); + Expr *BitWidth = InitializerOrBitWidth.getPointer(); + return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); +} + unsigned FieldDecl::getFieldIndex() const { if (CachedFieldIndex) return CachedFieldIndex - 1; @@ -2165,8 +2229,8 @@ unsigned FieldDecl::getFieldIndex() const { } SourceRange FieldDecl::getSourceRange() const { - if (isBitField()) - return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd()); + if (const Expr *E = InitializerOrBitWidth.getPointer()) + return SourceRange(getInnerLocStart(), E->getLocEnd()); return DeclaratorDecl::getSourceRange(); } @@ -2218,22 +2282,22 @@ void TagDecl::completeDefinition() { cast<CXXRecordDecl>(this)->hasDefinition()) && "definition completed but not started"); - IsDefinition = true; + IsCompleteDefinition = true; IsBeingDefined = false; if (ASTMutationListener *L = getASTMutationListener()) L->CompletedTagDefinition(this); } -TagDecl* TagDecl::getDefinition() const { - if (isDefinition()) +TagDecl *TagDecl::getDefinition() const { + if (isCompleteDefinition()) return const_cast<TagDecl *>(this); if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this)) return CXXRD->getDefinition(); for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); R != REnd; ++R) - if (R->isDefinition()) + if (R->isCompleteDefinition()) return *R; return 0; @@ -2246,8 +2310,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; - } - else { + } else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { @@ -2296,7 +2359,7 @@ void EnumDecl::completeDefinition(QualType NewType, QualType NewPromotionType, unsigned NumPositiveBits, unsigned NumNegativeBits) { - assert(!isDefinition() && "Cannot redefine enums!"); + assert(!isCompleteDefinition() && "Cannot redefine enums!"); if (!IntegerType) IntegerType = NewType.getTypePtr(); PromotionType = NewPromotionType; @@ -2349,7 +2412,7 @@ RecordDecl::field_iterator RecordDecl::field_begin() const { /// completeDefinition - Notes that the definition of this type is now /// complete. void RecordDecl::completeDefinition() { - assert(!isDefinition() && "Cannot redefine record!"); + assert(!isCompleteDefinition() && "Cannot redefine record!"); TagDecl::completeDefinition(); } @@ -2360,7 +2423,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { // Notify that we have a RecordDecl doing some initialization. ExternalASTSource::Deserializing TheFields(Source); - llvm::SmallVector<Decl*, 64> Decls; + SmallVector<Decl*, 64> Decls; LoadedFieldsFromExternalStorage = true; switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) { case ELR_Success: @@ -2380,23 +2443,22 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { if (Decls.empty()) return; - llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); + llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls, + /*FieldsAlreadyLoaded=*/false); } //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// -void BlockDecl::setParams(ParmVarDecl **NewParamInfo, - unsigned NParms) { +void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) { assert(ParamInfo == 0 && "Already has param info!"); // Zero params -> null pointer. - if (NParms) { - NumParams = NParms; - void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); - ParamInfo = new (Mem) ParmVarDecl*[NumParams]; - memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + if (!NewParamInfo.empty()) { + NumParams = NewParamInfo.size(); + ParamInfo = new (getASTContext()) ParmVarDecl*[NewParamInfo.size()]; + std::copy(NewParamInfo.begin(), NewParamInfo.end(), ParamInfo); } } @@ -2481,10 +2543,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, QualType T, TypeSourceInfo *TInfo, StorageClass SC, StorageClass SCAsWritten, bool isInlineSpecified, - bool hasWrittenPrototype) { + bool hasWrittenPrototype, + bool isConstexprSpecified) { FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo, T, TInfo, SC, SCAsWritten, - isInlineSpecified); + isInlineSpecified, + isConstexprSpecified); New->HasWrittenPrototype = hasWrittenPrototype; return New; } diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index b2806f0..321e40b 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -43,7 +43,7 @@ static bool StatSwitch = false; const char *Decl::getDeclKindName() const { switch (DeclKind) { - default: assert(0 && "Declaration not in DeclNodes.inc!"); + default: llvm_unreachable("Declaration not in DeclNodes.inc!"); #define DECL(DERIVED, BASE) case DERIVED: return #DERIVED; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" @@ -62,7 +62,7 @@ void Decl::setInvalidDecl(bool Invalid) { const char *DeclContext::getDeclKindName() const { switch (DeclKind) { - default: assert(0 && "Declaration context not in DeclNodes.inc!"); + default: llvm_unreachable("Declaration context not in DeclNodes.inc!"); #define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" @@ -100,7 +100,7 @@ void Decl::PrintStats() { void Decl::add(Kind k) { switch (k) { - default: assert(0 && "Declaration not in DeclNodes.inc!"); + default: llvm_unreachable("Declaration not in DeclNodes.inc!"); #define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" @@ -133,14 +133,18 @@ bool Decl::isFunctionOrFunctionTemplate() const { return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); } -bool Decl::isDefinedOutsideFunctionOrMethod() const { - for (const DeclContext *DC = getDeclContext(); - DC && !DC->isTranslationUnit(); +bool Decl::isTemplateDecl() const { + return isa<TemplateDecl>(this); +} + +const DeclContext *Decl::getParentFunctionOrMethod() const { + for (const DeclContext *DC = getDeclContext(); + DC && !DC->isTranslationUnit() && !DC->isNamespace(); DC = DC->getParent()) if (DC->isFunctionOrMethod()) - return false; + return DC; - return true; + return 0; } @@ -148,7 +152,7 @@ bool Decl::isDefinedOutsideFunctionOrMethod() const { // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// -void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { +void PrettyStackTraceDecl::print(raw_ostream &OS) const { SourceLocation TheLoc = Loc; if (TheLoc.isInvalid() && TheDecl) TheLoc = TheDecl->getLocation(); @@ -265,13 +269,13 @@ bool Decl::isReferenced() const { static AvailabilityResult CheckAvailability(ASTContext &Context, const AvailabilityAttr *A, std::string *Message) { - llvm::StringRef TargetPlatform = Context.Target.getPlatformName(); - llvm::StringRef PrettyPlatformName + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + StringRef PrettyPlatformName = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); if (PrettyPlatformName.empty()) PrettyPlatformName = TargetPlatform; - VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion(); + VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion(); if (TargetMinVersion.empty()) return AR_Available; @@ -493,6 +497,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case UsingDirective: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: + case ClassScopeFunctionSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: @@ -566,8 +571,7 @@ Decl *Decl::castFromDeclContext (const DeclContext *D) { if (DK >= first##NAME && DK <= last##NAME) \ return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); #include "clang/AST/DeclNodes.inc" - assert(false && "a decl that inherits DeclContext isn't handled"); - return 0; + llvm_unreachable("a decl that inherits DeclContext isn't handled"); } } @@ -586,8 +590,7 @@ DeclContext *Decl::castToDeclContext(const Decl *D) { if (DK >= first##NAME && DK <= last##NAME) \ return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); #include "clang/AST/DeclNodes.inc" - assert(false && "a decl that inherits DeclContext isn't handled"); - return 0; + llvm_unreachable("a decl that inherits DeclContext isn't handled"); } } @@ -627,7 +630,8 @@ void Decl::CheckAccessDeclContext() const { isa<ParmVarDecl>(this) || // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have // AS_none as access specifier. - isa<CXXRecordDecl>(this)) + isa<CXXRecordDecl>(this) || + isa<ClassScopeFunctionSpecializationDecl>(this)) return; assert(Access != AS_none && @@ -812,11 +816,15 @@ DeclContext *DeclContext::getNextContext() { } std::pair<Decl *, Decl *> -DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) { +DeclContext::BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, + bool FieldsAlreadyLoaded) { // Build up a chain of declarations via the Decl::NextDeclInContext field. Decl *FirstNewDecl = 0; Decl *PrevDecl = 0; for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (FieldsAlreadyLoaded && isa<FieldDecl>(Decls[I])) + continue; + Decl *D = Decls[I]; if (PrevDecl) PrevDecl->NextDeclInContext = D; @@ -838,9 +846,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { // Notify that we have a DeclContext that is initializing. ExternalASTSource::Deserializing ADeclContext(Source); - + // Load the external declarations, if any. - llvm::SmallVector<Decl*, 64> Decls; + SmallVector<Decl*, 64> Decls; ExternalLexicalStorage = false; switch (Source->FindExternalLexicalDecls(this, Decls)) { case ELR_Success: @@ -855,17 +863,16 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { return; // We may have already loaded just the fields of this record, in which case - // don't add the decls, just replace the FirstDecl/LastDecl chain. + // we need to ignore them. + bool FieldsAlreadyLoaded = false; if (const RecordDecl *RD = dyn_cast<RecordDecl>(this)) - if (RD->LoadedFieldsFromExternalStorage) { - llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); - return; - } - + FieldsAlreadyLoaded = RD->LoadedFieldsFromExternalStorage; + // Splice the newly-read declarations into the beginning of the list // of declarations. Decl *ExternalFirst, *ExternalLast; - llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls); + llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls, + FieldsAlreadyLoaded); ExternalLast->NextDeclInContext = FirstDecl; FirstDecl = ExternalFirst; if (!LastDecl) @@ -890,7 +897,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, DeclContext::lookup_result ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, - llvm::SmallVectorImpl<NamedDecl*> &Decls) { + ArrayRef<NamedDecl*> Decls) { ASTContext &Context = DC->getParentASTContext();; StoredDeclsMap *Map; @@ -898,35 +905,17 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, Map = DC->CreateStoredDeclsMap(Context); StoredDeclsList &List = (*Map)[Name]; - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + for (ArrayRef<NamedDecl*>::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { if (List.isNull()) - List.setOnlyValue(Decls[I]); + List.setOnlyValue(*I); else - List.AddSubsequentDecl(Decls[I]); + List.AddSubsequentDecl(*I); } return List.getLookupResult(); } -void ExternalASTSource::MaterializeVisibleDeclsForName(const DeclContext *DC, - DeclarationName Name, - llvm::SmallVectorImpl<NamedDecl*> &Decls) { - assert(DC->LookupPtr); - StoredDeclsMap &Map = *DC->LookupPtr; - - // If there's an entry in the table the visible decls for this name have - // already been deserialized. - if (Map.find(Name) == Map.end()) { - StoredDeclsList &List = Map[Name]; - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - if (List.isNull()) - List.setOnlyValue(Decls[I]); - else - List.AddSubsequentDecl(Decls[I]); - } - } -} - DeclContext::decl_iterator DeclContext::noload_decls_begin() const { return decl_iterator(FirstDecl); } @@ -939,8 +928,6 @@ DeclContext::decl_iterator DeclContext::decls_begin() const { if (hasExternalLexicalStorage()) LoadLexicalDeclsFromExternalStorage(); - // FIXME: Check whether we need to load some declarations from - // external storage. return decl_iterator(FirstDecl); } @@ -988,6 +975,9 @@ void DeclContext::removeDecl(Decl *D) { if (isa<NamedDecl>(D)) { NamedDecl *ND = cast<NamedDecl>(D); + // Remove only decls that have a name + if (!ND->getDeclName()) return; + StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; if (!Map) return; @@ -1038,12 +1028,10 @@ void DeclContext::buildLookup(DeclContext *DCtx) { if (D->getDeclContext() == DCtx) makeDeclVisibleInContextImpl(ND); - // Insert any forward-declared Objective-C interfaces into the lookup + // Insert any forward-declared Objective-C interface into the lookup // data structure. if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) - for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); - I != IEnd; ++I) - makeDeclVisibleInContextImpl(I->getInterface()); + makeDeclVisibleInContextImpl(Class->getForwardInterfaceDecl()); // If this declaration is itself a transparent declaration context or // inline namespace, add its members (recursively). @@ -1093,6 +1081,38 @@ DeclContext::lookup(DeclarationName Name) const { return const_cast<DeclContext*>(this)->lookup(Name); } +void DeclContext::localUncachedLookup(DeclarationName Name, + llvm::SmallVectorImpl<NamedDecl *> &Results) { + Results.clear(); + + // If there's no external storage, just perform a normal lookup and copy + // the results. + if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage()) { + lookup_result LookupResults = lookup(Name); + Results.insert(Results.end(), LookupResults.first, LookupResults.second); + return; + } + + // If we have a lookup table, check there first. Maybe we'll get lucky. + if (LookupPtr) { + StoredDeclsMap::iterator Pos = LookupPtr->find(Name); + if (Pos != LookupPtr->end()) { + Results.insert(Results.end(), + Pos->second.getLookupResult().first, + Pos->second.getLookupResult().second); + return; + } + } + + // Slow case: grovel through the declarations in our chain looking for + // matches. + for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (ND->getDeclName() == Name) + Results.push_back(ND); + } +} + DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; // Skip through transparent contexts. @@ -1205,15 +1225,6 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { DeclNameEntries.AddSubsequentDecl(D); } -void DeclContext::MaterializeVisibleDeclsFromExternalStorage() { - ExternalASTSource *Source = getParentASTContext().getExternalSource(); - assert(hasExternalVisibleStorage() && Source && "No external storage?"); - - if (!LookupPtr) - CreateStoredDeclsMap(getParentASTContext()); - Source->MaterializeVisibleDecls(this); -} - /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. DeclContext::udir_iterator_range diff --git a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp index 4b59bf3..f3da67c 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp @@ -35,15 +35,16 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasTrivialDefaultConstructor(true), - HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true), + HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true), HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), - DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(), - Definition(D), FirstFriend(0) { + DeclaredDestructor(false), FailedImplicitMoveConstructor(false), + FailedImplicitMoveAssignment(false), NumBases(0), NumVBases(0), Bases(), + VBases(), Definition(D), FirstFriend(0) { } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -89,7 +90,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; // The virtual bases of this class. - llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases; + SmallVector<const CXXBaseSpecifier *, 8> VBases; data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; @@ -287,7 +288,7 @@ bool CXXRecordDecl::isTriviallyCopyable() const { /// (if there is one). static CXXMethodDecl * GetBestOverloadCandidateSimple( - const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { + const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { if (Cands.empty()) return 0; if (Cands.size() == 1) @@ -313,7 +314,7 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{ = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned FoundTQs; - llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; + SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); Con != ConEnd; ++Con) { @@ -349,7 +350,7 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; + SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; DeclContext::lookup_const_iterator Op, OpEnd; for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) { // C++ [class.copy]p9: @@ -502,18 +503,18 @@ NotASpecialMember:; // Note that we have a user-declared constructor. data().UserDeclaredConstructor = true; - // FIXME: Under C++0x, /only/ special member functions may be user-provided. - // This is probably a defect. - bool UserProvided = false; + // Technically, "user-provided" is only defined for special member + // functions, but the intent of the standard is clearly that it should apply + // to all functions. + bool UserProvided = Constructor->isUserProvided(); // C++0x [class.ctor]p5: // A default constructor is trivial if it is not user-provided [...] if (Constructor->isDefaultConstructor()) { data().DeclaredDefaultConstructor = true; - if (Constructor->isUserProvided()) { + if (UserProvided) { data().HasTrivialDefaultConstructor = false; data().UserProvidedDefaultConstructor = true; - UserProvided = true; } } @@ -527,10 +528,8 @@ NotASpecialMember:; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if it is not // user-provided [...] - if (Constructor->isUserProvided()) { + if (UserProvided) data().HasTrivialCopyConstructor = false; - UserProvided = true; - } } else if (Constructor->isMoveConstructor()) { data().UserDeclaredMoveConstructor = true; data().DeclaredMoveConstructor = true; @@ -538,17 +537,14 @@ NotASpecialMember:; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if it is not // user-provided [...] - if (Constructor->isUserProvided()) { + if (UserProvided) data().HasTrivialMoveConstructor = false; - UserProvided = true; - } } } - if (Constructor->isConstExpr() && - !Constructor->isCopyOrMoveConstructor()) { - // Record if we see any constexpr constructors which are niether copy + if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) { + // Record if we see any constexpr constructors which are neither copy // nor move constructors. - data().HasConstExprNonCopyMoveConstructor = true; + data().HasConstexprNonCopyMoveConstructor = true; } // C++ [dcl.init.aggr]p1: @@ -657,6 +653,13 @@ NotASpecialMember:; // Handle non-static data members. if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + // C++ [class.bit]p2: + // A declaration for a bit-field that omits the identifier declares an + // unnamed bit-field. Unnamed bit-fields are not members and cannot be + // initialized. + if (Field->isUnnamedBitfield()) + return; + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] no // private or protected non-static data members (clause 11). @@ -675,7 +678,7 @@ NotASpecialMember:; case AS_private: data().HasPrivateFields = true; break; case AS_protected: data().HasProtectedFields = true; break; case AS_public: data().HasPublicFields = true; break; - case AS_none: assert(0 && "Invalid access specifier"); + case AS_none: llvm_unreachable("Invalid access specifier"); }; if ((data().HasPrivateFields + data().HasProtectedFields + data().HasPublicFields) > 1) @@ -716,7 +719,11 @@ NotASpecialMember:; } // Record if this field is the first non-literal field or base. - if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) + // As a slight variation on the standard, we regard mutable members as being + // non-literal, since mutating a constexpr variable would break C++11 + // constant expression semantics. + if ((!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) || + Field->isMutable()) data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer()) { @@ -827,15 +834,11 @@ NotASpecialMember:; // If this is not a zero-length bit-field, then the class is not empty. if (data().Empty) { - if (!Field->getBitWidth()) + if (!Field->isBitField() || + (!Field->getBitWidth()->isTypeDependent() && + !Field->getBitWidth()->isValueDependent() && + Field->getBitWidthValue(Context) != 0)) data().Empty = false; - else if (!Field->getBitWidth()->isTypeDependent() && - !Field->getBitWidth()->isValueDependent()) { - llvm::APSInt Bits; - if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context)) - if (!!Bits) - data().Empty = false; - } } } @@ -1057,7 +1060,7 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { return; } - assert(false && "Not a class template or member class specialization"); + llvm_unreachable("Not a class template or member class specialization"); } CXXDestructorDecl *CXXRecordDecl::getDestructor() const { @@ -1160,9 +1163,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isStatic, StorageClass SCAsWritten, bool isInline, - SourceLocation EndLocation) { + bool isConstexpr, SourceLocation EndLocation) { return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, - isStatic, SCAsWritten, isInline, EndLocation); + isStatic, SCAsWritten, isInline, isConstexpr, + EndLocation); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -1402,7 +1406,7 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(), - QualType(), 0, false, false, false); + QualType(), 0, false, false, false, false); } CXXConstructorDecl * @@ -1410,14 +1414,14 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isExplicit, - bool isInline, - bool isImplicitlyDeclared) { + bool isExplicit, bool isInline, + bool isImplicitlyDeclared, bool isConstexpr) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo, - isExplicit, isInline, isImplicitlyDeclared); + isExplicit, isInline, isImplicitlyDeclared, + isConstexpr); } bool CXXConstructorDecl::isDefaultConstructor() const { @@ -1545,8 +1549,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, - bool isImplicitlyDeclared) { + bool isInline, bool isImplicitlyDeclared) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); @@ -1557,7 +1560,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(), - QualType(), 0, false, false, + QualType(), 0, false, false, false, SourceLocation()); } @@ -1567,12 +1570,13 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit, - SourceLocation EndLocation) { + bool isConstexpr, SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo, - isInline, isExplicit, EndLocation); + isInline, isExplicit, isConstexpr, + EndLocation); } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, @@ -1696,8 +1700,7 @@ static const char *getAccessName(AccessSpecifier AS) { switch (AS) { default: case AS_none: - assert("Invalid access specifier!"); - return 0; + llvm_unreachable("Invalid access specifier!"); case AS_public: return "public"; case AS_private: diff --git a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp index 557b681..a589b7f 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" +#include "clang/AST/ASTMutationListener.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -185,7 +186,7 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( // Check for duplicate protocol in class's protocol list. // This is O(n*m). But it is extremely rare and number of protocols in // class or its extension are very few. - llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; for (unsigned i = 0; i < ExtNum; i++) { bool protocolExists = false; ObjCProtocolDecl *ProtoInExtension = ExtList[i]; @@ -337,17 +338,60 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isInstance, bool isVariadic, bool isSynthesized, + bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, - bool HasRelatedResultType, - unsigned numSelectorArgs) { + bool HasRelatedResultType) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, - isVariadic, isSynthesized, isDefined, + isVariadic, isSynthesized, isImplicitlyDeclared, + isDefined, impControl, - HasRelatedResultType, - numSelectorArgs); + HasRelatedResultType); +} + +void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) { + assert(PrevMethod); + getASTContext().setObjCMethodRedeclaration(PrevMethod, this); + IsRedeclaration = true; + PrevMethod->HasRedeclaration = true; +} + +void ObjCMethodDecl::setParamsAndSelLocs(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs) { + ParamsAndSelLocs = 0; + NumParams = Params.size(); + if (Params.empty() && SelLocs.empty()) + return; + + unsigned Size = sizeof(ParmVarDecl *) * NumParams + + sizeof(SourceLocation) * SelLocs.size(); + ParamsAndSelLocs = C.Allocate(Size); + std::copy(Params.begin(), Params.end(), getParams()); + std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); +} + +void ObjCMethodDecl::getSelectorLocs( + SmallVectorImpl<SourceLocation> &SelLocs) const { + for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i) + SelLocs.push_back(getSelectorLoc(i)); +} + +void ObjCMethodDecl::setMethodParams(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs) { + assert((!SelLocs.empty() || isImplicit()) && + "No selector locs for non-implicit method"); + if (isImplicit()) + return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + + SelLocsKind = hasStandardSelectorLocs(getSelector(), SelLocs, Params, EndLoc); + if (SelLocsKind != SelLoc_NonStandard) + return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + + setParamsAndSelLocs(C, Params, SelLocs); } /// \brief A definition will return its interface declaration. @@ -356,6 +400,11 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { ASTContext &Ctx = getASTContext(); ObjCMethodDecl *Redecl = 0; + if (HasRedeclaration) + Redecl = const_cast<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this)); + if (Redecl) + return Redecl; + Decl *CtxD = cast<Decl>(getDeclContext()); if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { @@ -377,6 +426,12 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); } + if (!Redecl && isRedeclaration()) { + // This is the last redeclaration, go back to the first method. + return cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(), + isInstanceMethod()); + } + return Redecl ? Redecl : this; } @@ -444,6 +499,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { // These selectors have a conventional meaning only for instance methods. case OMF_dealloc: + case OMF_finalize: case OMF_retain: case OMF_release: case OMF_autorelease: @@ -545,8 +601,7 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { return IMD->getClassInterface(); assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method"); - assert(false && "unknown method context"); - return 0; + llvm_unreachable("unknown method context"); } //===----------------------------------------------------------------------===// @@ -566,11 +621,10 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, ObjCInterfaceDecl:: ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, SourceLocation CLoc, bool FD, bool isInternal) - : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id), + : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc), TypeForDecl(0), SuperClass(0), CategoryList(0), IvarList(0), - ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false), - ClassLoc(CLoc) { + ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false) { } void ObjCInterfaceDecl::LoadExternalDefinition() const { @@ -756,8 +810,7 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, ID = IM->getClassInterface(); if (BW) IM->setHasSynthBitfield(true); - } - else { + } else { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC); ID = CD->getClassInterface(); if (BW) @@ -778,8 +831,7 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { default: case ObjCCategoryImpl: case ObjCProtocol: - assert(0 && "invalid ivar container!"); - return 0; + llvm_unreachable("invalid ivar container!"); // Ivars can only appear in class extension categories. case ObjCCategory: { @@ -812,9 +864,10 @@ ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - IdentifierInfo *Id) { - return new (C) ObjCProtocolDecl(DC, L, Id); + IdentifierInfo *Id, + SourceLocation nameLoc, + SourceLocation atStartLoc) { + return new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc); } ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { @@ -850,36 +903,31 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, //===----------------------------------------------------------------------===// ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, - ObjCInterfaceDecl *const *Elts, - const SourceLocation *Locs, - unsigned nElts, + ObjCInterfaceDecl *const Elt, + const SourceLocation Loc, ASTContext &C) : Decl(ObjCClass, DC, L) { - setClassList(C, Elts, Locs, nElts); -} - -void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, - const SourceLocation *Locs, unsigned Num) { - ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num, - llvm::alignOf<ObjCClassRef>()); - for (unsigned i = 0; i < Num; ++i) - new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]); - - NumDecls = Num; + setClass(C, Elt, Loc); } ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ObjCInterfaceDecl *const *Elts, - const SourceLocation *Locs, - unsigned nElts) { - return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C); + ObjCInterfaceDecl *const Elt, + const SourceLocation Loc) { + return new (C) ObjCClassDecl(DC, L, Elt, Loc, C); } +void ObjCClassDecl::setClass(ASTContext &C, ObjCInterfaceDecl*const Cls, + const SourceLocation Loc) { + + ForwardDecl = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef), + llvm::alignOf<ObjCClassRef>()); + new (ForwardDecl) ObjCClassRef(Cls, Loc); +} + SourceRange ObjCClassDecl::getSourceRange() const { // FIXME: We should include the semicolon - assert(NumDecls); - return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation()); + return SourceRange(getLocation(), ForwardDecl->getLocation()); } //===----------------------------------------------------------------------===// @@ -912,8 +960,25 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, - IdentifierInfo *Id) { - return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id); + IdentifierInfo *Id, + ObjCInterfaceDecl *IDecl) { + ObjCCategoryDecl *CatDecl = new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, + CategoryNameLoc, Id, + IDecl); + if (IDecl) { + // Link this category into its class's category list. + CatDecl->NextClassCategory = IDecl->getCategoryList(); + IDecl->setCategoryList(CatDecl); + if (ASTMutationListener *L = C.getASTMutationListener()) + L->AddedObjCCategoryToInterface(CatDecl, IDecl); + } + + return CatDecl; +} + +ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) ObjCCategoryDecl(0, SourceLocation(), SourceLocation(), + SourceLocation(), 0, 0); } ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { @@ -932,9 +997,12 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { ObjCCategoryImplDecl * ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L,IdentifierInfo *Id, - ObjCInterfaceDecl *ClassInterface) { - return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); + IdentifierInfo *Id, + ObjCInterfaceDecl *ClassInterface, + SourceLocation nameLoc, + SourceLocation atStartLoc) { + return new (C) ObjCCategoryImplDecl(DC, Id, ClassInterface, + nameLoc, atStartLoc); } ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { @@ -997,7 +1065,7 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } -llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, +raw_ostream &clang::operator<<(raw_ostream &OS, const ObjCCategoryImplDecl *CID) { OS << CID->getName(); return OS; @@ -1009,13 +1077,28 @@ llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, ObjCImplementationDecl * ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, ObjCInterfaceDecl *ClassInterface, - ObjCInterfaceDecl *SuperDecl) { - return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); + ObjCInterfaceDecl *SuperDecl, + SourceLocation nameLoc, + SourceLocation atStartLoc) { + return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl, + nameLoc, atStartLoc); +} + +void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, + CXXCtorInitializer ** initializers, + unsigned numInitializers) { + if (numInitializers > 0) { + NumIvarInitializers = numInitializers; + CXXCtorInitializer **ivarInitializers = + new (C) CXXCtorInitializer*[NumIvarInitializers]; + memcpy(ivarInitializers, initializers, + numInitializers * sizeof(CXXCtorInitializer*)); + IvarInitializers = ivarInitializers; + } } -llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, +raw_ostream &clang::operator<<(raw_ostream &OS, const ObjCImplementationDecl *ID) { OS << ID->getName(); return OS; diff --git a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp index 19554a3..08a1ab5 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp @@ -24,22 +24,25 @@ using namespace clang; namespace { class DeclPrinter : public DeclVisitor<DeclPrinter> { - llvm::raw_ostream &Out; + raw_ostream &Out; ASTContext &Context; PrintingPolicy Policy; unsigned Indentation; + bool PrintInstantiation; - llvm::raw_ostream& Indent() { return Indent(Indentation); } - llvm::raw_ostream& Indent(unsigned Indentation); - void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); + raw_ostream& Indent() { return Indent(Indentation); } + raw_ostream& Indent(unsigned Indentation); + void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls); void Print(AccessSpecifier AS); public: - DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, + DeclPrinter(raw_ostream &Out, ASTContext &Context, const PrintingPolicy &Policy, - unsigned Indentation = 0) - : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } + unsigned Indentation = 0, + bool PrintInstantiation = false) + : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation), + PrintInstantiation(PrintInstantiation) { } void VisitDeclContext(DeclContext *DC, bool Indent = true); @@ -62,6 +65,8 @@ namespace { void VisitCXXRecordDecl(CXXRecordDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitTemplateDecl(const TemplateDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCClassDecl(ObjCClassDecl *D); void VisitObjCImplementationDecl(ObjCImplementationDecl *D); @@ -77,16 +82,20 @@ namespace { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); + + void PrintTemplateParameters(const TemplateParameterList *Params, + const TemplateArgumentList *Args); }; } -void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const { - print(Out, getASTContext().PrintingPolicy, Indentation); +void Decl::print(raw_ostream &Out, unsigned Indentation, + bool PrintInstantiation) const { + print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation); } -void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy, - unsigned Indentation) const { - DeclPrinter Printer(Out, getASTContext(), Policy, Indentation); +void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation, bool PrintInstantiation) const { + DeclPrinter Printer(Out, getASTContext(), Policy, Indentation, PrintInstantiation); Printer.Visit(const_cast<Decl*>(this)); } @@ -105,7 +114,7 @@ static QualType GetBaseType(QualType T) { else if (const VectorType *VTy = BaseType->getAs<VectorType>()) BaseType = VTy->getElementType(); else - assert(0 && "Unknown declarator!"); + llvm_unreachable("Unknown declarator!"); } return BaseType; } @@ -119,7 +128,7 @@ static QualType getDeclType(Decl* D) { } void Decl::printGroup(Decl** Begin, unsigned NumDecls, - llvm::raw_ostream &Out, const PrintingPolicy &Policy, + raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation) { if (NumDecls == 1) { (*Begin)->print(Out, Policy, Indentation); @@ -132,7 +141,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, ++Begin; PrintingPolicy SubPolicy(Policy); - if (TD && TD->isDefinition()) { + if (TD && TD->isCompleteDefinition()) { TD->print(Out, Policy, Indentation); Out << " "; SubPolicy.SuppressTag = true; @@ -159,7 +168,7 @@ void DeclContext::dumpDeclContext() const { DC = DC->getParent(); ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); - DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0); + DeclPrinter Printer(llvm::errs(), Ctx, Ctx.getPrintingPolicy(), 0); Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); } @@ -167,13 +176,13 @@ void Decl::dump() const { print(llvm::errs()); } -llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) { +raw_ostream& DeclPrinter::Indent(unsigned Indentation) { for (unsigned i = 0; i != Indentation; ++i) Out << " "; return Out; } -void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) { +void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) { this->Indent(); Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation); Out << ";\n"; @@ -183,7 +192,7 @@ void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) { void DeclPrinter::Print(AccessSpecifier AS) { switch(AS) { - case AS_none: assert(0 && "No access specifier!"); break; + case AS_none: llvm_unreachable("No access specifier!"); case AS_public: Out << "public"; break; case AS_protected: Out << "protected"; break; case AS_private: Out << "private"; break; @@ -198,7 +207,7 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (Indent) Indentation += Policy.Indentation; - llvm::SmallVector<Decl*, 2> Decls; + SmallVector<Decl*, 2> Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { @@ -304,8 +313,12 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { std::string S = D->getNameAsString(); D->getUnderlyingType().getAsStringInternal(S, Policy); - if (!Policy.SuppressSpecifiers) + if (!Policy.SuppressSpecifiers) { Out << "typedef "; + + if (D->isModulePrivate()) + Out << "__module_private__ "; + } Out << S; } @@ -315,6 +328,8 @@ void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { + if (!Policy.SuppressSpecifiers && D->isModulePrivate()) + Out << "__module_private__ "; Out << "enum "; if (D->isScoped()) { if (D->isScopedUsingClassTag()) @@ -322,7 +337,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { else Out << "struct "; } - Out << D; + Out << *D; if (D->isFixed()) { std::string Underlying; @@ -330,7 +345,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { Out << " : " << Underlying; } - if (D->isDefinition()) { + if (D->isCompleteDefinition()) { Out << " {\n"; VisitDeclContext(D); Indent() << "}"; @@ -338,11 +353,13 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { + if (!Policy.SuppressSpecifiers && D->isModulePrivate()) + Out << "__module_private__ "; Out << D->getKindName(); if (D->getIdentifier()) - Out << ' ' << D; + Out << ' ' << *D; - if (D->isDefinition()) { + if (D->isCompleteDefinition()) { Out << " {\n"; VisitDeclContext(D); Indent() << "}"; @@ -350,7 +367,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { } void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { - Out << D; + Out << *D; if (Expr *Init = D->getInitExpr()) { Out << " = "; Init->printPretty(Out, Context, 0, Policy, Indentation); @@ -364,11 +381,13 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { case SC_Extern: Out << "extern "; break; case SC_Static: Out << "static "; break; case SC_PrivateExtern: Out << "__private_extern__ "; break; - case SC_Auto: case SC_Register: llvm_unreachable("invalid for functions"); + case SC_Auto: case SC_Register: case SC_OpenCLWorkGroupLocal: + llvm_unreachable("invalid for functions"); } - if (D->isInlineSpecified()) Out << "inline "; + if (D->isInlineSpecified()) Out << "inline "; if (D->isVirtualAsWritten()) Out << "virtual "; + if (D->isModulePrivate()) Out << "__module_private__ "; } PrintingPolicy SubPolicy(Policy); @@ -449,6 +468,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->hasAttr<NoReturnAttr>()) Proto += " __attribute((noreturn))"; + + if (D->hasAttr<ReturnsTwiceAttr>()) + Proto += " __attribute((returns_twice))"; + if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { bool HasInitializerList = false; for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), @@ -468,10 +491,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (BMInitializer->isAnyMemberInitializer()) { FieldDecl *FD = BMInitializer->getAnyMember(); - Out << FD; + Out << *FD; } else { - Out << QualType(BMInitializer->getBaseClass(), - 0).getAsString(Policy); + Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy); } Out << "("; @@ -549,6 +571,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (!Policy.SuppressSpecifiers && D->isMutable()) Out << "mutable "; + if (!Policy.SuppressSpecifiers && D->isModulePrivate()) + Out << "__module_private__ "; std::string Name = D->getNameAsString(); D->getType().getAsStringInternal(Name, Policy); @@ -577,6 +601,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) Out << "__thread "; + if (!Policy.SuppressSpecifiers && D->isModulePrivate()) + Out << "__module_private__ "; std::string Name = D->getNameAsString(); QualType T = D->getType(); @@ -621,7 +647,7 @@ void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { - Out << "namespace " << D << " {\n"; + Out << "namespace " << *D << " {\n"; VisitDeclContext(D); Indent() << "}"; } @@ -630,22 +656,24 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespaceAsWritten(); + Out << *D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - Out << "namespace " << D << " = "; + Out << "namespace " << *D << " = "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getAliasedNamespace(); + Out << *D->getAliasedNamespace(); } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { + if (!Policy.SuppressSpecifiers && D->isModulePrivate()) + Out << "__module_private__ "; Out << D->getKindName(); if (D->getIdentifier()) - Out << ' ' << D; + Out << ' ' << *D; - if (D->isDefinition()) { + if (D->isCompleteDefinition()) { // Print the base classes if (D->getNumBases()) { Out << " : "; @@ -694,10 +722,13 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { Visit(*D->decls_begin()); } -void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { +void DeclPrinter::PrintTemplateParameters( + const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) { + assert(Params); + assert(!Args || Params->size() == Args->size()); + Out << "template <"; - TemplateParameterList *Params = D->getTemplateParameters(); for (unsigned i = 0, e = Params->size(); i != e; ++i) { if (i != 0) Out << ", "; @@ -716,7 +747,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { Out << TTP->getNameAsString(); - if (TTP->hasDefaultArgument()) { + if (Args) { + Out << " = "; + Args->get(i).print(Policy, Out); + } else if (TTP->hasDefaultArgument()) { Out << " = "; Out << TTP->getDefaultArgument().getAsString(Policy); }; @@ -732,7 +766,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { Out << Name->getName(); } - if (NTTP->hasDefaultArgument()) { + if (Args) { + Out << " = "; + Args->get(i).print(Policy, Out); + } else if (NTTP->hasDefaultArgument()) { Out << " = "; NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, Indentation); @@ -745,6 +782,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { } Out << "> "; +} + +void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { + PrintTemplateParameters(D->getTemplateParameters()); if (const TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { @@ -757,17 +798,39 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { } } +void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + if (PrintInstantiation) { + TemplateParameterList *Params = D->getTemplateParameters(); + for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end(); + I != E; ++I) { + PrintTemplateParameters(Params, (*I)->getTemplateSpecializationArgs()); + Visit(*I); + } + } + + return VisitRedeclarableTemplateDecl(D); +} + +void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) { + if (PrintInstantiation) { + TemplateParameterList *Params = D->getTemplateParameters(); + for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end(); + I != E; ++I) { + PrintTemplateParameters(Params, &(*I)->getTemplateArgs()); + Visit(*I); + Out << '\n'; + } + } + + return VisitRedeclarableTemplateDecl(D); +} + //---------------------------------------------------------------------------- // Objective-C declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { - Out << "@class "; - for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); - I != E; ++I) { - if (I != D->begin()) Out << ", "; - Out << I->getInterface(); - } + Out << "@class " << *D->getForwardInterfaceDecl(); } void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { @@ -783,9 +846,9 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), E = OMD->param_end(); PI != E; ++PI) { // FIXME: selector is missing here! - pos = name.find_first_of(":", lastPos); + pos = name.find_first_of(':', lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI; + Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << **PI; lastPos = pos + 1; } @@ -807,7 +870,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@implementation " << I << " : " << SID; + Out << "@implementation " << I << " : " << *SID; else Out << "@implementation " << I; Out << "\n"; @@ -820,7 +883,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@interface " << I << " : " << SID; + Out << "@interface " << I << " : " << *SID; else Out << "@interface " << I; @@ -829,7 +892,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { if (!Protocols.empty()) { for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - Out << (I == Protocols.begin() ? '<' : ',') << *I; + Out << (I == Protocols.begin() ? '<' : ',') << **I; } if (!Protocols.empty()) @@ -840,7 +903,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n"; + Indent() << (*I)->getType().getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -857,18 +920,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; - Out << *I; + Out << **I; } } void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - Out << "@protocol " << PID << '\n'; + Out << "@protocol " << *PID << '\n'; VisitDeclContext(PID, false); Out << "@end"; } void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { - Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n"; + Out << "@implementation " << *PID->getClassInterface() << '(' << *PID <<")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -876,7 +939,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n"; + Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -884,8 +947,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID - << ' ' << AID->getClassInterface() << ";\n"; + Out << "@compatibility_alias " << *AID + << ' ' << *AID->getClassInterface() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -904,58 +967,60 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { ObjCPropertyDecl::OBJC_PR_readonly) { Out << (first ? ' ' : ',') << "readonly"; first = false; - } + } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { - Out << (first ? ' ' : ',') << "getter = " - << PDecl->getGetterName().getAsString(); - first = false; - } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { - Out << (first ? ' ' : ',') << "setter = " - << PDecl->getSetterName().getAsString(); - first = false; - } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { + Out << (first ? ' ' : ',') << "getter = " + << PDecl->getGetterName().getAsString(); + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { + Out << (first ? ' ' : ',') << "setter = " + << PDecl->getSetterName().getAsString(); + first = false; + } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { - Out << (first ? ' ' : ',') << "assign"; - first = false; - } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { + Out << (first ? ' ' : ',') << "assign"; + first = false; + } - if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_readwrite) { - Out << (first ? ' ' : ',') << "readwrite"; - first = false; - } + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readwrite) { + Out << (first ? ' ' : ',') << "readwrite"; + first = false; + } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { - Out << (first ? ' ' : ',') << "retain"; - first = false; - } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { + Out << (first ? ' ' : ',') << "retain"; + first = false; + } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) { - Out << (first ? ' ' : ',') << "strong"; - first = false; - } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) { + Out << (first ? ' ' : ',') << "strong"; + first = false; + } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { - Out << (first ? ' ' : ',') << "copy"; - first = false; - } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { + Out << (first ? ' ' : ',') << "copy"; + first = false; + } - if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_nonatomic) { - Out << (first ? ' ' : ',') << "nonatomic"; - first = false; - } - if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_atomic) { - Out << (first ? ' ' : ',') << "atomic"; - first = false; - } - Out << " )"; + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_nonatomic) { + Out << (first ? ' ' : ',') << "nonatomic"; + first = false; + } + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Out << (first ? ' ' : ',') << "atomic"; + first = false; + } + + (void) first; // Silence dead store warning due to idiomatic code. + Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; + Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { @@ -963,15 +1028,15 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { Out << "@synthesize "; else Out << "@dynamic "; - Out << PID->getPropertyDecl(); + Out << *PID->getPropertyDecl(); if (PID->getPropertyIvarDecl()) - Out << '=' << PID->getPropertyIvarDecl(); + Out << '=' << *PID->getPropertyIvarDecl(); } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; D->getQualifier()->print(Out, Policy); - Out << D; + Out << *D; } void diff --git a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp index bc375d0a..558a4cc 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp @@ -348,7 +348,7 @@ void ClassTemplateDecl::AddPartialSpecialization( } void ClassTemplateDecl::getPartialSpecializations( - llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) { + SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) { llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs = getPartialSpecializations(); PS.clear(); @@ -406,7 +406,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { // pack. ASTContext &Context = getASTContext(); TemplateParameterList *Params = getTemplateParameters(); - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + SmallVector<TemplateArgument, 16> TemplateArgs; TemplateArgs.resize(Params->size()); GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data()); CommonPtr->InjectedClassNameType @@ -563,6 +563,24 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(StoredArgs, NumArgs, true); } +FunctionTemplateSpecializationInfo * +FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD, + FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI) { + const ASTTemplateArgumentListInfo *ArgsAsWritten = 0; + if (TemplateArgsAsWritten) + ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C, + *TemplateArgsAsWritten); + + return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK, + TemplateArgs, + ArgsAsWritten, + POI); +} + //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// @@ -638,15 +656,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { SourceRange ClassTemplateSpecializationDecl::getSourceRange() const { - if (!ExplicitInfo) - return SourceRange(); - SourceLocation Begin = getExternLoc(); - if (Begin.isInvalid()) - Begin = getTemplateKeywordLoc(); - SourceLocation End = getRBraceLoc(); - if (End.isInvalid()) - End = getTypeAsWritten()->getTypeLoc().getEndLoc(); - return SourceRange(Begin, End); + if (ExplicitInfo) { + SourceLocation Begin = getExternLoc(); + if (Begin.isInvalid()) + Begin = getTemplateKeywordLoc(); + SourceLocation End = getRBraceLoc(); + if (End.isInvalid()) + End = getTypeAsWritten()->getTypeLoc().getEndLoc(); + return SourceRange(Begin, End); + } + else { + // No explicit info available. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + inst_from = getInstantiatedFrom(); + if (inst_from.isNull()) + return getSpecializedTemplate()->getSourceRange(); + if (ClassTemplateDecl *ctd = inst_from.dyn_cast<ClassTemplateDecl*>()) + return ctd->getSourceRange(); + return inst_from.get<ClassTemplatePartialSpecializationDecl*>() + ->getSourceRange(); + } } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp index 72c0e9d..bf647ed 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp @@ -193,8 +193,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { } // Can't actually get here. - assert(0 && "This should be unreachable!"); - return Identifier; + llvm_unreachable("This should be unreachable!"); } bool DeclarationName::isDependentName() const { @@ -209,7 +208,7 @@ std::string DeclarationName::getAsString() const { return OS.str(); } -void DeclarationName::printName(llvm::raw_ostream &OS) const { +void DeclarationName::printName(raw_ostream &OS) const { switch (getNameKind()) { case Identifier: if (const IdentifierInfo *II = getAsIdentifierInfo()) @@ -225,7 +224,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const { case CXXConstructorName: { QualType ClassType = getCXXNameType(); if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - OS << ClassRec->getDecl(); + OS << *ClassRec->getDecl(); else OS << ClassType.getAsString(); return; @@ -235,7 +234,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const { OS << '~'; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << Rec->getDecl(); + OS << *Rec->getDecl(); else OS << Type.getAsString(); return; @@ -266,7 +265,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const { OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << Rec->getDecl(); + OS << *Rec->getDecl(); else OS << Type.getAsString(); return; @@ -276,7 +275,7 @@ void DeclarationName::printName(llvm::raw_ostream &OS) const { return; } - assert(false && "Unexpected declaration name kind"); + llvm_unreachable("Unexpected declaration name kind"); } QualType DeclarationName::getCXXNameType() const { @@ -338,9 +337,8 @@ void *DeclarationName::getFETokenInfoAsVoid() const { return getCXXLiteralIdentifier()->getFETokenInfo<void>(); default: - assert(false && "Declaration name has no FETokenInfo"); + llvm_unreachable("Declaration name has no FETokenInfo"); } - return 0; } void DeclarationName::setFETokenInfo(void *T) { @@ -364,7 +362,7 @@ void DeclarationName::setFETokenInfo(void *T) { break; default: - assert(false && "Declaration name has no FETokenInfo"); + llvm_unreachable("Declaration name has no FETokenInfo"); } } @@ -562,7 +560,7 @@ std::string DeclarationNameInfo::getAsString() const { return OS.str(); } -void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const { +void DeclarationNameInfo::printName(raw_ostream &OS) const { switch (Name.getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: @@ -588,7 +586,7 @@ void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const { Name.printName(OS); return; } - assert(false && "Unexpected declaration name kind"); + llvm_unreachable("Unexpected declaration name kind"); } SourceLocation DeclarationNameInfo::getEndLoc() const { @@ -621,6 +619,5 @@ SourceLocation DeclarationNameInfo::getEndLoc() const { case DeclarationName::CXXUsingDirective: return NameLoc; } - assert(false && "Unexpected declaration name kind"); - return SourceLocation(); + llvm_unreachable("Unexpected declaration name kind"); } diff --git a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp index dfe0119..2568ada 100644 --- a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp @@ -53,9 +53,9 @@ enum NodeState { }; struct Node { - llvm::StringRef Name; + StringRef Name; NodeState State; - Node(llvm::StringRef name) : Name(name), State(NS_Attrs) {} + Node(StringRef name) : Name(name), State(NS_Attrs) {} bool isDoneWithAttrs() const { return State != NS_Attrs; } }; @@ -159,7 +159,7 @@ template <class Impl> struct XMLTypeVisitor { #undef DISPATCH }; -static llvm::StringRef getTypeKindName(Type *T) { +static StringRef getTypeKindName(Type *T) { switch (T->getTypeClass()) { #define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; #define ABSTRACT_TYPE(DERIVED, BASE) @@ -172,11 +172,11 @@ static llvm::StringRef getTypeKindName(Type *T) { struct XMLDumper : public XMLDeclVisitor<XMLDumper>, public XMLTypeVisitor<XMLDumper> { - llvm::raw_ostream &out; + raw_ostream &out; ASTContext &Context; - llvm::SmallVector<Node, 16> Stack; + SmallVector<Node, 16> Stack; unsigned Indent; - explicit XMLDumper(llvm::raw_ostream &OS, ASTContext &context) + explicit XMLDumper(raw_ostream &OS, ASTContext &context) : out(OS), Context(context), Indent(0) {} void indent() { @@ -185,7 +185,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } /// Push a new node on the stack. - void push(llvm::StringRef name) { + void push(StringRef name) { if (!Stack.empty()) { assert(Stack.back().isDoneWithAttrs()); if (Stack.back().State == NS_LazyChildren) { @@ -200,7 +200,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } /// Set the given attribute to the given value. - void set(llvm::StringRef attr, llvm::StringRef value) { + void set(StringRef attr, StringRef value) { assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation } @@ -226,7 +226,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, //---- General utilities -------------------------------------------// - void setPointer(llvm::StringRef prop, const void *p) { + void setPointer(StringRef prop, const void *p) { llvm::SmallString<10> buffer; llvm::raw_svector_ostream os(buffer); os << p; @@ -238,11 +238,11 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setPointer("ptr", p); } - void setInteger(llvm::StringRef prop, const llvm::APSInt &v) { + void setInteger(StringRef prop, const llvm::APSInt &v) { set(prop, v.toString(10)); } - void setInteger(llvm::StringRef prop, unsigned n) { + void setInteger(StringRef prop, unsigned n) { llvm::SmallString<10> buffer; llvm::raw_svector_ostream os(buffer); os << n; @@ -250,7 +250,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, set(prop, buffer); } - void setFlag(llvm::StringRef prop, bool flag) { + void setFlag(StringRef prop, bool flag) { if (flag) set(prop, "true"); } @@ -268,7 +268,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, class TemporaryContainer { XMLDumper &Dumper; public: - TemporaryContainer(XMLDumper &dumper, llvm::StringRef name) + TemporaryContainer(XMLDumper &dumper, StringRef name) : Dumper(dumper) { Dumper.push(name); Dumper.completeAttrs(); @@ -303,7 +303,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, completeAttrs(); pop(); } - void visitDeclRef(llvm::StringRef Name, Decl *D) { + void visitDeclRef(StringRef Name, Decl *D) { TemporaryContainer C(*this, Name); if (D) visitDeclRef(D); } @@ -423,7 +423,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, // LinkageSpecDecl void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { - llvm::StringRef lang = ""; + StringRef lang = ""; switch (D->getLanguage()) { case LinkageSpecDecl::lang_c: lang = "C"; break; case LinkageSpecDecl::lang_cxx: lang = "C++"; break; @@ -742,8 +742,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, // ObjCClassDecl void visitObjCClassDeclChildren(ObjCClassDecl *D) { - for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) - visitDeclRef(I->getInterface()); + visitDeclRef(D->getForwardInterfaceDecl()); } // ObjCInterfaceDecl @@ -860,7 +859,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } // ObjCIvarDecl - void setAccessControl(llvm::StringRef prop, ObjCIvarDecl::AccessControl AC) { + void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) { switch (AC) { case ObjCIvarDecl::None: return set(prop, "none"); case ObjCIvarDecl::Private: return set(prop, "private"); @@ -1031,13 +1030,13 @@ void Decl::dumpXML() const { dumpXML(llvm::errs()); } -void Decl::dumpXML(llvm::raw_ostream &out) const { +void Decl::dumpXML(raw_ostream &out) const { XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); } #else /* ifndef NDEBUG */ void Decl::dumpXML() const {} -void Decl::dumpXML(llvm::raw_ostream &out) const {} +void Decl::dumpXML(raw_ostream &out) const {} #endif diff --git a/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp index 4611ae3..b0bcfe0 100644 --- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Expr.cpp @@ -130,57 +130,6 @@ SourceLocation Expr::getExprLoc() const { // Primary Expressions. //===----------------------------------------------------------------------===// -void ExplicitTemplateArgumentList::initializeFrom( - const TemplateArgumentListInfo &Info) { - LAngleLoc = Info.getLAngleLoc(); - RAngleLoc = Info.getRAngleLoc(); - NumTemplateArgs = Info.size(); - - TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); - for (unsigned i = 0; i != NumTemplateArgs; ++i) - new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); -} - -void ExplicitTemplateArgumentList::initializeFrom( - const TemplateArgumentListInfo &Info, - bool &Dependent, - bool &InstantiationDependent, - bool &ContainsUnexpandedParameterPack) { - LAngleLoc = Info.getLAngleLoc(); - RAngleLoc = Info.getRAngleLoc(); - NumTemplateArgs = Info.size(); - - TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); - for (unsigned i = 0; i != NumTemplateArgs; ++i) { - Dependent = Dependent || Info[i].getArgument().isDependent(); - InstantiationDependent = InstantiationDependent || - Info[i].getArgument().isInstantiationDependent(); - ContainsUnexpandedParameterPack - = ContainsUnexpandedParameterPack || - Info[i].getArgument().containsUnexpandedParameterPack(); - - new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); - } -} - -void ExplicitTemplateArgumentList::copyInto( - TemplateArgumentListInfo &Info) const { - Info.setLAngleLoc(LAngleLoc); - Info.setRAngleLoc(RAngleLoc); - for (unsigned I = 0; I != NumTemplateArgs; ++I) - Info.addArgument(getTemplateArgs()[I]); -} - -std::size_t ExplicitTemplateArgumentList::sizeFor(unsigned NumTemplateArgs) { - return sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * NumTemplateArgs; -} - -std::size_t ExplicitTemplateArgumentList::sizeFor( - const TemplateArgumentListInfo &Info) { - return sizeFor(Info.size()); -} - /// \brief Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. @@ -325,7 +274,8 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, if (InstantiationDependent) setInstantiationDependent(true); } - + DeclRefExprBits.HadMultipleCandidates = 0; + computeDependence(); } @@ -360,7 +310,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, if (FoundD) Size += sizeof(NamedDecl *); if (TemplateArgs) - Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + Size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs, @@ -378,7 +328,7 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, if (HasFoundDecl) Size += sizeof(NamedDecl *); if (HasExplicitTemplateArgs) - Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + Size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(EmptyShell()); @@ -463,7 +413,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { // For incorrect code, there might not be an ObjCInterfaceDecl. Do // a null check to avoid a crash. if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) - Out << ID; + Out << *ID; if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) @@ -532,9 +482,8 @@ double FloatingLiteral::getValueAsApproximateDouble() const { return V.convertToDouble(); } -StringLiteral *StringLiteral::Create(ASTContext &C, llvm::StringRef Str, - bool Wide, - bool Pascal, QualType Ty, +StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str, + StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs) { // Allocate enough space for the StringLiteral plus an array of locations for @@ -549,7 +498,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, llvm::StringRef Str, memcpy(AStrData, Str.data(), Str.size()); SL->StrData = AStrData; SL->ByteLength = Str.size(); - SL->IsWide = Wide; + SL->Kind = Kind; SL->IsPascal = Pascal; SL->TokLocs[0] = Loc[0]; SL->NumConcatenated = NumStrs; @@ -570,7 +519,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { return SL; } -void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { +void StringLiteral::setString(ASTContext &C, StringRef Str) { char *AStrData = new (C, 1) char[Str.size()]; memcpy(AStrData, Str.data(), Str.size()); StrData = AStrData; @@ -587,8 +536,8 @@ void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { SourceLocation StringLiteral:: getLocationOfByte(unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, const TargetInfo &Target) const { - assert(!isWide() && "This doesn't work for wide strings yet"); - + assert(Kind == StringLiteral::Ascii && "This only works for ASCII strings"); + // Loop over all of the tokens in this string until we find the one that // contains the byte we're looking for. unsigned TokNo = 0; @@ -604,7 +553,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM, // Re-lex the token to get its length and original spelling. std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc); bool Invalid = false; - llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return StrTokSpellingLoc; @@ -647,7 +596,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM, /// corresponds to, e.g. "sizeof" or "[pre]++". const char *UnaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { - default: assert(0 && "Unknown unary operator"); + default: llvm_unreachable("Unknown unary operator"); case UO_PostInc: return "++"; case UO_PostDec: return "--"; case UO_PreInc: return "++"; @@ -667,7 +616,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) { UnaryOperatorKind UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { switch (OO) { - default: assert(false && "No unary operator for overloaded function"); + default: llvm_unreachable("No unary operator for overloaded function"); case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc; case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec; case OO_Amp: return UO_AddrOf; @@ -771,7 +720,13 @@ CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, } Decl *CallExpr::getCalleeDecl() { - Expr *CEE = getCallee()->IgnoreParenCasts(); + Expr *CEE = getCallee()->IgnoreParenImpCasts(); + + while (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) { + CEE = NTTP->getReplacement()->IgnoreParenCasts(); + } + // If we're calling a dereference, look at the pointer instead. if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) { if (BO->isPtrMemOp()) @@ -947,7 +902,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, Size += sizeof(MemberNameQualifier); if (targs) - Size += ExplicitTemplateArgumentList::sizeFor(*targs); + Size += ASTTemplateArgumentListInfo::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>()); MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, @@ -1008,6 +963,94 @@ SourceRange MemberExpr::getSourceRange() const { return SourceRange(StartLoc, EndLoc); } +void CastExpr::CheckCastConsistency() const { + switch (getCastKind()) { + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerived: + case CK_BaseToDerivedMemberPointer: + assert(!path_empty() && "Cast kind should have a base path!"); + break; + + case CK_CPointerToObjCPointerCast: + assert(getType()->isObjCObjectPointerType()); + assert(getSubExpr()->getType()->isPointerType()); + goto CheckNoBasePath; + + case CK_BlockPointerToObjCPointerCast: + assert(getType()->isObjCObjectPointerType()); + assert(getSubExpr()->getType()->isBlockPointerType()); + goto CheckNoBasePath; + + case CK_BitCast: + // Arbitrary casts to C pointer types count as bitcasts. + // Otherwise, we should only have block and ObjC pointer casts + // here if they stay within the type kind. + if (!getType()->isPointerType()) { + assert(getType()->isObjCObjectPointerType() == + getSubExpr()->getType()->isObjCObjectPointerType()); + assert(getType()->isBlockPointerType() == + getSubExpr()->getType()->isBlockPointerType()); + } + goto CheckNoBasePath; + + case CK_AnyPointerToBlockPointerCast: + assert(getType()->isBlockPointerType()); + assert(getSubExpr()->getType()->isAnyPointerType() && + !getSubExpr()->getType()->isBlockPointerType()); + goto CheckNoBasePath; + + // These should not have an inheritance path. + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToMemberPointer: + case CK_NullToPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: + assert(!getType()->isBooleanType() && "unheralded conversion to bool"); + goto CheckNoBasePath; + + case CK_Dependent: + case CK_LValueToRValue: + case CK_GetObjCProperty: + case CK_NoOp: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_FloatingToBoolean: + case CK_MemberPointerToBoolean: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: + case CK_LValueBitCast: // -> bool& + case CK_UserDefinedConversion: // operator bool() + CheckNoBasePath: + assert(path_empty() && "Cast kind should not have a base path!"); + break; + } +} + const char *CastExpr::getCastKindName() const { switch (getCastKind()) { case CK_Dependent: @@ -1072,8 +1115,10 @@ const char *CastExpr::getCastKindName() const { return "FloatingToBoolean"; case CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; - case CK_AnyPointerToObjCPointerCast: - return "AnyPointerToObjCPointerCast"; + case CK_CPointerToObjCPointerCast: + return "CPointerToObjCPointerCast"; + case CK_BlockPointerToObjCPointerCast: + return "BlockPointerToObjCPointerCast"; case CK_AnyPointerToBlockPointerCast: return "AnyPointerToBlockPointerCast"; case CK_ObjCObjectLValueCast: @@ -1098,12 +1143,14 @@ const char *CastExpr::getCastKindName() const { return "IntegralComplexCast"; case CK_IntegralComplexToFloatingComplex: return "IntegralComplexToFloatingComplex"; - case CK_ObjCConsumeObject: - return "ObjCConsumeObject"; - case CK_ObjCProduceObject: - return "ObjCProduceObject"; - case CK_ObjCReclaimReturnedObject: - return "ObjCReclaimReturnedObject"; + case CK_ARCConsumeObject: + return "ARCConsumeObject"; + case CK_ARCProduceObject: + return "ARCProduceObject"; + case CK_ARCReclaimReturnedObject: + return "ARCReclaimReturnedObject"; + case CK_ARCExtendBlockObject: + return "ARCCExtendBlockObject"; } llvm_unreachable("Unhandled cast kind!"); @@ -1243,7 +1290,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) { BinaryOperatorKind BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { switch (OO) { - default: assert(false && "Not an overloadable binary operator"); + default: llvm_unreachable("Not an overloadable binary operator"); case OO_Plus: return BO_Add; case OO_Minus: return BO_Sub; case OO_Star: return BO_Mul; @@ -1491,6 +1538,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, } case CompoundAssignOperatorClass: case VAArgExprClass: + case AtomicExprClass: return false; case ConditionalOperatorClass: { @@ -1525,8 +1573,24 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange(); return true; + case CXXOperatorCallExprClass: { + // We warn about operator== and operator!= even when user-defined operator + // overloads as there is no reasonable way to define these such that they + // have non-trivial, desirable side-effects. See the -Wunused-comparison + // warning: these operators are commonly typo'ed, and so warning on them + // provides additional value as well. If this list is updated, + // DiagnoseUnusedComparison should be as well. + const CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(this); + if (Op->getOperator() == OO_EqualEqual || + Op->getOperator() == OO_ExclaimEqual) { + Loc = Op->getOperatorLoc(); + R1 = Op->getSourceRange(); + return true; + } + + // Fallthrough for generic call handling. + } case CallExprClass: - case CXXOperatorCallExprClass: case CXXMemberCallExprClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); @@ -1666,8 +1730,15 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { ->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case BlockDeclRefExprClass: case DeclRefExprClass: { - const Decl *D = cast<DeclRefExpr>(E)->getDecl(); + + const Decl *D; + if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E)) + D = BDRE->getDecl(); + else + D = cast<DeclRefExpr>(E)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasGlobalStorage()) return true; @@ -2024,7 +2095,11 @@ Expr *Expr::IgnoreParenCasts() { E = Materialize->GetTemporaryExpr(); continue; } - + if (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { + E = NTTP->getReplacement(); + continue; + } return E; } } @@ -2058,6 +2133,10 @@ Expr *Expr::IgnoreParenLValueCasts() { = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); continue; + } else if (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { + E = NTTP->getReplacement(); + continue; } break; } @@ -2092,6 +2171,11 @@ Expr *Expr::IgnoreParenImpCasts() { E = Materialize->GetTemporaryExpr(); continue; } + if (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { + E = NTTP->getReplacement(); + continue; + } return E; } } @@ -2149,6 +2233,12 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } + if (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { + E = NTTP->getReplacement(); + continue; + } + return E; } } @@ -2397,7 +2487,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { break; case MaterializeTemporaryExprClass: - return llvm::cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() + return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); @@ -2414,9 +2504,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx, if (isValueDependent()) { switch (NPC) { case NPC_NeverValueDependent: - assert(false && "Unexpected value dependent expression!"); - // If the unthinkable happens, fall through to the safest alternative. - + llvm_unreachable("Unexpected value dependent expression!"); case NPC_ValueDependentIsNull: if (isTypeDependent() || getType()->isIntegralType(Ctx)) return NPCK_ZeroInteger; @@ -2576,7 +2664,7 @@ unsigned ExtVectorElementExpr::getNumElements() const { bool ExtVectorElementExpr::containsDuplicateElements() const { // FIXME: Refactor this code to an accessor on the AST node which returns the // "type" of component access, and share with code below and in Sema. - llvm::StringRef Comp = Accessor->getName(); + StringRef Comp = Accessor->getName(); // Halving swizzles do not contain duplicate elements. if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd") @@ -2587,7 +2675,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { Comp = Comp.substr(1); for (unsigned i = 0, e = Comp.size(); i != e; ++i) - if (Comp.substr(i + 1).find(Comp[i]) != llvm::StringRef::npos) + if (Comp.substr(i + 1).find(Comp[i]) != StringRef::npos) return true; return false; @@ -2595,8 +2683,8 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { /// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. void ExtVectorElementExpr::getEncodedElementAccess( - llvm::SmallVectorImpl<unsigned> &Elts) const { - llvm::StringRef Comp = Accessor->getName(); + SmallVectorImpl<unsigned> &Elts) const { + StringRef Comp = Accessor->getName(); if (Comp[0] == 's' || Comp[0] == 'S') Comp = Comp.substr(1); @@ -2630,23 +2718,23 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, bool IsInstanceSuper, QualType SuperType, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/false, /*InstantiationDependent=*/false, /*ContainsUnexpandedParameterPack=*/false), - NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), - HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) + Kind(IsInstanceSuper? SuperInstance : SuperClass), + HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { + initArgsAndSelLocs(Args, SelLocs, SelLocsK); setReceiverPointer(SuperType.getAsOpaquePtr()); - if (NumArgs) - memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); } ObjCMessageExpr::ObjCMessageExpr(QualType T, @@ -2654,33 +2742,22 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, SourceLocation LBracLoc, TypeSourceInfo *Receiver, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Class), - HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) + Kind(Class), + HasMethod(Method != 0), IsDelegateInitCall(false), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { + initArgsAndSelLocs(Args, SelLocs, SelLocsK); setReceiverPointer(Receiver); - Expr **MyArgs = getArgs(); - for (unsigned I = 0; I != NumArgs; ++I) { - if (Args[I]->isTypeDependent()) - ExprBits.TypeDependent = true; - if (Args[I]->isValueDependent()) - ExprBits.ValueDependent = true; - if (Args[I]->isInstantiationDependent()) - ExprBits.InstantiationDependent = true; - if (Args[I]->containsUnexpandedParameterPack()) - ExprBits.ContainsUnexpandedParameterPack = true; - - MyArgs[I] = Args[I]; - } } ObjCMessageExpr::ObjCMessageExpr(QualType T, @@ -2688,23 +2765,31 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, SourceLocation LBracLoc, Expr *Receiver, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(), Receiver->isTypeDependent(), Receiver->isInstantiationDependent(), Receiver->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Instance), - HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) + Kind(Instance), + HasMethod(Method != 0), IsDelegateInitCall(false), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { + initArgsAndSelLocs(Args, SelLocs, SelLocsK); setReceiverPointer(Receiver); +} + +void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK) { + setNumArgs(Args.size()); Expr **MyArgs = getArgs(); - for (unsigned I = 0; I != NumArgs; ++I) { + for (unsigned I = 0; I != Args.size(); ++I) { if (Args[I]->isTypeDependent()) ExprBits.TypeDependent = true; if (Args[I]->isValueDependent()) @@ -2716,6 +2801,10 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, MyArgs[I] = Args[I]; } + + SelLocsKind = SelLocsK; + if (SelLocsK == SelLoc_NonStandard) + std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs()); } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, @@ -2725,16 +2814,15 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, bool IsInstanceSuper, QualType SuperType, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) { - unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + - NumArgs * sizeof(Expr *); - void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + SelectorLocationsKind SelLocsK; + ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper, - SuperType, Sel, SelLoc, Method, Args,NumArgs, - RBracLoc); + SuperType, Sel, SelLocs, SelLocsK, + Method, Args, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, @@ -2742,15 +2830,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, SourceLocation LBracLoc, TypeSourceInfo *Receiver, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) { - unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + - NumArgs * sizeof(Expr *); - void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); - return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, - Method, Args, NumArgs, RBracLoc); + SelectorLocationsKind SelLocsK; + ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, + SelLocs, SelLocsK, Method, Args, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, @@ -2758,25 +2845,50 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, SourceLocation LBracLoc, Expr *Receiver, Selector Sel, - SourceLocation SelLoc, + ArrayRef<SourceLocation> SelLocs, ObjCMethodDecl *Method, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, SourceLocation RBracLoc) { - unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + - NumArgs * sizeof(Expr *); - void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); - return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, - Method, Args, NumArgs, RBracLoc); + SelectorLocationsKind SelLocsK; + ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, + SelLocs, SelLocsK, Method, Args, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, - unsigned NumArgs) { - unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + - NumArgs * sizeof(Expr *); - void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + unsigned NumArgs, + unsigned NumStoredSelLocs) { + ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs); return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); } +ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, + ArrayRef<Expr *> Args, + SourceLocation RBraceLoc, + ArrayRef<SourceLocation> SelLocs, + Selector Sel, + SelectorLocationsKind &SelLocsK) { + SelLocsK = hasStandardSelectorLocs(Sel, SelLocs, Args, RBraceLoc); + unsigned NumStoredSelLocs = (SelLocsK == SelLoc_NonStandard) ? SelLocs.size() + : 0; + return alloc(C, Args.size(), NumStoredSelLocs); +} + +ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, + unsigned NumArgs, + unsigned NumStoredSelLocs) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *) + NumStoredSelLocs * sizeof(SourceLocation); + return (ObjCMessageExpr *)C.Allocate(Size, + llvm::AlignOf<ObjCMessageExpr>::Alignment); +} + +void ObjCMessageExpr::getSelectorLocs( + SmallVectorImpl<SourceLocation> &SelLocs) const { + for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i) + SelLocs.push_back(getSelectorLoc(i)); +} + SourceRange ObjCMessageExpr::getReceiverRange() const { switch (getReceiverKind()) { case Instance: @@ -2830,7 +2942,7 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return 0; } -llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const { +StringRef ObjCBridgedCastExpr::getBridgeKindName() const { switch (getBridgeKind()) { case OBC_Bridge: return "__bridge"; @@ -2844,7 +2956,7 @@ llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const { } bool ChooseExpr::isConditionTrue(const ASTContext &C) const { - return getCond()->EvaluateAsInt(C) != 0; + return getCond()->EvaluateKnownConstInt(C) != 0; } ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, @@ -3203,3 +3315,24 @@ BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, ExprBits.ValueDependent = ValueDependent; ExprBits.InstantiationDependent = InstantiationDependent; } + + +AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, + QualType t, AtomicOp op, SourceLocation RP) + : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary, + false, false, false, false), + NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) +{ + for (unsigned i = 0; i < nexpr; i++) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i] = args[i]; + } +} diff --git a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp index f92afff..ad5ec8b 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp @@ -49,6 +49,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, + bool HadMultipleCandidates, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, QualType ty, TypeSourceInfo *AllocatedTypeInfo, @@ -61,6 +62,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, ty->containsUnexpandedParameterPack()), GlobalNew(globalNew), Initializer(initializer), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), + HadMultipleCandidates(HadMultipleCandidates), SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens), @@ -202,7 +204,7 @@ UnresolvedLookupExpr::Create(ASTContext &C, UnresolvedSetIterator End) { void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + - ExplicitTemplateArgumentList::sizeFor(Args)); + ASTTemplateArgumentListInfo::sizeFor(Args)); return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo, ADL, /*Overload*/ true, &Args, Begin, End, /*StdIsAssociated=*/false); @@ -213,7 +215,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedLookupExpr); if (HasExplicitTemplateArgs) - size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>()); UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); @@ -332,7 +334,7 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, bool ContainsUnexpandedParameterPack = ExprBits.ContainsUnexpandedParameterPack; - reinterpret_cast<ExplicitTemplateArgumentList*>(this+1) + reinterpret_cast<ASTTemplateArgumentListInfo*>(this+1) ->initializeFrom(*Args, Dependent, InstantiationDependent, ContainsUnexpandedParameterPack); @@ -347,7 +349,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, const TemplateArgumentListInfo *Args) { std::size_t size = sizeof(DependentScopeDeclRefExpr); if (Args) - size += ExplicitTemplateArgumentList::sizeFor(*Args); + size += ASTTemplateArgumentListInfo::sizeFor(*Args); void *Mem = C.Allocate(size); return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc, NameInfo, Args); @@ -359,7 +361,7 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { std::size_t size = sizeof(DependentScopeDeclRefExpr); if (HasExplicitTemplateArgs) - size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size); DependentScopeDeclRefExpr *E = new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(), @@ -628,11 +630,13 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, Expr **Args, unsigned NumArgs, SourceRange parenRange, + bool HadMultipleCandidates, bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type->getType().getNonReferenceType(), Type->getTypeLoc().getBeginLoc(), - Cons, false, Args, NumArgs, ZeroInitialization, + Cons, false, Args, NumArgs, + HadMultipleCandidates, ZeroInitialization, CXXConstructExpr::CK_Complete, parenRange), Type(Type) { } @@ -646,11 +650,13 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, + bool HadMultipleCandidates, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, ZeroInitialization, + Elidable, Args, NumArgs, + HadMultipleCandidates, ZeroInitialization, ConstructKind, ParenRange); } @@ -658,16 +664,18 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization, + bool HadMultipleCandidates, + bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) : Expr(SC, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable), - ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), - Args(0), NumArgs(numargs) + Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs), + Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), + ZeroInitialization(ZeroInitialization), + ConstructKind(ConstructKind), Args(0) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -838,7 +846,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, std::size_t size = sizeof(CXXDependentScopeMemberExpr); if (TemplateArgs) - size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, @@ -859,7 +867,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, DeclarationNameInfo()); std::size_t size = sizeof(CXXDependentScopeMemberExpr) + - ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); CXXDependentScopeMemberExpr *E = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(), @@ -947,7 +955,7 @@ UnresolvedMemberExpr::Create(ASTContext &C, UnresolvedSetIterator End) { std::size_t size = sizeof(UnresolvedMemberExpr); if (TemplateArgs) - size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); return new (Mem) UnresolvedMemberExpr(C, @@ -961,7 +969,7 @@ UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedMemberExpr); if (HasExplicitTemplateArgs) - size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); diff --git a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp index e7888a6..49c6821 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp @@ -162,6 +162,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::AtomicExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -393,7 +394,7 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) { // C++ [expr.call]p10: A function call is an lvalue if the result type is an // lvalue reference type or an rvalue reference to function type, an xvalue - // if the result type is an rvalue refernence to object type, and a prvalue + // if the result type is an rvalue reference to object type, and a prvalue // otherwise. if (T->isLValueReferenceType()) return Cl::CL_LValue; diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index 786155a..df75bc8 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -59,6 +59,8 @@ namespace { EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult) : Ctx(ctx), EvalResult(evalresult) {} + + const LangOptions &getLangOpts() { return Ctx.getLangOptions(); } }; struct ComplexValue { @@ -378,18 +380,22 @@ private: RetTy DerivedError(const Expr *E) { return static_cast<Derived*>(this)->Error(E); } + RetTy DerivedValueInitialization(const Expr *E) { + return static_cast<Derived*>(this)->ValueInitialization(E); + } protected: EvalInfo &Info; typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy; typedef ExprEvaluatorBase ExprEvaluatorBaseTy; + RetTy ValueInitialization(const Expr *E) { return DerivedError(E); } + public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} RetTy VisitStmt(const Stmt *) { - assert(0 && "Expression evaluator should not be called on stmts"); - return DerivedError(0); + llvm_unreachable("Expression evaluator should not be called on stmts"); } RetTy VisitExpr(const Expr *E) { return DerivedError(E); @@ -436,6 +442,23 @@ public: : DerivedError(E)); return DerivedSuccess(*value, E); } + + RetTy VisitInitListExpr(const InitListExpr *E) { + if (Info.getLangOpts().CPlusPlus0x) { + if (E->getNumInits() == 0) + return DerivedValueInitialization(E); + if (E->getNumInits() == 1) + return StmtVisitorTy::Visit(E->getInit(0)); + } + return DerivedError(E); + } + RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { + return DerivedValueInitialization(E); + } + RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { + return DerivedValueInitialization(E); + } + }; } @@ -447,6 +470,7 @@ namespace { class LValueExprEvaluator : public ExprEvaluatorBase<LValueExprEvaluator, bool> { LValue &Result; + const Decl *PrevDecl; bool Success(const Expr *E) { Result.Base = E; @@ -456,7 +480,7 @@ class LValueExprEvaluator public: LValueExprEvaluator(EvalInfo &info, LValue &Result) : - ExprEvaluatorBaseTy(info), Result(Result) {} + ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {} bool Success(const APValue &V, const Expr *E) { Result.setFrom(V); @@ -481,9 +505,13 @@ public: return false; case CK_NoOp: + case CK_LValueBitCast: return Visit(E->getSubExpr()); + + // FIXME: Support CK_DerivedToBase and friends. } } + // FIXME: Missing: __real__, __imag__ }; @@ -501,10 +529,16 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { return Success(E); // Reference parameters can refer to anything even if they have an // "initializer" in the form of a default argument. - if (!isa<ParmVarDecl>(VD)) + if (!isa<ParmVarDecl>(VD)) { // FIXME: Check whether VD might be overridden! + + // Check for recursive initializers of references. + if (PrevDecl == VD) + return Error(E); + PrevDecl = VD; if (const Expr *Init = VD->getAnyInitializer()) return Visit(Init); + } } return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); @@ -585,6 +619,9 @@ public: bool Error(const Stmt *S) { return false; } + bool ValueInitialization(const Expr *E) { + return Success((Expr*)0); + } bool VisitBinaryOperator(const BinaryOperator *E); bool VisitCastExpr(const CastExpr* E); @@ -599,10 +636,8 @@ public: return Success(E); return false; } - bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) - { return Success((Expr*)0); } bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) - { return Success((Expr*)0); } + { return ValueInitialization(E); } // FIXME: Missing: @protocol, @selector }; @@ -667,7 +702,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { case CK_NoOp: case CK_BitCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); @@ -761,11 +797,11 @@ namespace { APValue Success(const APValue &V, const Expr *E) { return V; } APValue Error(const Expr *E) { return APValue(); } + APValue ValueInitialization(const Expr *E) + { return GetZeroVector(E->getType()); } APValue VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) - { return GetZeroVector(E->getType()); } APValue VisitCastExpr(const CastExpr* E); APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); APValue VisitInitListExpr(const InitListExpr *E); @@ -812,7 +848,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { } // Splat and create vector APValue. - llvm::SmallVector<APValue, 4> Elts(NElts, Result); + SmallVector<APValue, 4> Elts(NElts, Result); return APValue(&Elts[0], Elts.size()); } case CK_BitCast: { @@ -829,7 +865,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) && "Vectors must be composed of ints or floats"); - llvm::SmallVector<APValue, 4> Elts; + SmallVector<APValue, 4> Elts; for (unsigned i = 0; i != NElts; ++i) { APSInt Tmp = Init.extOrTrunc(EltWidth); @@ -862,7 +898,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { unsigned NumElements = VT->getNumElements(); QualType EltTy = VT->getElementType(); - llvm::SmallVector<APValue, 4> Elements; + SmallVector<APValue, 4> Elements; // If a vector is initialized with a single element, that value // becomes every element of the vector, not just the first. @@ -926,7 +962,7 @@ VectorExprEvaluator::GetZeroVector(QualType T) { ZeroElement = APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy))); - llvm::SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement); + SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement); return APValue(&Elements[0], Elements.size()); } @@ -999,6 +1035,8 @@ public: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); } + bool ValueInitialization(const Expr *E) { return Success(0, E); } + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -1039,16 +1077,9 @@ public: return Success(E->getValue(), E); } + // Note, GNU defines __null as an integer, not a pointer. bool VisitGNUNullExpr(const GNUNullExpr *E) { - return Success(0, E); - } - - bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { - return Success(0, E); - } - - bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { - return Success(0, E); + return ValueInitialization(E); } bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { @@ -1072,7 +1103,7 @@ public: bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); - + private: CharUnits GetAlignOfExpr(const Expr *E); CharUnits GetAlignOfType(QualType T); @@ -1210,7 +1241,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { else if (ArgTy->isUnionType()) return union_type_class; else // FIXME: offset_type_class, method_type_class, & lang_type_class? - assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); + llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); return -1; } @@ -1267,7 +1298,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { // If evaluating the argument has side-effects we can't determine // the size of the object and lower it to unknown now. if (E->getArg(0)->HasSideEffects(Info.Ctx)) { - if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1) + if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1) return Success(-1ULL, E); return Success(0, E); } @@ -1284,8 +1315,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E); case Builtin::BI__builtin_eh_return_data_regno: { - int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue(); - Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); + int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); + Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand); return Success(Operand, E); } @@ -1300,9 +1331,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) { // The string literal may have embedded null characters. Find the first // one and truncate there. - llvm::StringRef Str = S->getString(); - llvm::StringRef::size_type Pos = Str.find(0); - if (Pos != llvm::StringRef::npos) + StringRef Str = S->getString(); + StringRef::size_type Pos = Str.find(0); + if (Pos != StringRef::npos) Str = Str.substr(0, Pos); return Success(Str.size(), E); @@ -1419,7 +1450,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { default: - assert(0 && "Invalid binary operator!"); + llvm_unreachable("Invalid binary operator!"); case BO_LT: return Success(CR == APFloat::cmpLessThan, E); case BO_GT: @@ -1801,7 +1832,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_VectorSplat: case CK_IntegralToFloating: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: @@ -1818,9 +1850,10 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_GetObjCProperty: case CK_LValueBitCast: case CK_UserDefinedConversion: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: return false; case CK_LValueToRValue: @@ -1943,13 +1976,17 @@ public: return false; } + bool ValueInitialization(const Expr *E) { + Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType())); + return true; + } + bool VisitCallExpr(const CallExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitFloatingLiteral(const FloatingLiteral *E); bool VisitCastExpr(const CastExpr *E); - bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E); bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); @@ -2219,11 +2256,6 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { return false; } -bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { - Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType())); - return true; -} - //===----------------------------------------------------------------------===// // Complex Evaluation (for float and integer) //===----------------------------------------------------------------------===// @@ -2255,7 +2287,7 @@ public: bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); - // FIXME Missing: ImplicitValueInitExpr + // FIXME Missing: ImplicitValueInitExpr, InitListExpr }; } // end anonymous namespace @@ -2318,16 +2350,18 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: @@ -2633,6 +2667,13 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, return HandleConversionToBool(this, Result, Info); } +bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { + EvalResult Scratch; + EvalInfo Info(Ctx, Scratch); + + return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects; +} + bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); @@ -2671,7 +2712,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return HasSideEffect(Info).Visit(this); } -APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const { +APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const { EvalResult EvalResult; bool Result = Evaluate(EvalResult, Ctx); (void)Result; @@ -2755,7 +2796,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: case Expr::ExtVectorElementExprClass: - case Expr::InitListExprClass: case Expr::DesignatedInitExprClass: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: @@ -2800,6 +2840,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::MaterializeTemporaryExprClass: + case Expr::AtomicExprClass: + return ICEDiag(2, E->getLocStart()); + + case Expr::InitListExprClass: + if (Ctx.getLangOptions().CPlusPlus0x) { + const InitListExpr *ILE = cast<InitListExpr>(E); + if (ILE->getNumInits() == 0) + return NoDiag(); + if (ILE->getNumInits() == 1) + return CheckICE(ILE->getInit(0), Ctx); + // Fall through for more than 1 expression. + } return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: @@ -2963,11 +3015,11 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // Evaluate gives an error for undefined Div/Rem, so make sure // we don't evaluate one. if (LHSResult.Val == 0 && RHSResult.Val == 0) { - llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); + llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx); if (REval == 0) return ICEDiag(1, E->getLocStart()); if (REval.isSigned() && REval.isAllOnesValue()) { - llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); + llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx); if (LEval.isMinSignedValue()) return ICEDiag(1, E->getLocStart()); } @@ -2998,11 +3050,11 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // evaluated are not considered. if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) { if (Exp->getOpcode() == BO_LAnd && - Exp->getLHS()->EvaluateAsInt(Ctx) == 0) + Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0) return LHSResult; if (Exp->getOpcode() == BO_LOr && - Exp->getLHS()->EvaluateAsInt(Ctx) != 0) + Exp->getLHS()->EvaluateKnownConstInt(Ctx) != 0) return LHSResult; } @@ -3012,7 +3064,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // to actually check the condition to see whether the side // with the comma is evaluated. if ((Exp->getOpcode() == BO_LAnd) != - (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) + (Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0)) return RHSResult; return NoDiag(); } @@ -3031,11 +3083,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: { const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); - if (SubExpr->getType()->isIntegralOrEnumerationType()) + switch (cast<CastExpr>(E)->getCastKind()) { + case CK_LValueToRValue: + case CK_NoOp: + case CK_IntegralToBoolean: + case CK_IntegralCast: return CheckICE(SubExpr, Ctx); - if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) - return NoDiag(); - return ICEDiag(2, E->getLocStart()); + default: + if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } } case Expr::BinaryConditionalOperatorClass: { const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E); @@ -3045,7 +3103,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (FalseResult.Val == 2) return FalseResult; if (CommonResult.Val == 1) return CommonResult; if (FalseResult.Val == 1 && - Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag(); + Exp->getCommon()->EvaluateKnownConstInt(Ctx) == 0) return NoDiag(); return FalseResult; } case Expr::ConditionalOperatorClass: { @@ -3072,7 +3130,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // subexpressions of [...] conditional (5.16) operations that // are not evaluated are not considered bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x - ? Exp->getCond()->EvaluateAsInt(Ctx) != 0 + ? Exp->getCond()->EvaluateKnownConstInt(Ctx) != 0 : false; ICEDiag TrueResult = NoDiag(); if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch) @@ -3092,7 +3150,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // Rare case where the diagnostics depend on which side is evaluated // Note that if we get here, CondResult is 0, and at least one of // TrueResult and FalseResult is non-zero. - if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { + if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) { return FalseResult; } return TrueResult; diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp index b96d65a..fd616db 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp @@ -49,12 +49,10 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return DeclContext::lookup_result(); } -void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { } - ExternalLoadResult ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), - llvm::SmallVectorImpl<Decl*> &Result) { + SmallVectorImpl<Decl*> &Result) { return ELR_AlreadyLoaded; } diff --git a/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp b/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp index c47a9da..b70520f 100644 --- a/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp +++ b/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp @@ -33,12 +33,12 @@ namespace clang { /// vs. non-virtual bases. class InheritanceHierarchyWriter { ASTContext& Context; - llvm::raw_ostream &Out; + raw_ostream &Out; std::map<QualType, int, QualTypeOrdering> DirectBaseCount; std::set<QualType, QualTypeOrdering> KnownVirtualBases; public: - InheritanceHierarchyWriter(ASTContext& Context, llvm::raw_ostream& Out) + InheritanceHierarchyWriter(ASTContext& Context, raw_ostream& Out) : Context(Context), Out(Out) { } void WriteGraph(QualType Type) { @@ -55,7 +55,7 @@ protected: /// WriteNodeReference - Write out a reference to the given node, /// using a unique identifier for each direct base and for the /// (only) virtual base. - llvm::raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual); + raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual); }; void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { @@ -120,7 +120,7 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { /// WriteNodeReference - Write out a reference to the given node, /// using a unique identifier for each direct base and for the /// (only) virtual base. -llvm::raw_ostream& +raw_ostream& InheritanceHierarchyWriter::WriteNodeReference(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp index 30aece3..0027dbf 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp @@ -53,7 +53,7 @@ public: const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); CharUnits PointerSize = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize; } }; diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp index ec9863b..acedf70 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp @@ -73,7 +73,7 @@ class ItaniumMangleContext : public MangleContext { public: explicit ItaniumMangleContext(ASTContext &Context, - Diagnostic &Diags) + DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { } uint64_t getAnonymousStructId(const TagDecl *TD) { @@ -92,30 +92,30 @@ public: /// @{ bool shouldMangleDeclName(const NamedDecl *D); - void mangleName(const NamedDecl *D, llvm::raw_ostream &); + void mangleName(const NamedDecl *D, raw_ostream &); void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, - llvm::raw_ostream &); + raw_ostream &); void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &ThisAdjustment, - llvm::raw_ostream &); + raw_ostream &); void mangleReferenceTemporary(const VarDecl *D, - llvm::raw_ostream &); + raw_ostream &); void mangleCXXVTable(const CXXRecordDecl *RD, - llvm::raw_ostream &); + raw_ostream &); void mangleCXXVTT(const CXXRecordDecl *RD, - llvm::raw_ostream &); + raw_ostream &); void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &); - void mangleCXXRTTI(QualType T, llvm::raw_ostream &); - void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + raw_ostream &); + void mangleCXXRTTI(QualType T, raw_ostream &); + void mangleCXXRTTIName(QualType T, raw_ostream &); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::raw_ostream &); + raw_ostream &); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::raw_ostream &); + raw_ostream &); - void mangleItaniumGuardVariable(const VarDecl *D, llvm::raw_ostream &); + void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); void mangleInitDiscriminator() { Discriminator = 0; @@ -136,7 +136,7 @@ public: /// CXXNameMangler - Manage the mangling of a single name. class CXXNameMangler { ItaniumMangleContext &Context; - llvm::raw_ostream &Out; + raw_ostream &Out; /// The "structor" is the top-level declaration being mangled, if /// that's not a template specialization; otherwise it's the pattern @@ -191,7 +191,7 @@ class CXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: - CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, const NamedDecl *D = 0) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), SeqID(0) { @@ -199,11 +199,11 @@ public: assert(!D || (!isa<CXXDestructorDecl>(D) && !isa<CXXConstructorDecl>(D))); } - CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), SeqID(0) { } - CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), SeqID(0) { } @@ -219,9 +219,9 @@ public: free(result); } #endif - llvm::raw_ostream &getStream() { return Out; } + raw_ostream &getStream() { return Out; } - void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); + void mangle(const NamedDecl *D, StringRef Prefix = "_Z"); void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); void mangleNumber(const llvm::APSInt &I); void mangleNumber(int64_t Number); @@ -310,7 +310,7 @@ private: void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); - void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs); + void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); void mangleTemplateArgs(TemplateName Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -385,7 +385,7 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { return true; } -void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { +void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { // Any decl can be declared with __asm("foo") on it, and this takes precedence // over all other naming in the .o file. if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { @@ -397,8 +397,8 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { // llvm mangler on ELF is a nop, so we can just avoid adding the \01 // marker. We also avoid adding the marker if this is an alias for an // LLVM intrinsic. - llvm::StringRef UserLabelPrefix = - getASTContext().Target.getUserLabelPrefix(); + StringRef UserLabelPrefix = + getASTContext().getTargetInfo().getUserLabelPrefix(); if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) Out << '\01'; // LLVM IR Marker for __asm("foo") @@ -788,6 +788,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::Atomic: llvm_unreachable("type is illegal as a nested name specifier"); case Type::SubstTemplateTypeParmPack: @@ -1069,8 +1070,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - assert(false && "Can't mangle Objective-C selector names here!"); - break; + llvm_unreachable("Can't mangle Objective-C selector names here!"); case DeclarationName::CXXConstructorName: if (ND == Structor) @@ -1124,8 +1124,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; case DeclarationName::CXXUsingDirective: - assert(false && "Can't mangle a using directive name!"); - break; + llvm_unreachable("Can't mangle a using directive name!"); } } @@ -1512,8 +1511,7 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_None: case NUM_OVERLOADED_OPERATORS: - assert(false && "Not an overloaded operator"); - break; + llvm_unreachable("Not an overloaded operator"); } } @@ -1538,7 +1536,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { Out << 'U' << ASString.size() << ASString; } - llvm::StringRef LifetimeName; + StringRef LifetimeName; switch (Quals.getObjCLifetime()) { // Objective-C ARC Extension: // @@ -1706,7 +1704,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) - // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= Dh # IEEE 754r half-precision floating point (16 bits) // ::= Di # char32_t // ::= Ds # char16_t // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) @@ -1731,6 +1729,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Long: Out << 'l'; break; case BuiltinType::LongLong: Out << 'x'; break; case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Half: Out << "Dh"; break; case BuiltinType::Float: Out << 'f'; break; case BuiltinType::Double: Out << 'd'; break; case BuiltinType::LongDouble: Out << 'e'; break; @@ -2114,6 +2113,13 @@ void CXXNameMangler::mangleType(const AutoType *T) { mangleType(D); } +void CXXNameMangler::mangleType(const AtomicType *T) { + // <type> ::= U <source-name> <type> # vendor extended type qualifier + // (Until there's a standardized mangling...) + Out << "U7_Atomic"; + mangleType(T->getValueType()); +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // <expr-primary> ::= L <type> <value number> E # integer literal @@ -2250,10 +2256,11 @@ recurse: case Expr::CXXNoexceptExprClass: case Expr::CUDAKernelCallExprClass: case Expr::AsTypeExprClass: + case Expr::AtomicExprClass: { // As bad as this diagnostic is, it's better than crashing. - Diagnostic &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet mangle expression type %0"); Diags.Report(E->getExprLoc(), DiagID) << E->getStmtClassName() << E->getSourceRange(); @@ -2262,9 +2269,9 @@ recurse: // Even gcc-4.5 doesn't mangle this. case Expr::BinaryConditionalOperatorClass: { - Diagnostic &Diags = Context.getDiags(); + DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = - Diags.getCustomDiagID(Diagnostic::Error, + Diags.getCustomDiagID(DiagnosticsEngine::Error, "?: operator with omitted middle operand cannot be mangled"); Diags.Report(E->getExprLoc(), DiagID) << E->getStmtClassName() << E->getSourceRange(); @@ -2411,7 +2418,8 @@ recurse: QualType T = (ImplicitlyConvertedToType.isNull() || !ImplicitlyConvertedToType->isIntegerType())? SAE->getType() : ImplicitlyConvertedToType; - mangleIntegerLiteral(T, SAE->EvaluateAsInt(Context.getASTContext())); + llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext()); + mangleIntegerLiteral(T, V); break; } @@ -2423,8 +2431,8 @@ recurse: Out << 'a'; break; case UETT_VecStep: - Diagnostic &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet mangle vec_step expression"); Diags.Report(DiagID); return; @@ -2526,7 +2534,7 @@ recurse: case Expr::ObjCBridgedCastExprClass: { // Mangle ownership casts as a vendor extended operator __bridge, // __bridge_transfer, or __bridge_retain. - llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName(); + StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName(); Out << "v1U" << Kind.size() << Kind; } // Fall through to mangle the cast itself. @@ -2817,7 +2825,7 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } void CXXNameMangler::mangleTemplateArgs( - const ExplicitTemplateArgumentList &TemplateArgs) { + const ASTTemplateArgumentListInfo &TemplateArgs) { // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) @@ -3021,7 +3029,7 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { } Out << 'S' - << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) + << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) << '_'; } @@ -3196,7 +3204,7 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) { /// emit the identifier of the declaration (\c D->getIdentifier()) as its /// name. void ItaniumMangleContext::mangleName(const NamedDecl *D, - llvm::raw_ostream &Out) { + raw_ostream &Out) { assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && "Invalid mangleName() call, argument is not a variable or function!"); assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && @@ -3212,21 +3220,21 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D, void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::raw_ostream &Out) { + raw_ostream &Out) { CXXNameMangler Mangler(*this, Out, D, Type); Mangler.mangle(D); } void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::raw_ostream &Out) { + raw_ostream &Out) { CXXNameMangler Mangler(*this, Out, D, Type); Mangler.mangle(D); } void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> @@ -3256,7 +3264,7 @@ void ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &ThisAdjustment, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk CXXNameMangler Mangler(*this, Out, DD, Type); @@ -3272,7 +3280,7 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, /// mangleGuardVariable - Returns the mangled name for a guard variable /// for the passed in VarDecl. void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= GV <object name> # Guard variable for one-time // # initialization CXXNameMangler Mangler(*this, Out); @@ -3281,7 +3289,7 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, } void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // We match the GCC mangling here. // <special-name> ::= GR <object name> CXXNameMangler Mangler(*this, Out); @@ -3290,7 +3298,7 @@ void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, } void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= TV <type> # virtual table CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTV"; @@ -3298,7 +3306,7 @@ void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, } void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= TT <type> # VTT structure CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTT"; @@ -3308,7 +3316,7 @@ void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= TC <type> <offset number> _ <base type> CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTC"; @@ -3319,7 +3327,7 @@ void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, } void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= TI <type> # typeinfo structure assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); CXXNameMangler Mangler(*this, Out); @@ -3328,7 +3336,7 @@ void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, } void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, - llvm::raw_ostream &Out) { + raw_ostream &Out) { // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTS"; @@ -3336,6 +3344,6 @@ void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, } MangleContext *clang::createItaniumMangleContext(ASTContext &Context, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { return new ItaniumMangleContext(Context, Diags); } diff --git a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp index c3f3b11..5cb8f47 100644 --- a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp @@ -37,9 +37,9 @@ using namespace clang; namespace { static void mangleFunctionBlock(MangleContext &Context, - llvm::StringRef Outer, + StringRef Outer, const BlockDecl *BD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true); } @@ -60,13 +60,13 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) { } void MangleContext::mangleGlobalBlock(const BlockDecl *BD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { Out << "__block_global_" << getBlockId(BD, false); } void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT, const BlockDecl *BD, - llvm::raw_ostream &ResStream) { + raw_ostream &ResStream) { checkMangleDC(CD, BD); llvm::SmallString<64> Buffer; llvm::raw_svector_ostream Out(Buffer); @@ -77,7 +77,7 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, CXXDtorType DT, const BlockDecl *BD, - llvm::raw_ostream &ResStream) { + raw_ostream &ResStream) { checkMangleDC(DD, BD); llvm::SmallString<64> Buffer; llvm::raw_svector_ostream Out(Buffer); @@ -87,7 +87,7 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, } void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC)); checkMangleDC(DC, BD); @@ -113,7 +113,7 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, } void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { llvm::SmallString<64> Name; llvm::raw_svector_ostream OS(Name); @@ -129,7 +129,7 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, } void MangleContext::mangleBlock(const BlockDecl *BD, - llvm::raw_ostream &Out) { + raw_ostream &Out) { const DeclContext *DC = BD->getDeclContext(); while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) DC = DC->getParent(); diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp index 206f6dd..f33d6fe 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp @@ -30,7 +30,7 @@ public: unsigned getMemberPointerSize(const MemberPointerType *MPT) const; CallingConv getDefaultMethodCallConv() const { - if (Context.Target.getTriple().getArch() == llvm::Triple::x86) + if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) return CC_X86ThisCall; else return CC_C; @@ -45,7 +45,7 @@ public: // In the Microsoft ABI, classes can have one or two vtable pointers. CharUnits PointerSize = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; } diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp index 4f920f9..1515db4 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp @@ -29,15 +29,15 @@ namespace { /// Microsoft Visual C++ ABI. class MicrosoftCXXNameMangler { MangleContext &Context; - llvm::raw_ostream &Out; + raw_ostream &Out; ASTContext &getASTContext() const { return Context.getASTContext(); } public: - MicrosoftCXXNameMangler(MangleContext &C, llvm::raw_ostream &Out_) + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_) { } - void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?"); + void mangle(const NamedDecl *D, StringRef Prefix = "?"); void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); @@ -78,30 +78,30 @@ private: class MicrosoftMangleContext : public MangleContext { public: MicrosoftMangleContext(ASTContext &Context, - Diagnostic &Diags) : MangleContext(Context, Diags) { } + DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { } virtual bool shouldMangleDeclName(const NamedDecl *D); - virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &Out); + virtual void mangleName(const NamedDecl *D, raw_ostream &Out); virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &ThisAdjustment, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleCXXVTable(const CXXRecordDecl *RD, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleCXXVTT(const CXXRecordDecl *RD, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &); - virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &); - virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + raw_ostream &); + virtual void mangleCXXRTTI(QualType T, raw_ostream &); + virtual void mangleCXXRTTIName(QualType T, raw_ostream &); virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::raw_ostream &); + raw_ostream &); virtual void mangleReferenceTemporary(const clang::VarDecl *, - llvm::raw_ostream &); + raw_ostream &); }; } @@ -154,7 +154,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { } void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, - llvm::StringRef Prefix) { + StringRef Prefix) { // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. // Therefore it's really important that we don't decorate the // name with leading underscores or leading/trailing at signs. So, emit a @@ -332,16 +332,13 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - assert(false && "Can't mangle Objective-C selector names here!"); - break; + llvm_unreachable("Can't mangle Objective-C selector names here!"); case DeclarationName::CXXConstructorName: - assert(false && "Can't mangle constructors yet!"); - break; + llvm_unreachable("Can't mangle constructors yet!"); case DeclarationName::CXXDestructorName: - assert(false && "Can't mangle destructors yet!"); - break; + llvm_unreachable("Can't mangle destructors yet!"); case DeclarationName::CXXConversionFunctionName: // <operator-name> ::= ?B # (cast) @@ -355,12 +352,10 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::CXXLiteralOperatorName: // FIXME: Was this added in VS2010? Does MS even know how to mangle this? - assert(false && "Don't know how to mangle literal operators yet!"); - break; + llvm_unreachable("Don't know how to mangle literal operators yet!"); case DeclarationName::CXXUsingDirective: - assert(false && "Can't mangle a using directive name!"); - break; + llvm_unreachable("Can't mangle a using directive name!"); } } @@ -513,13 +508,11 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO) { case OO_Array_Delete: Out << "?_V"; break; case OO_Conditional: - assert(false && "Don't know how to mangle ?:"); - break; + llvm_unreachable("Don't know how to mangle ?:"); case OO_None: case NUM_OVERLOADED_OPERATORS: - assert(false && "Not an overloaded operator"); - break; + llvm_unreachable("Not an overloaded operator"); } } @@ -712,18 +705,17 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Dependent: case BuiltinType::UnknownAny: case BuiltinType::BoundMember: - assert(false && + llvm_unreachable( "Overloaded and dependent types shouldn't get to name mangling"); - break; case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break; case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break; case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break; case BuiltinType::Char16: case BuiltinType::Char32: + case BuiltinType::Half: case BuiltinType::NullPtr: - assert(false && "Don't know how to mangle this type"); - break; + llvm_unreachable("Don't know how to mangle this type"); } } @@ -869,7 +861,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C; switch (CC) { default: - assert(0 && "Unsupported CC for mangling"); + llvm_unreachable("Unsupported CC for mangling"); case CC_Default: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; @@ -890,7 +882,7 @@ void MicrosoftCXXNameMangler::mangleThrowSpecification( } void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T) { - assert(false && "Don't know how to mangle UnresolvedUsingTypes yet!"); + llvm_unreachable("Don't know how to mangle UnresolvedUsingTypes yet!"); } // <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type> @@ -954,7 +946,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T) { mangleType(static_cast<const ArrayType *>(T), false); } void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { - llvm::SmallVector<llvm::APInt, 3> Dimensions; + SmallVector<llvm::APInt, 3> Dimensions; for (;;) { if (ElementTy->isConstantArrayType()) { const ConstantArrayType *CAT = @@ -962,10 +954,10 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { Dimensions.push_back(CAT->getSize()); ElementTy = CAT->getElementType(); } else if (ElementTy->isVariableArrayType()) { - assert(false && "Don't know how to mangle VLAs!"); + llvm_unreachable("Don't know how to mangle VLAs!"); } else if (ElementTy->isDependentSizedArrayType()) { // The dependent expression has to be folded into a constant (TODO). - assert(false && "Don't know how to mangle dependent-sized arrays!"); + llvm_unreachable("Don't know how to mangle dependent-sized arrays!"); } else if (ElementTy->isIncompleteArrayType()) continue; else break; } @@ -999,12 +991,12 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) { } void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) { - assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!"); + llvm_unreachable("Don't know how to mangle TemplateTypeParmTypes yet!"); } void MicrosoftCXXNameMangler::mangleType( const SubstTemplateTypeParmPackType *T) { - assert(false && + llvm_unreachable( "Don't know how to mangle SubstTemplateTypeParmPackTypes yet!"); } @@ -1045,21 +1037,22 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) { } void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T) { - assert(false && "Don't know how to mangle RValueReferenceTypes yet!"); + llvm_unreachable("Don't know how to mangle RValueReferenceTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T) { - assert(false && "Don't know how to mangle ComplexTypes yet!"); + llvm_unreachable("Don't know how to mangle ComplexTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const VectorType *T) { - assert(false && "Don't know how to mangle VectorTypes yet!"); + llvm_unreachable("Don't know how to mangle VectorTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T) { - assert(false && "Don't know how to mangle ExtVectorTypes yet!"); + llvm_unreachable("Don't know how to mangle ExtVectorTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { - assert(false && "Don't know how to mangle DependentSizedExtVectorTypes yet!"); + llvm_unreachable( + "Don't know how to mangle DependentSizedExtVectorTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T) { @@ -1080,49 +1073,53 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T) { } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T) { - assert(false && "Don't know how to mangle InjectedClassNameTypes yet!"); + llvm_unreachable("Don't know how to mangle InjectedClassNameTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T) { - assert(false && "Don't know how to mangle TemplateSpecializationTypes yet!"); + llvm_unreachable("Don't know how to mangle TemplateSpecializationTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T) { - assert(false && "Don't know how to mangle DependentNameTypes yet!"); + llvm_unreachable("Don't know how to mangle DependentNameTypes yet!"); } void MicrosoftCXXNameMangler::mangleType( const DependentTemplateSpecializationType *T) { - assert(false && + llvm_unreachable( "Don't know how to mangle DependentTemplateSpecializationTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) { - assert(false && "Don't know how to mangle PackExpansionTypes yet!"); + llvm_unreachable("Don't know how to mangle PackExpansionTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) { - assert(false && "Don't know how to mangle TypeOfTypes yet!"); + llvm_unreachable("Don't know how to mangle TypeOfTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T) { - assert(false && "Don't know how to mangle TypeOfExprTypes yet!"); + llvm_unreachable("Don't know how to mangle TypeOfExprTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) { - assert(false && "Don't know how to mangle DecltypeTypes yet!"); + llvm_unreachable("Don't know how to mangle DecltypeTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) { - assert(false && "Don't know how to mangle UnaryTransformationTypes yet!"); + llvm_unreachable("Don't know how to mangle UnaryTransformationTypes yet!"); } void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { - assert(false && "Don't know how to mangle AutoTypes yet!"); + llvm_unreachable("Don't know how to mangle AutoTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const AtomicType *T) { + llvm_unreachable("Don't know how to mangle AtomicTypes yet!"); } void MicrosoftMangleContext::mangleName(const NamedDecl *D, - llvm::raw_ostream &Out) { + raw_ostream &Out) { assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && "Invalid mangleName() call, argument is not a variable or function!"); assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && @@ -1137,53 +1134,53 @@ void MicrosoftMangleContext::mangleName(const NamedDecl *D, } void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle thunks!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle thunks!"); } void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle destructor thunks!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle destructor thunks!"); } void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle virtual tables!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle virtual tables!"); } void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, - llvm::raw_ostream &) { + raw_ostream &) { llvm_unreachable("The MS C++ ABI does not have virtual table tables!"); } void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &) { + raw_ostream &) { llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); } void MicrosoftMangleContext::mangleCXXRTTI(QualType T, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle RTTI!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle RTTI!"); } void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle RTTI names!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle RTTI names!"); } void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle constructors!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle constructors!"); } void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle destructors!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle destructors!"); } void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *, - llvm::raw_ostream &) { - assert(false && "Can't yet mangle reference temporaries!"); + raw_ostream &) { + llvm_unreachable("Can't yet mangle reference temporaries!"); } MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { return new MicrosoftMangleContext(Context, Diags); } diff --git a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp index f6d4f25..1ff2e71 100644 --- a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp +++ b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp @@ -218,7 +218,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const { /// \brief Print this nested name specifier to the given output /// stream. void -NestedNameSpecifier::print(llvm::raw_ostream &OS, +NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy) const { if (getPrefix()) getPrefix()->print(OS, Policy); @@ -569,7 +569,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, // Construct bogus (but well-formed) source information for the // nested-name-specifier. BufferSize = 0; - llvm::SmallVector<NestedNameSpecifier *, 4> Stack; + SmallVector<NestedNameSpecifier *, 4> Stack; for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) Stack.push_back(NNS); while (!Stack.empty()) { diff --git a/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp b/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp index b7b2005..5eef83a 100644 --- a/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp @@ -66,6 +66,14 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const { return S; } +Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const { + do { + S = getParent(S); + } while (S && isa<Expr>(S) && cast<Expr>(S)->IgnoreParenImpCasts() != S); + + return S; +} + Stmt *ParentMap::getOuterParenParent(Stmt *S) const { Stmt *Paren = 0; while (isa<ParenExpr>(S)) { diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp index 035c48f..ccc591a 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" using namespace clang; @@ -42,7 +43,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, // Constructor for C++ records. ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, - CharUnits datasize, + CharUnits vbptroffset, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, CharUnits nonvirtualsize, @@ -67,15 +68,20 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; CXXInfo->BaseOffsets = BaseOffsets; CXXInfo->VBaseOffsets = VBaseOffsets; + CXXInfo->VBPtrOffset = vbptroffset; #ifndef NDEBUG if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { - if (isPrimaryBaseVirtual()) + if (isPrimaryBaseVirtual()) { + // Microsoft ABI doesn't have primary virtual base + if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) { assert(getVBaseClassOffset(PrimaryBase).isZero() && "Primary virtual base must be at offset 0!"); - else + } + } else { assert(getBaseClassOffsetInBits(PrimaryBase) == 0 && "Primary base must be at offset 0!"); + } } #endif } diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp index 5636a6f..bbd3fc0 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp @@ -44,7 +44,7 @@ struct BaseSubobjectInfo { bool IsVirtual; /// Bases - Information about the base subobjects. - llvm::SmallVector<BaseSubobjectInfo*, 4> Bases; + SmallVector<BaseSubobjectInfo*, 4> Bases; /// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base /// of this base info (if one exists). @@ -64,7 +64,7 @@ class EmptySubobjectMap { const CXXRecordDecl *Class; /// EmptyClassOffsets - A map from offsets to empty record decls. - typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; + typedef SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy; EmptyClassOffsetsMapTy EmptyClassOffsets; @@ -556,7 +556,7 @@ protected: /// \brief The alignment if attribute packed is not used. CharUnits UnpackedAlignment; - llvm::SmallVector<uint64_t, 16> FieldOffsets; + SmallVector<uint64_t, 16> FieldOffsets; /// Packed - Whether the record is packed or not. unsigned Packed : 1; @@ -592,6 +592,9 @@ protected: /// out is virtual. bool PrimaryBaseIsVirtual; + /// VBPtrOffset - Virtual base table offset. Only for MS layout. + CharUnits VBPtrOffset; + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// Bases - base classes and their offsets in the record. @@ -613,16 +616,17 @@ protected: llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap - *EmptySubobjects) + *EmptySubobjects, CharUnits Alignment) : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), - Alignment(CharUnits::One()), UnpackedAlignment(Alignment), + Alignment(Alignment), UnpackedAlignment(Alignment), Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), ZeroLengthBitfield(0), PrimaryBase(0), - PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } + PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)), + FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); void Layout(const CXXRecordDecl *D); @@ -633,6 +637,8 @@ protected: void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize, bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); + void MSLayoutVirtualBases(const CXXRecordDecl *RD); + void MSLayout(const CXXRecordDecl *RD); /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; @@ -663,7 +669,7 @@ protected: void SelectPrimaryVBase(const CXXRecordDecl *RD); - virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; + CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -713,6 +719,8 @@ protected: void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); } void setSize(uint64_t NewSize) { Size = NewSize; } + CharUnits getAligment() const { return Alignment; } + CharUnits getDataSize() const { assert(DataSize % Context.getCharWidth() == 0); return Context.toCharUnitsFromBits(DataSize); @@ -722,6 +730,11 @@ protected: void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } void setDataSize(uint64_t NewSize) { DataSize = NewSize; } + bool HasVBPtr(const CXXRecordDecl *RD) const; + bool HasNewVirtualFunction(const CXXRecordDecl *RD) const; + + /// Add vbptr or vfptr to layout. + void AddVPointer(); RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT @@ -729,6 +742,8 @@ public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); virtual ~RecordLayoutBuilder() { } + + CharUnits GetVBPtrOffset() const { return VBPtrOffset; } }; } // end anonymous namespace @@ -765,7 +780,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { CharUnits RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { - return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); } /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -825,7 +840,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { setDataSize(getSize()); CharUnits UnpackedBaseAlign = - Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; // The maximum field alignment overrides base align. @@ -1046,6 +1061,45 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, } } +void RecordLayoutBuilder::AddVPointer() { + CharUnits PtrWidth = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + setSize(getSize() + PtrWidth); + setDataSize(getSize()); + + if (Alignment > PtrWidth) { + setSize(getSize() + (Alignment - PtrWidth)); + setDataSize(getSize()); + } +} + +bool +RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const { + for (CXXRecordDecl::method_iterator method = RD->method_begin(); + method != RD->method_end(); + ++method) { + if (method->isVirtual() && + !method->size_overridden_methods()) { + return true; + } + } + return false; +} + +bool +RecordLayoutBuilder::HasVBPtr(const CXXRecordDecl *RD) const { + if (!RD->getNumBases()) + return false; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (!I->isVirtual()) { + return false; + } + } + return true; +} + void RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) { @@ -1157,6 +1211,11 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { IsMsStruct = D->hasAttr<MsStructAttr>(); + // Honor the default struct packing maximum alignment flag. + if (unsigned DefaultMaxFieldAlignment = Context.getLangOptions().PackStruct) { + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); + } + // mac68k alignment supersedes maximum field alignment and attribute aligned, // and forces all structures to have 2-byte alignment. The IBM docs on it // allude to additional (more complicated) semantics, especially with regard @@ -1184,6 +1243,11 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) { } void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { + if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) { + MSLayout(RD); + return ; + } + InitializeLayout(RD); // Lay out the vtable and the non-virtual bases. @@ -1193,7 +1257,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { NonVirtualSize = Context.toCharUnitsFromBits( llvm::RoundUpToAlignment(getSizeInBits(), - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); NonVirtualAlignment = Alignment; // Lay out the virtual bases and add the primary virtual base offsets. @@ -1242,10 +1306,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { } InitializeLayout(D); - ObjCInterfaceDecl *OI = const_cast<ObjCInterfaceDecl*>(D); // Layout each ivar sequentially. - for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) + for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) LayoutField(IVD); // Finally, round the size of the total struct up to the alignment of the @@ -1271,8 +1334,8 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { continue; // FIXME. streamline these conditions into a simple one. else if (Context.BitfieldFollowsBitfield(FD, LastFD) || - Context.BitfieldFollowsNoneBitfield(FD, LastFD) || - Context.NoneBitfieldFollowsBitfield(FD, LastFD)) { + Context.BitfieldFollowsNonBitfield(FD, LastFD) || + Context.NonBitfieldFollowsBitfield(FD, LastFD)) { // 1) Adjacent bit fields are packed into the same 1-, 2-, or // 4-byte allocation unit if the integral types are the same // size and if the next bit field fits into the current @@ -1299,14 +1362,14 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { if (TypeSizeLastFD != TypeSize) { if (RemainingInAlignment && LastFD && LastFD->isBitField() && - LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + LastFD->getBitWidthValue(Context)) { // If previous field was a bitfield with some remaining unfilled // bits, pad the field so current field starts on its type boundary. uint64_t FieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); setSize(std::max(getSizeInBits(), getDataSizeInBits())); RemainingInAlignment = 0; } @@ -1325,13 +1388,12 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { uint64_t NewSizeInBits = llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign); setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; setSize(std::max(getSizeInBits(), getDataSizeInBits())); } if (FD->isBitField()) { - uint64_t FieldSize = - FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = FD->getBitWidthValue(Context); assert (FieldSize > 0 && "LayoutFields - ms_struct layout"); if (RemainingInAlignment < FieldSize) RemainingInAlignment = TypeSize - FieldSize; @@ -1340,8 +1402,7 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } } else if (FD->isBitField()) { - uint64_t FieldSize = - FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = FD->getBitWidthValue(Context); std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(FD->getType()); uint64_t TypeSize = FieldInfo.first; @@ -1349,18 +1410,23 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } LastFD = FD; } + else if (!Context.getTargetInfo().useBitFieldTypeAlignment() && + Context.getTargetInfo().useZeroLengthBitfieldAlignment()) { + FieldDecl *FD = (*Field); + if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + ZeroLengthBitfield = FD; + } LayoutField(*Field); } if (IsMsStruct && RemainingInAlignment && - LastFD && LastFD->isBitField() && - LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) { // If we ended a bitfield before the full length of the type then // pad the struct out to the full length of the last type. uint64_t FieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); setSize(std::max(getSizeInBits(), getDataSizeInBits())); } } @@ -1405,15 +1471,15 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, setDataSize(std::max(getDataSizeInBits(), FieldSize)); FieldOffset = 0; } else { - // The bitfield is allocated starting at the next offset aligned appropriately - // for T', with length n bits. + // The bitfield is allocated starting at the next offset aligned + // appropriately for T', with length n bits. FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(TypeAlign)); uint64_t NewSizeInBits = FieldOffset + FieldSize; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1434,7 +1500,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; - uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = D->getBitWidthValue(Context); std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; @@ -1443,21 +1509,32 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // This check is needed for 'long long' in -m32 mode. if (IsMsStruct && (TypeSize > FieldAlign)) FieldAlign = TypeSize; - + if (ZeroLengthBitfield) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - if (ZeroLengthBitfield != D) { - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(ZeroLengthBitfield->getType()); - unsigned ZeroLengthBitfieldAlignment = FieldInfo.second; - // Ignore alignment of subsequent zero-length bitfields. - if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) - FieldAlign = ZeroLengthBitfieldAlignment; - if (FieldSize) - ZeroLengthBitfield = 0; + std::pair<uint64_t, unsigned> FieldInfo; + unsigned ZeroLengthBitfieldAlignment; + if (IsMsStruct) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + if (ZeroLengthBitfield != D) { + FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType()); + ZeroLengthBitfieldAlignment = FieldInfo.second; + // Ignore alignment of subsequent zero-length bitfields. + if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) + FieldAlign = ZeroLengthBitfieldAlignment; + if (FieldSize) + ZeroLengthBitfield = 0; + } + } else { + // The alignment of a zero-length bitfield affects the alignment + // of the next member. The alignment is the max of the zero + // length bitfield's alignment and a target specific fixed value. + unsigned ZeroLengthBitfieldBoundary = + Context.getTargetInfo().getZeroLengthBitfieldBoundary(); + if (ZeroLengthBitfieldBoundary > FieldAlign) + FieldAlign = ZeroLengthBitfieldBoundary; } } @@ -1470,10 +1547,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // was unnecessary (-Wpacked). unsigned UnpackedFieldAlign = FieldAlign; uint64_t UnpackedFieldOffset = FieldOffset; - if (!Context.Target.useBitFieldTypeAlignment()) + if (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield) UnpackedFieldAlign = 1; - if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) + if (FieldPacked || + (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield)) FieldAlign = 1; FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment()); @@ -1494,10 +1572,14 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, UnpackedFieldAlign); - // Padding members don't affect overall alignment. - if (!D->getIdentifier()) + // Padding members don't affect overall alignment, unless zero length bitfield + // alignment is enabled. + if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment()) FieldAlign = UnpackedFieldAlign = 1; + if (!IsMsStruct) + ZeroLengthBitfield = 0; + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); @@ -1512,7 +1594,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { uint64_t NewSizeInBits = FieldOffset + FieldSize; setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1552,25 +1634,36 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { unsigned AS = RT->getPointeeType().getAddressSpace(); FieldSize = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS)); FieldAlign = - Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS)); } else { std::pair<CharUnits, CharUnits> FieldInfo = Context.getTypeInfoInChars(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; - + if (ZeroLengthBitfield) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - std::pair<CharUnits, CharUnits> FieldInfo = - Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); - CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; - if (ZeroLengthBitfieldAlignment > FieldAlign) - FieldAlign = ZeroLengthBitfieldAlignment; + CharUnits ZeroLengthBitfieldBoundary = + Context.toCharUnitsFromBits( + Context.getTargetInfo().getZeroLengthBitfieldBoundary()); + if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); + CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; + if (ZeroLengthBitfieldAlignment > FieldAlign) + FieldAlign = ZeroLengthBitfieldAlignment; + } else if (ZeroLengthBitfieldBoundary > FieldAlign) { + // Align 'bar' based on a fixed alignment specified by the target. + assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() && + "ZeroLengthBitfieldBoundary should only be used in conjunction" + " with useZeroLengthBitfieldAlignment."); + FieldAlign = ZeroLengthBitfieldBoundary; + } ZeroLengthBitfield = 0; } @@ -1641,6 +1734,104 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { UpdateAlignment(FieldAlign, UnpackedFieldAlign); } +void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) { + + if (!RD->getNumVBases()) + return; + + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + + const CXXRecordDecl* BaseDecl = I->getType()->getAsCXXRecordDecl(); + const BaseSubobjectInfo* BaseInfo = VirtualBaseInfo.lookup(BaseDecl); + + assert(BaseInfo && "Did not find virtual base info!"); + + LayoutVirtualBase(BaseInfo); + } +} + +void RecordLayoutBuilder::MSLayout(const CXXRecordDecl *RD) { + + bool IsVBPtrAddedToLayout = false; + + InitializeLayout(RD); + + if (HasVBPtr(RD)) { + // If all bases are virtual and the class declares a new virtual function, + // MSVC builds a vfptr. + if (HasNewVirtualFunction(RD)) { + AddVPointer(); + } + + VBPtrOffset = getSize(); + AddVPointer(); + IsVBPtrAddedToLayout = true; + + ComputeBaseSubobjectInfo(RD); + } else { + LayoutNonVirtualBases(RD); + } + + if (RD->getNumVBases() && + !IsVBPtrAddedToLayout) { + // Add vbptr. + VBPtrOffset = getSize(); + AddVPointer(); + } + + LayoutFields(RD); + + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.getTargetInfo().getCharAlign())); + NonVirtualAlignment = Alignment; + + if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) { + CharUnits AlignMember = + NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize; + + setSize(getSize() + AlignMember); + setDataSize(getSize()); + + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.getTargetInfo().getCharAlign())); + } + + MSLayoutVirtualBases(RD); + + VisitedVirtualBases.clear(); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + if (!RD->getNumVBases()) + FinishLayout(RD); + +#ifndef NDEBUG + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } +#endif +} + void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // In C++, records cannot be of size 0. if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) { @@ -1663,7 +1854,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); - unsigned CharBitNum = Context.Target.getCharWidth(); + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { // Warn if padding was introduced to the struct/class/union. if (getSizeInBits() > UnpaddedSize) { @@ -1718,7 +1909,12 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, if (isa<ObjCIvarDecl>(D)) return; - unsigned CharBitNum = Context.Target.getCharWidth(); + // Don't warn about structs created without a SourceLocation. This can + // be done by clients of the AST, such as codegen. + if (D->getLocation().isInvalid()) + return; + + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); // Warn if padding was introduced to the struct/class. if (!IsUnion && Offset > UnpaddedOffset) { @@ -1802,36 +1998,18 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { return Context.getDiagnostics().Report(Loc, DiagID); } -namespace { - // This class implements layout specific to the Microsoft ABI. - class MSRecordLayoutBuilder : public RecordLayoutBuilder { - public: - MSRecordLayoutBuilder(const ASTContext& Ctx, - EmptySubobjectMap *EmptySubobjects) : - RecordLayoutBuilder(Ctx, EmptySubobjects) {} - - virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; - }; -} - -CharUnits -MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { - // We should reserve space for two pointers if the class has both - // virtual functions and virtual bases. - CharUnits PointerWidth = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); - if (RD->isPolymorphic() && RD->getNumVBases() > 0) - return 2 * PointerWidth; - return PointerWidth; -} - /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout & ASTContext::getASTRecordLayout(const RecordDecl *D) const { + // These asserts test different things. A record has a definition + // as soon as we begin to parse the definition. That definition is + // not a complete definition (which is what isDefinition() tests) + // until we *finish* parsing the definition. D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); + assert(D->isCompleteDefinition() && "Cannot layout type before complete!"); // Look up this layout, if already laid out, return what we have. // Note that we can't save a reference to the entry because this function @@ -1844,25 +2022,44 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); - // When compiling for Microsoft, use the special MS builder. llvm::OwningPtr<RecordLayoutBuilder> Builder; - switch (Target.getCXXABI()) { - default: - Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects)); - break; - case CXXABI_Microsoft: - Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); - } + CharUnits TargetAlign = CharUnits::One(); + + Builder.reset(new RecordLayoutBuilder(*this, + &EmptySubobjects, + TargetAlign)); + // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> RecordBuilderCleanup(Builder.get()); Builder->Layout(RD); + TargetAlign = Builder->getAligment(); + + if (getTargetInfo().getCXXABI() == CXXABI_Microsoft && + TargetAlign.getQuantity() > 4) { + // MSVC rounds the vtable pointer to the struct alignment in what must + // be a multi-pass operation. For now, let the builder figure out the + // alignment and recalculate the layout once its known. + Builder.reset(new RecordLayoutBuilder(*this, + &EmptySubobjects, + TargetAlign)); + + Builder->Layout(RD); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> + RecordBuilderCleanup(Builder.get()); + } + // FIXME: This is not always correct. See the part about bitfields at // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. - bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); + // This does not affect the calculations of MSVC layouts + bool IsPODForThePurposeOfLayout = + (getTargetInfo().getCXXABI() == CXXABI_Microsoft) || + cast<CXXRecordDecl>(D)->isPOD(); // FIXME: This should be done in FinalizeLayout. CharUnits DataSize = @@ -1873,6 +2070,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { NewEntry = new (*this) ASTRecordLayout(*this, Builder->getSize(), Builder->Alignment, + Builder->GetVBPtrOffset(), DataSize, Builder->FieldOffsets.data(), Builder->FieldOffsets.size(), @@ -1883,7 +2081,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder->PrimaryBaseIsVirtual, Builder->Bases, Builder->VBases); } else { - RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One()); Builder.Layout(D); NewEntry = @@ -1915,8 +2113,8 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { return Entry; } -/// getInterfaceLayoutImpl - Get or compute information about the -/// layout of the given interface. +/// getObjCLayout - Get or compute information about the layout of the +/// given interface. /// /// \param Impl - If given, also include the layout of the interface's /// implementation. This may differ by including synthesized ivars. @@ -1942,7 +2140,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return getObjCLayout(D, 0); } - RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One()); Builder.Layout(D); const ASTRecordLayout *NewEntry = @@ -1957,13 +2155,13 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return *NewEntry; } -static void PrintOffset(llvm::raw_ostream &OS, +static void PrintOffset(raw_ostream &OS, CharUnits Offset, unsigned IndentLevel) { OS << llvm::format("%4d | ", Offset.getQuantity()); OS.indent(IndentLevel * 2); } -static void DumpCXXRecordLayout(llvm::raw_ostream &OS, +static void DumpCXXRecordLayout(raw_ostream &OS, const CXXRecordDecl *RD, const ASTContext &C, CharUnits Offset, unsigned IndentLevel, @@ -1982,12 +2180,22 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, IndentLevel++; const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1); // Vtable pointer. if (RD->isDynamicClass() && !PrimaryBase) { PrintOffset(OS, Offset, IndentLevel); - OS << '(' << RD << " vtable pointer)\n"; + OS << '(' << *RD << " vtable pointer)\n"; + } + + if (HasVbptr && !PrimaryBase) { + PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); + OS << '(' << *RD << " vbtable pointer)\n"; + + // one vbtable per class + HasVbptr = false; } + // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { @@ -2005,6 +2213,11 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, Base == PrimaryBase ? "(primary base)" : "(base)", /*IncludeVirtualBases=*/false); } + // vbptr + if (HasVbptr) { + PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); + OS << '(' << *RD << " vbtable pointer)\n"; + } // Dump fields. uint64_t FieldNo = 0; @@ -2024,7 +2237,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, } PrintOffset(OS, FieldOffset, IndentLevel); - OS << Field->getType().getAsString() << ' ' << Field << '\n'; + OS << Field->getType().getAsString() << ' ' << *Field << '\n'; } if (!IncludeVirtualBases) @@ -2053,7 +2266,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, } void ASTContext::DumpRecordLayout(const RecordDecl *RD, - llvm::raw_ostream &OS) const { + raw_ostream &OS) const { const ASTRecordLayout &Info = getASTRecordLayout(RD); if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) diff --git a/contrib/llvm/tools/clang/lib/AST/SelectorLocationsKind.cpp b/contrib/llvm/tools/clang/lib/AST/SelectorLocationsKind.cpp new file mode 100644 index 0000000..671207a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/SelectorLocationsKind.cpp @@ -0,0 +1,128 @@ +//===--- SelectorLocationsKind.cpp - Kind of selector locations -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Describes whether the identifier locations for a selector are "standard" +// or not. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/SelectorLocationsKind.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +static SourceLocation getStandardSelLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + SourceLocation ArgLoc, + SourceLocation EndLoc) { + unsigned NumSelArgs = Sel.getNumArgs(); + if (NumSelArgs == 0) { + assert(Index == 0); + if (EndLoc.isInvalid()) + return SourceLocation(); + IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0); + unsigned Len = II ? II->getLength() : 0; + return EndLoc.getLocWithOffset(-Len); + } + + assert(Index < NumSelArgs); + if (ArgLoc.isInvalid()) + return SourceLocation(); + IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index); + unsigned Len = /* selector id */ (II ? II->getLength() : 0) + /* ':' */ 1; + if (WithArgSpace) + ++Len; + return ArgLoc.getLocWithOffset(-Len); +} + +namespace { + +template <typename T> +SourceLocation getArgLoc(T* Arg); + +template <> +SourceLocation getArgLoc<Expr>(Expr *Arg) { + return Arg->getLocStart(); +} + +template <> +SourceLocation getArgLoc<ParmVarDecl>(ParmVarDecl *Arg) { + SourceLocation Loc = Arg->getLocStart(); + if (Loc.isInvalid()) + return Loc; + // -1 to point to left paren of the method parameter's type. + return Loc.getLocWithOffset(-1); +} + +template <typename T> +SourceLocation getArgLoc(unsigned Index, ArrayRef<T*> Args) { + return Index < Args.size() ? getArgLoc(Args[Index]) : SourceLocation(); +} + +template <typename T> +SelectorLocationsKind hasStandardSelLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<T *> Args, + SourceLocation EndLoc) { + // Are selector locations in standard position with no space between args ? + unsigned i; + for (i = 0; i != SelLocs.size(); ++i) { + if (SelLocs[i] != getStandardSelectorLoc(i, Sel, /*WithArgSpace=*/false, + Args, EndLoc)) + break; + } + if (i == SelLocs.size()) + return SelLoc_StandardNoSpace; + + // Are selector locations in standard position with space between args ? + for (i = 0; i != SelLocs.size(); ++i) { + if (SelLocs[i] != getStandardSelectorLoc(i, Sel, /*WithArgSpace=*/true, + Args, EndLoc)) + return SelLoc_NonStandard; + } + + return SelLoc_StandardWithSpace; +} + +} // anonymous namespace + +SelectorLocationsKind +clang::hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<Expr *> Args, + SourceLocation EndLoc) { + return hasStandardSelLocs(Sel, SelLocs, Args, EndLoc); +} + +SourceLocation clang::getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<Expr *> Args, + SourceLocation EndLoc) { + return getStandardSelLoc(Index, Sel, WithArgSpace, + getArgLoc(Index, Args), EndLoc); +} + +SelectorLocationsKind +clang::hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc) { + return hasStandardSelLocs(Sel, SelLocs, Args, EndLoc); +} + +SourceLocation clang::getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc) { + return getStandardSelLoc(Index, Sel, WithArgSpace, + getArgLoc(Index, Args), EndLoc); +} diff --git a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp index fd6f21d..e7b87e4 100644 --- a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp @@ -97,6 +97,22 @@ Stmt *Stmt::IgnoreImplicit() { return s; } +/// \brief Strip off all label-like statements. +/// +/// This will strip off label statements, case statements, and default +/// statements recursively. +const Stmt *Stmt::stripLabelLikeStatements() const { + const Stmt *S = this; + while (true) { + if (const LabelStmt *LS = dyn_cast<LabelStmt>(S)) + S = LS->getSubStmt(); + else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) + S = SC->getSubStmt(); + else + return S; + } +} + namespace { struct good {}; struct bad {}; @@ -214,7 +230,7 @@ Expr *AsmStmt::getOutputExpr(unsigned i) { /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). -llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const { +StringRef AsmStmt::getOutputConstraint(unsigned i) const { return getOutputConstraintLiteral(i)->getString(); } @@ -238,7 +254,7 @@ void AsmStmt::setInputExpr(unsigned i, Expr *E) { /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. -llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const { +StringRef AsmStmt::getInputConstraint(unsigned i) const { return getInputConstraintLiteral(i)->getString(); } @@ -277,7 +293,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. -int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { +int AsmStmt::getNamedOperand(StringRef SymbolicName) const { unsigned NumPlusOperands = 0; // Check if this is an output operand. @@ -297,9 +313,9 @@ int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. -unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, +unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, ASTContext &C, unsigned &DiagOffs) const { - llvm::StringRef Str = getAsmString()->getString(); + StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); const char *CurPtr = StrStart; @@ -326,7 +342,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, // asm string. std::string CurStringPiece; - bool HasVariants = !C.Target.hasNoAsmVariants(); + bool HasVariants = !C.getTargetInfo().hasNoAsmVariants(); while (1) { // Done with the string? @@ -416,7 +432,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; - llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); + StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { diff --git a/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp index fb024f3..2968739 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp @@ -27,7 +27,7 @@ using namespace clang; namespace { class StmtDumper : public StmtVisitor<StmtDumper> { SourceManager *SM; - llvm::raw_ostream &OS; + raw_ostream &OS; unsigned IndentLevel; /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump @@ -41,7 +41,7 @@ namespace { unsigned LastLocLine; public: - StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth) + StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth) : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) { LastLocFilename = ""; LastLocLine = ~0U; @@ -235,9 +235,9 @@ void StmtDumper::DumpDeclarator(Decl *D) { // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { OS << "\"typedef " << localType->getUnderlyingType().getAsString() - << ' ' << localType << '"'; + << ' ' << *localType << '"'; } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) { - OS << "\"using " << localType << " = " + OS << "\"using " << *localType << " = " << localType->getUnderlyingType().getAsString() << '"'; } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { OS << "\""; @@ -294,7 +294,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { DumpSubTree(SAD->getMessage()); OS << ");\""; } else { - assert(0 && "Unexpected decl"); + llvm_unreachable("Unexpected decl"); } } @@ -333,7 +333,7 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } -static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { +static void DumpBasePath(raw_ostream &OS, CastExpr *Node) { if (Node->path_empty()) return; @@ -407,7 +407,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); OS << " " << Node->getDecl()->getDeclKindName() - << "Decl='" << Node->getDecl() + << "Decl='" << *Node->getDecl() << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) OS << " isFreeIvar"; @@ -416,7 +416,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { - default: assert(0 && "unknown case"); + default: llvm_unreachable("unknown case"); case PredefinedExpr::Func: OS << " __func__"; break; case PredefinedExpr::Function: OS << " __FUNCTION__"; break; case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; @@ -443,8 +443,13 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) { DumpExpr(Str); // FIXME: this doesn't print wstrings right. OS << " "; - if (Str->isWide()) - OS << "L"; + switch (Str->getKind()) { + case StringLiteral::Ascii: break; // No prefix + case StringLiteral::Wide: OS << 'L'; break; + case StringLiteral::UTF8: OS << "u8"; break; + case StringLiteral::UTF16: OS << 'u'; break; + case StringLiteral::UTF32: OS << 'U'; break; + } OS << '"'; OS.write_escaped(Str->getString()); OS << '"'; @@ -475,7 +480,7 @@ void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") - << Node->getMemberDecl() << ' ' + << *Node->getMemberDecl() << ' ' << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -552,7 +557,8 @@ void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); - OS << " functional cast to " << Node->getTypeAsWritten().getAsString(); + OS << " functional cast to " << Node->getTypeAsWritten().getAsString() + << " <" << Node->getCastKindName() << ">"; } void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { @@ -637,7 +643,7 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - OS << ' ' << Node->getProtocol(); + OS << ' ' <<* Node->getProtocol(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { @@ -656,7 +662,7 @@ void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { OS << "(null)"; OS << "\""; } else { - OS << " Kind=PropertyRef Property=\"" << Node->getExplicitProperty() << '"'; + OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"'; } if (Node->isSuperReceiver()) @@ -674,7 +680,7 @@ void Stmt::dump(SourceManager &SM) const { dump(llvm::errs(), SM); } -void Stmt::dump(llvm::raw_ostream &OS, SourceManager &SM) const { +void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { StmtDumper P(&SM, OS, 4); P.DumpSubTree(const_cast<Stmt*>(this)); OS << "\n"; diff --git a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp index f705a84..daaa354 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp @@ -28,14 +28,14 @@ using namespace clang; namespace { class StmtPrinter : public StmtVisitor<StmtPrinter> { - llvm::raw_ostream &OS; + raw_ostream &OS; ASTContext &Context; unsigned IndentLevel; clang::PrinterHelper* Helper; PrintingPolicy Policy; public: - StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, + StmtPrinter(raw_ostream &os, ASTContext &C, PrinterHelper* helper, const PrintingPolicy &Policy, unsigned Indentation = 0) : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), @@ -76,7 +76,7 @@ namespace { OS << "<null expr>"; } - llvm::raw_ostream &Indent(int Delta = 0) { + raw_ostream &Indent(int Delta = 0) { for (int i = 0, e = IndentLevel+Delta; i < e; ++i) OS << " "; return OS; @@ -124,7 +124,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) { void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); - llvm::SmallVector<Decl*, 2> Decls; + SmallVector<Decl*, 2> Decls; for ( ; Begin != End; ++Begin) Decls.push_back(*Begin); @@ -564,7 +564,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - OS << Node->getDecl(); + OS << *Node->getDecl(); } void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { @@ -584,7 +584,7 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { switch (Node->getIdentType()) { default: - assert(0 && "unknown case"); + llvm_unreachable("unknown case"); case PredefinedExpr::Func: OS << "__func__"; break; @@ -599,8 +599,14 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { unsigned value = Node->getValue(); - if (Node->isWide()) - OS << "L"; + + switch (Node->getKind()) { + case CharacterLiteral::Ascii: break; // no prefix. + case CharacterLiteral::Wide: OS << 'L'; break; + case CharacterLiteral::UTF16: OS << 'u'; break; + case CharacterLiteral::UTF32: OS << 'U'; break; + } + switch (value) { case '\\': OS << "'\\\\'"; @@ -652,7 +658,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { // Emit suffixes. Integer literals are always a builtin integer type. switch (Node->getType()->getAs<BuiltinType>()->getKind()) { - default: assert(0 && "Unexpected type for integer literal!"); + default: llvm_unreachable("Unexpected type for integer literal!"); case BuiltinType::Int: break; // no suffix. case BuiltinType::UInt: OS << 'U'; break; case BuiltinType::Long: OS << 'L'; break; @@ -662,8 +668,9 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { } } void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { - // FIXME: print value more precisely. - OS << Node->getValueAsApproximateDouble(); + llvm::SmallString<16> Str; + Node->getValue().toString(Str); + OS << Str; } void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { @@ -672,12 +679,18 @@ void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { } void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { - if (Str->isWide()) OS << 'L'; + switch (Str->getKind()) { + case StringLiteral::Ascii: break; // no prefix. + case StringLiteral::Wide: OS << 'L'; break; + case StringLiteral::UTF8: OS << "u8"; break; + case StringLiteral::UTF16: OS << 'u'; break; + case StringLiteral::UTF32: OS << 'U'; break; + } OS << '"'; // FIXME: this doesn't print wstrings right. - llvm::StringRef StrData = Str->getString(); - for (llvm::StringRef::iterator I = StrData.begin(), E = StrData.end(); + StringRef StrData = Str->getString(); + for (StringRef::iterator I = StrData.begin(), E = StrData.end(); I != E; ++I) { unsigned char Char = *I; @@ -998,6 +1011,59 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { OS << ")"; } +void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { + const char *Name = 0; + switch (Node->getOp()) { + case AtomicExpr::Load: + Name = "__atomic_load("; + break; + case AtomicExpr::Store: + Name = "__atomic_store("; + break; + case AtomicExpr::CmpXchgStrong: + Name = "__atomic_compare_exchange_strong("; + break; + case AtomicExpr::CmpXchgWeak: + Name = "__atomic_compare_exchange_weak("; + break; + case AtomicExpr::Xchg: + Name = "__atomic_exchange("; + break; + case AtomicExpr::Add: + Name = "__atomic_fetch_add("; + break; + case AtomicExpr::Sub: + Name = "__atomic_fetch_sub("; + break; + case AtomicExpr::And: + Name = "__atomic_fetch_and("; + break; + case AtomicExpr::Or: + Name = "__atomic_fetch_or("; + break; + case AtomicExpr::Xor: + Name = "__atomic_fetch_xor("; + break; + } + OS << Name; + PrintExpr(Node->getPtr()); + OS << ", "; + if (Node->getOp() != AtomicExpr::Load) { + PrintExpr(Node->getVal1()); + OS << ", "; + } + if (Node->isCmpXChg()) { + PrintExpr(Node->getVal2()); + OS << ", "; + } + PrintExpr(Node->getOrder()); + if (Node->isCmpXChg()) { + OS << ", "; + PrintExpr(Node->getOrderFail()); + } + OS << ")"; +} + // C++ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { const char *OpStrings[NUM_OVERLOADED_OPERATORS] = { @@ -1039,7 +1105,7 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { OS << ' ' << OpStrings[Kind] << ' '; PrintExpr(Node->getArg(1)); } else { - assert(false && "unknown overloaded operator"); + llvm_unreachable("unknown overloaded operator"); } } @@ -1438,7 +1504,7 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { } void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - OS << "@protocol(" << Node->getProtocol() << ')'; + OS << "@protocol(" << *Node->getProtocol() << ')'; } void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { @@ -1520,7 +1586,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { } void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { - OS << Node->getDecl(); + OS << *Node->getDecl(); } void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {} @@ -1541,7 +1607,7 @@ void Stmt::dumpPretty(ASTContext& Context) const { PrintingPolicy(Context.getLangOptions())); } -void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, +void Stmt::printPretty(raw_ostream &OS, ASTContext& Context, PrinterHelper* Helper, const PrintingPolicy &Policy, unsigned Indentation) const { diff --git a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp index 120c9e5..214378a 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp +++ b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp @@ -252,7 +252,7 @@ void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) { void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) { VisitExpr(S); - ID.AddBoolean(S->isWide()); + ID.AddInteger(S->getKind()); ID.AddInteger(S->getValue()); } @@ -269,7 +269,7 @@ void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) { void StmtProfiler::VisitStringLiteral(const StringLiteral *S) { VisitExpr(S); ID.AddString(S->getString()); - ID.AddBoolean(S->isWide()); + ID.AddInteger(S->getKind()); } void StmtProfiler::VisitParenExpr(const ParenExpr *S) { @@ -468,6 +468,11 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { } } +void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getOp()); +} + static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, UnaryOperatorKind &UnaryOp, BinaryOperatorKind &BinaryOp) { diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp index 56c6e7b..0c011a8 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp @@ -33,7 +33,7 @@ using namespace clang; /// /// \param Out the raw_ostream instance to use for printing. static void printIntegral(const TemplateArgument &TemplArg, - llvm::raw_ostream &Out) { + raw_ostream &Out) { const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); const llvm::APSInt *Val = TemplArg.getAsIntegral(); @@ -68,8 +68,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, bool TemplateArgument::isDependent() const { switch (getKind()) { case Null: - assert(false && "Should not have a NULL template argument"); - return false; + llvm_unreachable("Should not have a NULL template argument"); case Type: return getAsType()->isDependentType(); @@ -107,8 +106,7 @@ bool TemplateArgument::isDependent() const { bool TemplateArgument::isInstantiationDependent() const { switch (getKind()) { case Null: - assert(false && "Should not have a NULL template argument"); - return false; + llvm_unreachable("Should not have a NULL template argument"); case Type: return getAsType()->isInstantiationDependentType(); @@ -309,7 +307,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const { } void TemplateArgument::print(const PrintingPolicy &Policy, - llvm::raw_ostream &Out) const { + raw_ostream &Out) const { switch (getKind()) { case Null: Out << "<no value>"; @@ -530,3 +528,65 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB; } + +const ASTTemplateArgumentListInfo * +ASTTemplateArgumentListInfo::Create(ASTContext &C, + const TemplateArgumentListInfo &List) { + std::size_t size = sizeof(CXXDependentScopeMemberExpr) + + ASTTemplateArgumentListInfo::sizeFor(List); + void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>()); + ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo(); + TAI->initializeFrom(List); + return TAI; +} + +void ASTTemplateArgumentListInfo::initializeFrom( + const TemplateArgumentListInfo &Info) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); +} + +void ASTTemplateArgumentListInfo::initializeFrom( + const TemplateArgumentListInfo &Info, + bool &Dependent, + bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) { + Dependent = Dependent || Info[i].getArgument().isDependent(); + InstantiationDependent = InstantiationDependent || + Info[i].getArgument().isInstantiationDependent(); + ContainsUnexpandedParameterPack + = ContainsUnexpandedParameterPack || + Info[i].getArgument().containsUnexpandedParameterPack(); + + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); + } +} + +void ASTTemplateArgumentListInfo::copyInto( + TemplateArgumentListInfo &Info) const { + Info.setLAngleLoc(LAngleLoc); + Info.setRAngleLoc(RAngleLoc); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + Info.addArgument(getTemplateArgs()[I]); +} + +std::size_t ASTTemplateArgumentListInfo::sizeFor(unsigned NumTemplateArgs) { + return sizeof(ASTTemplateArgumentListInfo) + + sizeof(TemplateArgumentLoc) * NumTemplateArgs; +} + +std::size_t ASTTemplateArgumentListInfo::sizeFor( + const TemplateArgumentListInfo &Info) { + return sizeFor(Info.size()); +} diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp index 1f7b19a..a0487ba 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp @@ -125,16 +125,16 @@ bool TemplateName::containsUnexpandedParameterPack() const { } void -TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, +TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) - OS << Template; + OS << *Template; else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getDecl(); + OS << *QTN->getDecl(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); diff --git a/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp index 08971eb..44eeec0 100644 --- a/contrib/llvm/tools/clang/lib/AST/Type.cpp +++ b/contrib/llvm/tools/clang/lib/AST/Type.cpp @@ -42,6 +42,26 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { (hasObjCLifetime() && !Other.hasObjCLifetime())); } +const IdentifierInfo* QualType::getBaseTypeIdentifier() const { + const Type* ty = getTypePtr(); + NamedDecl *ND = NULL; + if (ty->isPointerType() || ty->isReferenceType()) + return ty->getPointeeType().getBaseTypeIdentifier(); + else if (ty->isRecordType()) + ND = ty->getAs<RecordType>()->getDecl(); + else if (ty->isEnumeralType()) + ND = ty->getAs<EnumType>()->getDecl(); + else if (ty->getTypeClass() == Type::Typedef) + ND = ty->getAs<TypedefType>()->getDecl(); + else if (ty->isArrayType()) + return ty->castAsArrayTypeUnsafe()-> + getElementType().getBaseTypeIdentifier(); + + if (ND) + return ND->getIdentifier(); + return NULL; +} + bool QualType::isConstant(QualType T, ASTContext &Ctx) { if (T.isConstQualified()) return true; @@ -635,6 +655,18 @@ bool Type::isWideCharType() const { return false; } +bool Type::isChar16Type() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Char16; + return false; +} + +bool Type::isChar32Type() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Char32; + return false; +} + /// \brief Determine whether this type is any of the built-in character /// types. bool Type::isAnyCharacterType() const { @@ -734,9 +766,16 @@ bool Type::hasUnsignedIntegerRepresentation() const { return isUnsignedIntegerType(); } +bool Type::isHalfType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Half; + // FIXME: Should we allow complex __fp16? Probably not. + return false; +} + bool Type::isFloatingType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) - return BT->getKind() >= BuiltinType::Float && + return BT->getKind() >= BuiltinType::Half && BT->getKind() <= BuiltinType::LongDouble; if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) return CT->getElementType()->isFloatingType(); @@ -801,14 +840,16 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { const Type *T = CanonicalType.getTypePtr(); if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { if (BT->getKind() == BuiltinType::Bool) return STK_Bool; - if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer; + if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer; if (BT->isInteger()) return STK_Integral; if (BT->isFloatingPoint()) return STK_Floating; llvm_unreachable("unknown scalar builtin type"); - } else if (isa<PointerType>(T) || - isa<BlockPointerType>(T) || - isa<ObjCObjectPointerType>(T)) { - return STK_Pointer; + } else if (isa<PointerType>(T)) { + return STK_CPointer; + } else if (isa<BlockPointerType>(T)) { + return STK_BlockPointer; + } else if (isa<ObjCObjectPointerType>(T)) { + return STK_ObjCObjectPointer; } else if (isa<MemberPointerType>(T)) { return STK_MemberPointer; } else if (isa<EnumType>(T)) { @@ -821,7 +862,6 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } llvm_unreachable("unknown scalar type"); - return STK_Pointer; } /// \brief Determines whether the type is a C++ aggregate type or C @@ -872,7 +912,7 @@ bool Type::isIncompleteType() const { case Record: // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). - return !cast<TagType>(CanonicalType)->getDecl()->isDefinition(); + return !cast<TagType>(CanonicalType)->getDecl()->isCompleteDefinition(); case ConstantArray: // An array is incomplete if its element type is incomplete // (C++ [dcl.array]p1). @@ -1073,7 +1113,7 @@ bool Type::isLiteralType() const { // C++0x [basic.types]p10: // A type is a literal type if it is: // [...] - // -- an array of literal type + // -- an array of literal type. // Extension: variable arrays cannot be literal types, since they're // runtime-sized. if (isVariableArrayType()) @@ -1093,33 +1133,31 @@ bool Type::isLiteralType() const { // C++0x [basic.types]p10: // A type is a literal type if it is: // -- a scalar type; or - // As an extension, Clang treats vector types as Scalar types. - if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + // As an extension, Clang treats vector types as literal types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) + return true; // -- a reference type; or - if (BaseTy->isReferenceType()) return true; + if (BaseTy->isReferenceType()) + return true; // -- a class type that has all of the following properties: if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + // -- a trivial destructor, + // -- every constructor call and full-expression in the + // brace-or-equal-initializers for non-static data members (if any) + // is a constant expression, + // -- it is an aggregate type or has at least one constexpr + // constructor or constructor template that is not a copy or move + // constructor, and + // -- all non-static data members and base classes of literal types + // + // We resolve DR1361 by ignoring the second bullet. if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { - // -- a trivial destructor, - if (!ClassDecl->hasTrivialDestructor()) return false; - // -- every constructor call and full-expression in the - // brace-or-equal-initializers for non-static data members (if any) - // is a constant expression, - // FIXME: C++0x: Clang doesn't yet support non-static data member - // declarations with initializers, or constexprs. - // -- it is an aggregate type or has at least one constexpr - // constructor or constructor template that is not a copy or move - // constructor, and - if (!ClassDecl->isAggregate() && - !ClassDecl->hasConstExprNonCopyMoveConstructor()) - return false; - // -- all non-static data members and base classes of literal types - if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false; - } + dyn_cast<CXXRecordDecl>(RT->getDecl())) + return ClassDecl->isLiteral(); return true; } + return false; } @@ -1158,7 +1196,7 @@ bool Type::isStandardLayoutType() const { } // This is effectively the intersection of isTrivialType and -// isStandardLayoutType. We implement it dircetly to avoid redundant +// isStandardLayoutType. We implement it directly to avoid redundant // conversions from a type to a CXXRecordDecl. bool QualType::isCXX11PODType(ASTContext &Context) const { const Type *ty = getTypePtr(); @@ -1426,10 +1464,10 @@ const char *Type::getTypeClassName() const { return 0; } -const char *BuiltinType::getName(const LangOptions &LO) const { +const char *BuiltinType::getName(const PrintingPolicy &Policy) const { switch (getKind()) { case Void: return "void"; - case Bool: return LO.Bool ? "bool" : "_Bool"; + case Bool: return Policy.Bool ? "bool" : "_Bool"; case Char_S: return "char"; case Char_U: return "char"; case SChar: return "signed char"; @@ -1444,6 +1482,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case ULong: return "unsigned long"; case ULongLong: return "unsigned long long"; case UInt128: return "__uint128_t"; + case Half: return "half"; case Float: return "float"; case Double: return "double"; case LongDouble: return "long double"; @@ -1481,7 +1520,7 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const { return *this; } -llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { +StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { case CC_Default: llvm_unreachable("no name for default cc"); @@ -1716,7 +1755,7 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) { for (TagDecl::redecl_iterator I = decl->redecls_begin(), E = decl->redecls_end(); I != E; ++I) { - if (I->isDefinition() || I->isBeingDefined()) + if (I->isCompleteDefinition() || I->isBeingDefined()) return *I; } // If there's no definition (not even in progress), return what we have. @@ -2082,6 +2121,8 @@ static CachedProperties computeCachedProperties(const Type *T) { return Cache::get(cast<ObjCObjectType>(T)->getBaseType()); case Type::ObjCObjectPointer: return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType()); + case Type::Atomic: + return Cache::get(cast<AtomicType>(T)->getValueType()); } llvm_unreachable("unhandled type class"); @@ -2227,13 +2268,13 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { /// with non-trivial destructors. const CXXRecordDecl *record = type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); - if (record && !record->hasTrivialDestructor()) + if (record && record->hasDefinition() && !record->hasTrivialDestructor()) return DK_cxx_destructor; return DK_none; } -bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const { +bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const { switch (getObjCLifetime()) { case Qualifiers::OCL_None: break; @@ -2249,7 +2290,8 @@ bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const { if (const CXXRecordDecl *Record = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) - return Record->hasTrivialCopyAssignment(); + return Copying ? Record->hasTrivialCopyAssignment() : + Record->hasTrivialMoveAssignment(); return true; } diff --git a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp index 34e7693..8e8b227 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp @@ -206,7 +206,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Char_S: return TST_char; case BuiltinType::Char16: - return TST_char16; + return TST_char16; case BuiltinType::Char32: return TST_char32; case BuiltinType::WChar_S: @@ -225,6 +225,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Long: case BuiltinType::LongLong: case BuiltinType::Int128: + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp index b89d2aa..fb7b918 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp @@ -123,6 +123,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { case Type::DependentTemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: + case Type::Atomic: CanPrefixQualifiers = true; break; @@ -205,11 +206,11 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) { if (S.empty()) { - S = T->getName(Policy.LangOpts); + S = T->getName(Policy); } else { // Prefix the basic type, e.g. 'int X'. S = ' ' + S; - S = T->getName(Policy.LangOpts) + S; + S = T->getName(Policy) + S; } } @@ -581,6 +582,16 @@ void TypePrinter::printAuto(const AutoType *T, std::string &S) { } } +void TypePrinter::printAtomic(const AtomicType *T, std::string &S) { + if (!S.empty()) + S = ' ' + S; + std::string Str; + IncludeStrongLifetimeRAII Strong(Policy); + print(T->getValueType(), Str); + + S = "_Atomic(" + Str + ")" + S; +} + /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { if (DC->isTranslationUnit()) return; diff --git a/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp new file mode 100644 index 0000000..f5ff624 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/VTTBuilder.cpp @@ -0,0 +1,212 @@ +//===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with generation of the layout of virtual table +// tables (VTT). +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/VTTBuilder.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Format.h" +#include <algorithm> +#include <cstdio> + +using namespace clang; + +#define DUMP_OVERRIDERS 0 + +VTTBuilder::VTTBuilder(ASTContext &Ctx, + const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition) + : Ctx(Ctx), MostDerivedClass(MostDerivedClass), + MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)), + GenerateDefinition(GenerateDefinition) { + // Lay out this VTT. + LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), + /*BaseIsVirtual=*/false); +} + +void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, + const CXXRecordDecl *VTableClass) { + // Store the vtable pointer index if we're generating the primary VTT. + if (VTableClass == MostDerivedClass) { + assert(!SecondaryVirtualPointerIndices.count(Base) && + "A virtual pointer index already exists for this base subobject!"); + SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); + } + + if (!GenerateDefinition) { + VTTComponents.push_back(VTTComponent()); + return; + } + + VTTComponents.push_back(VTTComponent(VTableIndex, Base)); +} + +void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + // Don't layout virtual bases. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + CharUnits BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + // Layout the VTT for this base. + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); + } +} + +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + uint64_t VTableIndex, + const CXXRecordDecl *VTableClass, + VisitedVirtualBasesSetTy &VBases) { + const CXXRecordDecl *RD = Base.getBase(); + + // We're not interested in bases that don't have virtual bases, and not + // morally virtual bases. + if (!RD->getNumVBases() && !BaseIsMorallyVirtual) + return; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers are present for all bases with either + // virtual bases or virtual function declarations overridden along a + // virtual path. + // + // If the base class is not dynamic, we don't want to add it, nor any + // of its base classes. + if (!BaseDecl->isDynamicClass()) + continue; + + bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + bool BaseDeclIsNonVirtualPrimaryBase = false; + CharUnits BaseOffset; + if (I->isVirtual()) { + // Ignore virtual bases that we've already visited. + if (!VBases.insert(BaseDecl)) + continue; + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + BaseDeclIsMorallyVirtual = true; + } else { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + if (!Layout.isPrimaryBaseVirtual() && + Layout.getPrimaryBase() == BaseDecl) + BaseDeclIsNonVirtualPrimaryBase = true; + } + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers: for each base class X which (a) has virtual + // bases or is reachable along a virtual path from D, and (b) is not a + // non-virtual primary base, the address of the virtual table for X-in-D + // or an appropriate construction virtual table. + if (!BaseDeclIsNonVirtualPrimaryBase && + (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { + // Add the vtable pointer. + AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex, + VTableClass); + } + + // And lay out the secondary virtual pointers for the base class. + LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), + BaseDeclIsMorallyVirtual, VTableIndex, + VTableClass, VBases); + } +} + +void +VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, + uint64_t VTableIndex) { + VisitedVirtualBasesSetTy VBases; + LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, + VTableIndex, Base.getBase(), VBases); +} + +void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a virtual base. + if (I->isVirtual()) { + // Check if we've seen this base before. + if (!VBases.insert(BaseDecl)) + continue; + + CharUnits BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); + } + + // We only need to layout virtual VTTs for this base if it actually has + // virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVirtualVTTs(BaseDecl, VBases); + } +} + +void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { + const CXXRecordDecl *RD = Base.getBase(); + + // Itanium C++ ABI 2.6.2: + // An array of virtual table addresses, called the VTT, is declared for + // each class type that has indirect or direct virtual base classes. + if (RD->getNumVBases() == 0) + return; + + bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; + + if (!IsPrimaryVTT) { + // Remember the sub-VTT index. + SubVTTIndicies[Base] = VTTComponents.size(); + } + + uint64_t VTableIndex = VTTVTables.size(); + VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual)); + + // Add the primary vtable pointer. + AddVTablePointer(Base, VTableIndex, RD); + + // Add the secondary VTTs. + LayoutSecondaryVTTs(Base); + + // Add the secondary virtual pointers. + LayoutSecondaryVirtualPointers(Base, VTableIndex); + + // If this is the primary VTT, we want to lay out virtual VTTs as well. + if (IsPrimaryVTT) { + VisitedVirtualBasesSetTy VBases; + LayoutVirtualVTTs(Base.getBase(), VBases); + } +} diff --git a/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp new file mode 100644 index 0000000..7765817 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp @@ -0,0 +1,2404 @@ +//===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with generation of the layout of virtual tables. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/VTableBuilder.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Format.h" +#include <algorithm> +#include <cstdio> + +using namespace clang; + +#define DUMP_OVERRIDERS 0 + +namespace { + +/// BaseOffset - Represents an offset from a derived class to a direct or +/// indirect base class. +struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// (Or the offset from the virtual base class to the base class, if the + /// path from the derived class to the base class involves a virtual base + /// class. + CharUnits NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), + NonVirtualOffset(CharUnits::Zero()) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; } +}; + +/// FinalOverriders - Contains the final overrider member functions for all +/// member functions in the base subobjects of a class. +class FinalOverriders { +public: + /// OverriderInfo - Information about a final overrider. + struct OverriderInfo { + /// Method - The method decl of the overrider. + const CXXMethodDecl *Method; + + /// Offset - the base offset of the overrider in the layout class. + CharUnits Offset; + + OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { } + }; + +private: + /// MostDerivedClass - The most derived class for which the final overriders + /// are stored. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building final overriders for a + /// construction vtable, this holds the offset from the layout class to the + /// most derived class. + const CharUnits MostDerivedClassOffset; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if the final overriders are for a + /// construction vtable. + const CXXRecordDecl *LayoutClass; + + ASTContext &Context; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + /// MethodBaseOffsetPairTy - Uniquely identifies a member function + /// in a base subobject. + typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy; + + typedef llvm::DenseMap<MethodBaseOffsetPairTy, + OverriderInfo> OverridersMapTy; + + /// OverridersMap - The final overriders for all virtual member functions of + /// all the base subobjects of the most derived class. + OverridersMapTy OverridersMap; + + /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented + /// as a record decl and a subobject number) and its offsets in the most + /// derived class as well as the layout class. + typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>, + CharUnits> SubobjectOffsetMapTy; + + typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy; + + /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the + /// given base. + void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, + CharUnits OffsetInLayoutClass, + SubobjectOffsetMapTy &SubobjectOffsets, + SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, + SubobjectCountMapTy &SubobjectCounts); + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + /// dump - dump the final overriders for a base subobject, and all its direct + /// and indirect base subobjects. + void dump(raw_ostream &Out, BaseSubobject Base, + VisitedVirtualBasesSetTy& VisitedVirtualBases); + +public: + FinalOverriders(const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass); + + /// getOverrider - Get the final overrider for the given method declaration in + /// the subobject with the given base offset. + OverriderInfo getOverrider(const CXXMethodDecl *MD, + CharUnits BaseOffset) const { + assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) && + "Did not find overrider!"); + + return OverridersMap.lookup(std::make_pair(MD, BaseOffset)); + } + + /// dump - dump the final overriders. + void dump() { + VisitedVirtualBasesSetTy VisitedVirtualBases; + dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()), + VisitedVirtualBases); + } + +}; + +#define DUMP_OVERRIDERS 0 + +FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass) + : MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), + MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { + + // Compute base offsets. + SubobjectOffsetMapTy SubobjectOffsets; + SubobjectOffsetMapTy SubobjectLayoutClassOffsets; + SubobjectCountMapTy SubobjectCounts; + ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()), + /*IsVirtual=*/false, + MostDerivedClassOffset, + SubobjectOffsets, SubobjectLayoutClassOffsets, + SubobjectCounts); + + // Get the the final overriders. + CXXFinalOverriderMap FinalOverriders; + MostDerivedClass->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::const_iterator I = FinalOverriders.begin(), + E = FinalOverriders.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const OverridingMethods& Methods = I->second; + + for (OverridingMethods::const_iterator I = Methods.begin(), + E = Methods.end(); I != E; ++I) { + unsigned SubobjectNumber = I->first; + assert(SubobjectOffsets.count(std::make_pair(MD->getParent(), + SubobjectNumber)) && + "Did not find subobject offset!"); + + CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), + SubobjectNumber)]; + + assert(I->second.size() == 1 && "Final overrider is not unique!"); + const UniqueVirtualMethod &Method = I->second.front(); + + const CXXRecordDecl *OverriderRD = Method.Method->getParent(); + assert(SubobjectLayoutClassOffsets.count( + std::make_pair(OverriderRD, Method.Subobject)) + && "Did not find subobject offset!"); + CharUnits OverriderOffset = + SubobjectLayoutClassOffsets[std::make_pair(OverriderRD, + Method.Subobject)]; + + OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)]; + assert(!Overrider.Method && "Overrider should not exist yet!"); + + Overrider.Offset = OverriderOffset; + Overrider.Method = Method.Method; + } + } + +#if DUMP_OVERRIDERS + // And dump them (for now). + dump(); +#endif +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { + CharUnits NonVirtualOffset = CharUnits::Zero(); + + unsigned NonVirtualStart = 0; + const CXXRecordDecl *VirtualBase = 0; + + // First, look for the virtual base class. + for (unsigned I = 0, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + if (Element.Base->isVirtual()) { + // FIXME: Can we break when we find the first virtual base? + // (If we can't, can't we just iterate over the path in reverse order?) + NonVirtualStart = I + 1; + QualType VBaseType = Element.Base->getType(); + VirtualBase = + cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + } + } + + // Now compute the non-virtual offset. + for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); + const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); + + NonVirtualOffset += Layout.getBaseClassOffset(Base); + } + + // FIXME: This should probably use CharUnits or something. Maybe we should + // even change the base offsets in ASTRecordLayout to be specified in + // CharUnits. + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset); + +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + + if (!const_cast<CXXRecordDecl *>(DerivedRD)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { + llvm_unreachable("Class must be derived from the passed in base class!"); + } + + return ComputeBaseOffset(Context, DerivedRD, Paths.front()); +} + +static BaseOffset +ComputeReturnAdjustmentBaseOffset(ASTContext &Context, + const CXXMethodDecl *DerivedMD, + const CXXMethodDecl *BaseMD) { + const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>(); + const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>(); + + // Canonicalize the return types. + CanQualType CanDerivedReturnType = + Context.getCanonicalType(DerivedFT->getResultType()); + CanQualType CanBaseReturnType = + Context.getCanonicalType(BaseFT->getResultType()); + + assert(CanDerivedReturnType->getTypeClass() == + CanBaseReturnType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedReturnType == CanBaseReturnType) { + // No adjustment needed. + return BaseOffset(); + } + + if (isa<ReferenceType>(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs<ReferenceType>()->getPointeeType(); + } else if (isa<PointerType>(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs<PointerType>()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs<PointerType>()->getPointeeType(); + } else { + llvm_unreachable("Unexpected return type!"); + } + + // We need to compare unqualified types here; consider + // const T *Base::foo(); + // T *Derived::foo(); + if (CanDerivedReturnType.getUnqualifiedType() == + CanBaseReturnType.getUnqualifiedType()) { + // No adjustment needed. + return BaseOffset(); + } + + const CXXRecordDecl *DerivedRD = + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); + + const CXXRecordDecl *BaseRD = + cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); + + return ComputeBaseOffset(Context, BaseRD, DerivedRD); +} + +void +FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, + CharUnits OffsetInLayoutClass, + SubobjectOffsetMapTy &SubobjectOffsets, + SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, + SubobjectCountMapTy &SubobjectCounts) { + const CXXRecordDecl *RD = Base.getBase(); + + unsigned SubobjectNumber = 0; + if (!IsVirtual) + SubobjectNumber = ++SubobjectCounts[RD]; + + // Set up the subobject to offset mapping. + assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber)) + && "Subobject offset already exists!"); + assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber)) + && "Subobject offset already exists!"); + + SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset(); + SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] = + OffsetInLayoutClass; + + // Traverse our bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits BaseOffset; + CharUnits BaseOffsetInLayoutClass; + if (I->isVirtual()) { + // Check if we've visited this virtual base before. + if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0))) + continue; + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + CharUnits Offset = Layout.getBaseClassOffset(BaseDecl); + + BaseOffset = Base.getBaseOffset() + Offset; + BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset; + } + + ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), + I->isVirtual(), BaseOffsetInLayoutClass, + SubobjectOffsets, SubobjectLayoutClassOffsets, + SubobjectCounts); + } +} + +void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, + VisitedVirtualBasesSetTy &VisitedVirtualBases) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + CharUnits BaseOffset; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) { + // We've visited this base before. + continue; + } + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); + } + + dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases); + } + + Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; + Out << Base.getBaseOffset().getQuantity() << ")\n"; + + // Now dump the overriders for this base subobject. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset()); + + Out << " " << MD->getQualifiedNameAsString() << " - ("; + Out << Overrider.Method->getQualifiedNameAsString(); + Out << ", " << ", " << Overrider.Offset.getQuantity() << ')'; + + BaseOffset Offset; + if (!Overrider.Method->isPure()) + Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); + + if (!Offset.isEmpty()) { + Out << " [ret-adj: "; + if (Offset.VirtualBase) + Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; + + Out << Offset.NonVirtualOffset.getQuantity() << " nv]"; + } + + Out << "\n"; + } +} + +/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. +struct VCallOffsetMap { + + typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy; + + /// Offsets - Keeps track of methods and their offsets. + // FIXME: This should be a real map and not a vector. + SmallVector<MethodAndOffsetPairTy, 16> Offsets; + + /// MethodsCanShareVCallOffset - Returns whether two virtual member functions + /// can share the same vcall offset. + static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS); + +public: + /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the + /// add was successful, or false if there was already a member function with + /// the same signature in the map. + bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset); + + /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the + /// vtable address point) for the given virtual member function. + CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD); + + // empty - Return whether the offset map is empty or not. + bool empty() const { return Offsets.empty(); } +}; + +static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + ASTContext &C = LHS->getASTContext(); // TODO: thread this down + CanQual<FunctionProtoType> + LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(), + RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>(); + + // Fast-path matches in the canonical types. + if (LT == RT) return true; + + // Force the signatures to match. We can't rely on the overrides + // list here because there isn't necessarily an inheritance + // relationship between the two methods. + if (LT.getQualifiers() != RT.getQualifiers() || + LT->getNumArgs() != RT->getNumArgs()) + return false; + for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) + if (LT->getArgType(I) != RT->getArgType(I)) + return false; + return true; +} + +bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + assert(LHS->isVirtual() && "LHS must be virtual!"); + assert(RHS->isVirtual() && "LHS must be virtual!"); + + // A destructor can share a vcall offset with another destructor. + if (isa<CXXDestructorDecl>(LHS)) + return isa<CXXDestructorDecl>(RHS); + + // FIXME: We need to check more things here. + + // The methods must have the same name. + DeclarationName LHSName = LHS->getDeclName(); + DeclarationName RHSName = RHS->getDeclName(); + if (LHSName != RHSName) + return false; + + // And the same signatures. + return HasSameVirtualSignature(LHS, RHS); +} + +bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, + CharUnits OffsetOffset) { + // Check if we can reuse an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return false; + } + + // Add the offset. + Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); + return true; +} + +CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { + // Look for an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return Offsets[I].second; + } + + llvm_unreachable("Should always find a vcall offset offset!"); +} + +/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. +class VCallAndVBaseOffsetBuilder { +public: + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> + VBaseOffsetOffsetsMapTy; + +private: + /// MostDerivedClass - The most derived class for which we're building vcall + /// and vbase offsets. + const CXXRecordDecl *MostDerivedClass; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// Components - vcall and vbase offset components + typedef SmallVector<VTableComponent, 64> VTableComponentVectorTy; + VTableComponentVectorTy Components; + + /// VisitedVirtualBases - Visited virtual bases. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; + + /// VCallOffsets - Keeps track of vcall offsets. + VCallOffsetMap VCallOffsets; + + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, + /// relative to the address point. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// FinalOverriders - The final overriders of the most derived class. + /// (Can be null when we're not building a vtable of the most derived class). + const FinalOverriders *Overriders; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given base subobject. + void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + CharUnits RealBaseOffset); + + /// AddVCallOffsets - Add vcall offsets for the given base subobject. + void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *Base, + CharUnits OffsetInLayoutClass); + + /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in + /// chars, relative to the vtable address point. + CharUnits getCurrentOffsetOffset() const; + +public: + VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *LayoutClass, + const FinalOverriders *Overriders, + BaseSubobject Base, bool BaseIsVirtual, + CharUnits OffsetInLayoutClass) + : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { + + // Add vcall and vbase offsets. + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); + } + + /// Methods for iterating over the components. + typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; + const_iterator components_begin() const { return Components.rbegin(); } + const_iterator components_end() const { return Components.rend(); } + + const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } +}; + +void +VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, + bool BaseIsVirtual, + CharUnits RealBaseOffset) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); + + CharUnits PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets( + BaseSubobject(PrimaryBase,PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); + } + + AddVBaseOffsets(Base.getBase(), RealBaseOffset); + + // We only want to add vcall offsets for virtual bases. + if (BaseIsVirtual) + AddVCallOffsets(Base, RealBaseOffset); +} + +CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { + // OffsetIndex is the index of this vcall or vbase offset, relative to the + // vtable address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + CharUnits PointerWidth = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + CharUnits OffsetOffset = PointerWidth * OffsetIndex; + return OffsetOffset; +} + +void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, + CharUnits VBaseOffset) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Handle the primary base first. + // We only want to add vcall offsets if the base is non-virtual; a virtual + // primary base will have its vcall and vbase offsets emitted already. + if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) { + // Get the base offset of the primary base. + assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), + VBaseOffset); + } + + // Add the vcall offsets. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + CharUnits OffsetOffset = getCurrentOffsetOffset(); + + // Don't add a vcall offset if we already have one for this member function + // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; + + CharUnits Offset = CharUnits::Zero(); + + if (Overriders) { + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders->getOverrider(MD, Base.getBaseOffset()); + + /// The vcall offset is the offset from the virtual base to the object + /// where the function was overridden. + Offset = Overrider.Offset - VBaseOffset; + } + + Components.push_back( + VTableComponent::MakeVCallOffset(Offset)); + } + + // And iterate over all non-virtual bases (ignoring the primary base). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + if (BaseDecl == PrimaryBase) + continue; + + // Get the base offset of this base. + CharUnits BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), + VBaseOffset); + } +} + +void +VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + CharUnits OffsetInLayoutClass) { + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Add vbase offsets. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + CharUnits Offset = + LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; + + // Add the vbase offset offset. + assert(!VBaseOffsetOffsets.count(BaseDecl) && + "vbase offset offset already exists!"); + + CharUnits VBaseOffsetOffset = getCurrentOffsetOffset(); + VBaseOffsetOffsets.insert( + std::make_pair(BaseDecl, VBaseOffsetOffset)); + + Components.push_back( + VTableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); + } +} + +/// VTableBuilder - Class for building vtable layout information. +class VTableBuilder { +public: + /// PrimaryBasesSetVectorTy - A set vector of direct and indirect + /// primary bases. + typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> + PrimaryBasesSetVectorTy; + + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> + VBaseOffsetOffsetsMapTy; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> + AddressPointsMapTy; + +private: + /// VTables - Global vtable information. + VTableContext &VTables; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building a construction vtable, this + /// holds the offset from the layout class to the most derived class. + const CharUnits MostDerivedClassOffset; + + /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual + /// base. (This only makes sense when building a construction vtable). + bool MostDerivedClassIsVirtual; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// FinalOverriders - The final overriders of the most derived class. + const FinalOverriders Overriders; + + /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual + /// bases in this vtable. + llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for + /// the most derived class. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// Components - The components of the vtable being built. + SmallVector<VTableComponent, 64> Components; + + /// AddressPoints - Address points for the vtable being built. + AddressPointsMapTy AddressPoints; + + /// MethodInfo - Contains information about a method in a vtable. + /// (Used for computing 'this' pointer adjustment thunks. + struct MethodInfo { + /// BaseOffset - The base offset of this method. + const CharUnits BaseOffset; + + /// BaseOffsetInLayoutClass - The base offset in the layout class of this + /// method. + const CharUnits BaseOffsetInLayoutClass; + + /// VTableIndex - The index in the vtable that this method has. + /// (For destructors, this is the index of the complete destructor). + const uint64_t VTableIndex; + + MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass, + uint64_t VTableIndex) + : BaseOffset(BaseOffset), + BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), + VTableIndex(VTableIndex) { } + + MethodInfo() + : BaseOffset(CharUnits::Zero()), + BaseOffsetInLayoutClass(CharUnits::Zero()), + VTableIndex(0) { } + }; + + typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; + + /// MethodInfoMap - The information for all methods in the vtable we're + /// currently building. + MethodInfoMapTy MethodInfoMap; + + typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; + + /// VTableThunks - The thunks by vtable index in the vtable currently being + /// built. + VTableThunksMapTy VTableThunks; + + typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; + + /// Thunks - A map that contains all the thunks needed for all methods in the + /// most derived class for which the vtable is currently being built. + ThunksMapTy Thunks; + + /// AddThunk - Add a thunk for the given method. + void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); + + /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the + /// part of the vtable we're currently building. + void ComputeThisAdjustments(); + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + /// PrimaryVirtualBases - All known virtual bases who are a primary base of + /// some other base. + VisitedVirtualBasesSetTy PrimaryVirtualBases; + + /// ComputeReturnAdjustment - Compute the return adjustment given a return + /// adjustment base offset. + ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); + + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const; + + /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the + /// given virtual member function, its offset in the layout class and its + /// final overrider. + ThisAdjustment + ComputeThisAdjustment(const CXXMethodDecl *MD, + CharUnits BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider); + + /// AddMethod - Add a single virtual member function to the vtable + /// components vector. + void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); + + /// IsOverriderUsed - Returns whether the overrider will ever be used in this + /// part of the vtable. + /// + /// Itanium C++ ABI 2.5.2: + /// + /// struct A { virtual void f(); }; + /// struct B : virtual public A { int i; }; + /// struct C : virtual public A { int j; }; + /// struct D : public B, public C {}; + /// + /// When B and C are declared, A is a primary base in each case, so although + /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this + /// adjustment is required and no thunk is generated. However, inside D + /// objects, A is no longer a primary base of C, so if we allowed calls to + /// C::f() to use the copy of A's vtable in the C subobject, we would need + /// to adjust this from C* to B::A*, which would require a third-party + /// thunk. Since we require that a call to C::f() first convert to A*, + /// C-in-D's copy of A's vtable is never referenced, so this is not + /// necessary. + bool IsOverriderUsed(const CXXMethodDecl *Overrider, + CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass) const; + + + /// AddMethods - Add the methods of this base subobject and all its + /// primary bases to the vtable components vector. + void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases); + + // LayoutVTable - Layout the vtable for the given base class, including its + // secondary vtables and any vtables for virtual bases. + void LayoutVTable(); + + /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the + /// given base subobject, as well as all its secondary vtables. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual + /// in the layout class. + void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + CharUnits OffsetInLayoutClass); + + /// LayoutSecondaryVTables - Layout the secondary vtables for the given base + /// subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, + CharUnits OffsetInLayoutClass); + + /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this + /// class hierarchy. + void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + CharUnits OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the + /// given base (excluding any primary bases). + void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// isBuildingConstructionVTable - Return whether this vtable builder is + /// building a construction vtable. + bool isBuildingConstructorVTable() const { + return MostDerivedClass != LayoutClass; + } + +public: + VTableBuilder(VTableContext &VTables, const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, const + CXXRecordDecl *LayoutClass) + : VTables(VTables), MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), + MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), + LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), + Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + + LayoutVTable(); + + if (Context.getLangOptions().DumpVTableLayouts) + dumpLayout(llvm::errs()); + } + + uint64_t getNumThunks() const { + return Thunks.size(); + } + + ThunksMapTy::const_iterator thunks_begin() const { + return Thunks.begin(); + } + + ThunksMapTy::const_iterator thunks_end() const { + return Thunks.end(); + } + + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } + + const AddressPointsMapTy &getAddressPoints() const { + return AddressPoints; + } + + /// getNumVTableComponents - Return the number of components in the vtable + /// currently built. + uint64_t getNumVTableComponents() const { + return Components.size(); + } + + const VTableComponent *vtable_component_begin() const { + return Components.begin(); + } + + const VTableComponent *vtable_component_end() const { + return Components.end(); + } + + AddressPointsMapTy::const_iterator address_points_begin() const { + return AddressPoints.begin(); + } + + AddressPointsMapTy::const_iterator address_points_end() const { + return AddressPoints.end(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_begin() const { + return VTableThunks.begin(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_end() const { + return VTableThunks.end(); + } + + /// dumpLayout - Dump the vtable layout. + void dumpLayout(raw_ostream&); +}; + +void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { + assert(!isBuildingConstructorVTable() && + "Can't add thunks for construction vtable"); + + SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; + + // Check if we have this thunk already. + if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != + ThunksVector.end()) + return; + + ThunksVector.push_back(Thunk); +} + +typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; + +/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all +/// the overridden methods that the function decl overrides. +static void +ComputeAllOverriddenMethods(const CXXMethodDecl *MD, + OverriddenMethodsSetTy& OverriddenMethods) { + assert(MD->isVirtual() && "Method is not virtual!"); + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + OverriddenMethods.insert(OverriddenMD); + + ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); + } +} + +void VTableBuilder::ComputeThisAdjustments() { + // Now go through the method info map and see if any of the methods need + // 'this' pointer adjustments. + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MethodInfo = I->second; + + // Ignore adjustments for unused function pointers. + uint64_t VTableIndex = MethodInfo.VTableIndex; + if (Components[VTableIndex].getKind() == + VTableComponent::CK_UnusedFunctionPointer) + continue; + + // Get the final overrider for this method. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(MD, MethodInfo.BaseOffset); + + // Check if we need an adjustment at all. + if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { + // When a return thunk is needed by a derived class that overrides a + // virtual base, gcc uses a virtual 'this' adjustment as well. + // While the thunk itself might be needed by vtables in subclasses or + // in construction vtables, there doesn't seem to be a reason for using + // the thunk in this vtable. Still, we do so to match gcc. + if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) + continue; + } + + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); + + if (ThisAdjustment.isEmpty()) + continue; + + // Add it. + VTableThunks[VTableIndex].This = ThisAdjustment; + + if (isa<CXXDestructorDecl>(MD)) { + // Add an adjustment for the deleting destructor as well. + VTableThunks[VTableIndex + 1].This = ThisAdjustment; + } + } + + /// Clear the method info map. + MethodInfoMap.clear(); + + if (isBuildingConstructorVTable()) { + // We don't need to store thunk information for construction vtables. + return; + } + + for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(), + E = VTableThunks.end(); I != E; ++I) { + const VTableComponent &Component = Components[I->first]; + const ThunkInfo &Thunk = I->second; + const CXXMethodDecl *MD; + + switch (Component.getKind()) { + default: + llvm_unreachable("Unexpected vtable component kind!"); + case VTableComponent::CK_FunctionPointer: + MD = Component.getFunctionDecl(); + break; + case VTableComponent::CK_CompleteDtorPointer: + MD = Component.getDestructorDecl(); + break; + case VTableComponent::CK_DeletingDtorPointer: + // We've already added the thunk when we saw the complete dtor pointer. + continue; + } + + if (MD->getParent() == MostDerivedClass) + AddThunk(MD, Thunk); + } +} + +ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { + ReturnAdjustment Adjustment; + + if (!Offset.isEmpty()) { + if (Offset.VirtualBase) { + // Get the virtual base offset offset. + if (Offset.DerivedClass == MostDerivedClass) { + // We can get the offset offset directly from our map. + Adjustment.VBaseOffsetOffset = + VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); + } else { + Adjustment.VBaseOffsetOffset = + VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, + Offset.VirtualBase).getQuantity(); + } + } + + Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); + } + + return Adjustment; +} + +BaseOffset +VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const { + const CXXRecordDecl *BaseRD = Base.getBase(); + const CXXRecordDecl *DerivedRD = Derived.getBase(); + + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + + if (!const_cast<CXXRecordDecl *>(DerivedRD)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { + llvm_unreachable("Class must be derived from the passed in base class!"); + } + + // We have to go through all the paths, and see which one leads us to the + // right base subobject. + for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); + + CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset; + + if (Offset.VirtualBase) { + // If we have a virtual base class, the non-virtual offset is relative + // to the virtual base class offset. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + /// Get the virtual base offset, relative to the most derived class + /// layout. + OffsetToBaseSubobject += + LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); + } else { + // Otherwise, the non-virtual offset is relative to the derived class + // offset. + OffsetToBaseSubobject += Derived.getBaseOffset(); + } + + // Check if this path gives us the right base subobject. + if (OffsetToBaseSubobject == Base.getBaseOffset()) { + // Since we're going from the base class _to_ the derived class, we'll + // invert the non-virtual offset here. + Offset.NonVirtualOffset = -Offset.NonVirtualOffset; + return Offset; + } + } + + return BaseOffset(); +} + +ThisAdjustment +VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, + CharUnits BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) { + // Ignore adjustments for pure virtual member functions. + if (Overrider.Method->isPure()) + return ThisAdjustment(); + + BaseSubobject OverriddenBaseSubobject(MD->getParent(), + BaseOffsetInLayoutClass); + + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.Offset); + + // Compute the adjustment offset. + BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, + OverriderBaseSubobject); + if (Offset.isEmpty()) + return ThisAdjustment(); + + ThisAdjustment Adjustment; + + if (Offset.VirtualBase) { + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, + /*FinalOverriders=*/0, + BaseSubobject(Offset.VirtualBase, + CharUnits::Zero()), + /*BaseIsVirtual=*/true, + /*OffsetInLayoutClass=*/ + CharUnits::Zero()); + + VCallOffsets = Builder.getVCallOffsets(); + } + + Adjustment.VCallOffsetOffset = + VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); + } + + // Set the non-virtual part of the adjustment. + Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); + + return Adjustment; +} + +void +VTableBuilder::AddMethod(const CXXMethodDecl *MD, + ReturnAdjustment ReturnAdjustment) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + assert(ReturnAdjustment.isEmpty() && + "Destructor can't have return adjustment!"); + + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + } else { + // Add the return adjustment if necessary. + if (!ReturnAdjustment.isEmpty()) + VTableThunks[Components.size()].Return = ReturnAdjustment; + + // Add the function. + Components.push_back(VTableComponent::MakeFunction(MD)); + } +} + +/// OverridesIndirectMethodInBase - Return whether the given member function +/// overrides any methods in the set of given bases. +/// Unlike OverridesMethodInBase, this checks "overriders of overriders". +/// For example, if we have: +/// +/// struct A { virtual void f(); } +/// struct B : A { virtual void f(); } +/// struct C : B { virtual void f(); } +/// +/// OverridesIndirectMethodInBase will return true if given C::f as the method +/// and { A } as the set of bases. +static bool +OverridesIndirectMethodInBases(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + if (Bases.count(MD->getParent())) + return true; + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // Check "indirect overriders". + if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) + return true; + } + + return false; +} + +bool +VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, + CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass) const { + // If the base and the first base in the primary base chain have the same + // offsets, then this overrider will be used. + if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) + return true; + + // We know now that Base (or a direct or indirect base of it) is a primary + // base in part of the class hierarchy, but not a primary base in the most + // derived class. + + // If the overrider is the first base in the primary base chain, we know + // that the overrider will be used. + if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) + return true; + + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + + const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; + PrimaryBases.insert(RD); + + // Now traverse the base chain, starting with the first base, until we find + // the base that is no longer a primary base. + while (true) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.isPrimaryBaseVirtual()) { + assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Now check if this is the primary base that is not a primary base in the + // most derived class. + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + FirstBaseOffsetInLayoutClass) { + // We found it, stop walking the chain. + break; + } + } else { + assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + } + + if (!PrimaryBases.insert(PrimaryBase)) + llvm_unreachable("Found a duplicate primary base!"); + + RD = PrimaryBase; + } + + // If the final overrider is an override of one of the primary bases, + // then we know that it will be used. + return OverridesIndirectMethodInBases(Overrider, PrimaryBases); +} + +/// FindNearestOverriddenMethod - Given a method, returns the overridden method +/// from the nearest base. Returns null if no method was found. +static const CXXMethodDecl * +FindNearestOverriddenMethod(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + OverriddenMethodsSetTy OverriddenMethods; + ComputeAllOverriddenMethods(MD, OverriddenMethods); + + for (int I = Bases.size(), E = 0; I != E; --I) { + const CXXRecordDecl *PrimaryBase = Bases[I - 1]; + + // Now check the overriden methods. + for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), + E = OverriddenMethods.end(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // We found our overridden method. + if (OverriddenMD->getParent() == PrimaryBase) + return OverriddenMD; + } + } + + return 0; +} + +void +VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + CharUnits PrimaryBaseOffset; + CharUnits PrimaryBaseOffsetInLayoutClass; + if (Layout.isPrimaryBaseVirtual()) { + assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; + } + + AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass, PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + llvm_unreachable("Found a duplicate primary base!"); + } + + // Now go through all virtual member functions and add them. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(MD, Base.getBaseOffset()); + + // Check if this virtual member function overrides a method in a primary + // base. If this is the case, and the return type doesn't require adjustment + // then we can just use the member function from the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + if (ComputeReturnAdjustmentBaseOffset(Context, MD, + OverriddenMD).isEmpty()) { + // Replace the method info of the overridden method with our own + // method. + assert(MethodInfoMap.count(OverriddenMD) && + "Did not find the overridden method!"); + MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; + + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, + OverriddenMethodInfo.VTableIndex); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + MethodInfoMap.erase(OverriddenMD); + + // If the overridden method exists in a virtual base class or a direct + // or indirect base class of a virtual base class, we need to emit a + // thunk if we ever have a class hierarchy where the base class is not + // a primary base in the complete object. + if (!isBuildingConstructorVTable() && OverriddenMD != MD) { + // Compute the this adjustment. + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, + Overrider); + + if (ThisAdjustment.VCallOffsetOffset && + Overrider.Method->getParent() == MostDerivedClass) { + + // There's no return adjustment from OverriddenMD and MD, + // but that doesn't mean there isn't one between MD and + // the final overrider. + BaseOffset ReturnAdjustmentOffset = + ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); + ReturnAdjustment ReturnAdjustment = + ComputeReturnAdjustment(ReturnAdjustmentOffset); + + // This is a virtual thunk for the most derived class, add it. + AddThunk(Overrider.Method, + ThunkInfo(ThisAdjustment, ReturnAdjustment)); + } + } + + continue; + } + } + + // Insert the method info for this method. + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, + Components.size()); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + + // Check if this overrider is going to be used. + const CXXMethodDecl *OverriderMD = Overrider.Method; + if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, + FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass)) { + Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); + continue; + } + + // Check if this overrider needs a return adjustment. + // We don't want to do this for pure virtual member functions. + BaseOffset ReturnAdjustmentOffset; + if (!OverriderMD->isPure()) { + ReturnAdjustmentOffset = + ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); + } + + ReturnAdjustment ReturnAdjustment = + ComputeReturnAdjustment(ReturnAdjustmentOffset); + + AddMethod(Overrider.Method, ReturnAdjustment); + } +} + +void VTableBuilder::LayoutVTable() { + LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, + CharUnits::Zero()), + /*BaseIsMorallyVirtual=*/false, + MostDerivedClassIsVirtual, + MostDerivedClassOffset); + + VisitedVirtualBasesSetTy VBases; + + // Determine the primary virtual bases. + DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, + VBases); + VBases.clear(); + + LayoutVTablesForVirtualBases(MostDerivedClass, VBases); + + // -fapple-kext adds an extra entry at end of vtbl. + bool IsAppleKext = Context.getLangOptions().AppleKext; + if (IsAppleKext) + Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero())); +} + +void +VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + CharUnits OffsetInLayoutClass) { + assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); + + // Add vcall and vbase offsets for this vtable. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, + Base, BaseIsVirtualInLayoutClass, + OffsetInLayoutClass); + Components.append(Builder.components_begin(), Builder.components_end()); + + // Check if we need to add these vcall offsets. + if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; + + if (VCallOffsets.empty()) + VCallOffsets = Builder.getVCallOffsets(); + } + + // If we're laying out the most derived class we want to keep track of the + // virtual base class offset offsets. + if (Base.getBase() == MostDerivedClass) + VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); + + // Add the offset to top. + CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; + Components.push_back( + VTableComponent::MakeOffsetToTop(OffsetToTop)); + + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); + + uint64_t AddressPoint = Components.size(); + + // Now go through all virtual member functions and add them. + PrimaryBasesSetVectorTy PrimaryBases; + AddMethods(Base, OffsetInLayoutClass, + Base.getBase(), OffsetInLayoutClass, + PrimaryBases); + + // Compute 'this' pointer adjustments. + ComputeThisAdjustments(); + + // Add all address points. + const CXXRecordDecl *RD = Base.getBase(); + while (true) { + AddressPoints.insert(std::make_pair( + BaseSubobject(RD, OffsetInLayoutClass), + AddressPoint)); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.isPrimaryBaseVirtual()) { + // Check if this virtual primary base is a primary base in the layout + // class. If it's not, we don't want to add it. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + OffsetInLayoutClass) { + // We don't want to add this class (or any of its primary bases). + break; + } + } + + RD = PrimaryBase; + } + + // Layout secondary vtables. + LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); +} + +void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + CharUnits OffsetInLayoutClass) { + // Itanium C++ ABI 2.5.2: + // Following the primary virtual table of a derived class are secondary + // virtual tables for each of its proper base classes, except any primary + // base(s) with which it shares its primary virtual table. + + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + // Ignore virtual bases, we'll emit them later. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Ignore bases that don't have a vtable. + if (!BaseDecl->isDynamicClass()) + continue; + + if (isBuildingConstructorVTable()) { + // Itanium C++ ABI 2.6.4: + // Some of the base class subobjects may not need construction virtual + // tables, which will therefore not be present in the construction + // virtual table group, even though the subobject virtual tables are + // present in the main virtual table group for the complete object. + if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) + continue; + } + + // Get the base offset of this base. + CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); + CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; + + CharUnits BaseOffsetInLayoutClass = + OffsetInLayoutClass + RelativeBaseOffset; + + // Don't emit a secondary vtable for a primary base. We might however want + // to emit secondary vtables for other bases of this base. + if (BaseDecl == PrimaryBase) { + LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, BaseOffsetInLayoutClass); + continue; + } + + // Layout the primary vtable (and any secondary vtables) for this base. + LayoutPrimaryAndSecondaryVTables( + BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, + /*BaseIsVirtualInLayoutClass=*/false, + BaseOffsetInLayoutClass); + } +} + +void +VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + CharUnits OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Check if this base has a primary base. + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + + // Check if it's virtual. + if (Layout.isPrimaryBaseVirtual()) { + bool IsPrimaryVirtualBase = true; + + if (isBuildingConstructorVTable()) { + // Check if the base is actually a primary base in the class we use for + // layout. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + CharUnits PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + + // We know that the base is not a primary base in the layout class if + // the base offsets are different. + if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) + IsPrimaryVirtualBase = false; + } + + if (IsPrimaryVirtualBase) + PrimaryVirtualBases.insert(PrimaryBase); + } + } + + // Traverse bases, looking for more primary virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits BaseOffsetInLayoutClass; + + if (I->isVirtual()) { + if (!VBases.insert(BaseDecl)) + continue; + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffsetInLayoutClass = + OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); + } + + DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); + } +} + +void +VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + // Itanium C++ ABI 2.5.2: + // Then come the virtual base virtual tables, also in inheritance graph + // order, and again excluding primary bases (which share virtual tables with + // the classes for which they are primary). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this base needs a vtable. (If it's virtual, not a primary base + // of some other class, and we haven't visited it before). + if (I->isVirtual() && BaseDecl->isDynamicClass() && + !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + CharUnits BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + CharUnits BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutPrimaryAndSecondaryVTables( + BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsMorallyVirtual=*/true, + /*BaseIsVirtualInLayoutClass=*/true, + BaseOffsetInLayoutClass); + } + + // We only need to check the base for virtual base vtables if it actually + // has virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVTablesForVirtualBases(BaseDecl, VBases); + } +} + +/// dumpLayout - Dump the vtable layout. +void VTableBuilder::dumpLayout(raw_ostream& Out) { + + if (isBuildingConstructorVTable()) { + Out << "Construction vtable for ('"; + Out << MostDerivedClass->getQualifiedNameAsString() << "', "; + Out << MostDerivedClassOffset.getQuantity() << ") in '"; + Out << LayoutClass->getQualifiedNameAsString(); + } else { + Out << "Vtable for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + } + Out << "' (" << Components.size() << " entries).\n"; + + // Iterate through the address points and insert them into a new map where + // they are keyed by the index and not the base object. + // Since an address point can be shared by multiple subobjects, we use an + // STL multimap. + std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex; + for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), + E = AddressPoints.end(); I != E; ++I) { + const BaseSubobject& Base = I->first; + uint64_t Index = I->second; + + AddressPointsByIndex.insert(std::make_pair(Index, Base)); + } + + for (unsigned I = 0, E = Components.size(); I != E; ++I) { + uint64_t Index = I; + + Out << llvm::format("%4d | ", I); + + const VTableComponent &Component = Components[I]; + + // Dump the component. + switch (Component.getKind()) { + + case VTableComponent::CK_VCallOffset: + Out << "vcall_offset (" + << Component.getVCallOffset().getQuantity() + << ")"; + break; + + case VTableComponent::CK_VBaseOffset: + Out << "vbase_offset (" + << Component.getVBaseOffset().getQuantity() + << ")"; + break; + + case VTableComponent::CK_OffsetToTop: + Out << "offset_to_top (" + << Component.getOffsetToTop().getQuantity() + << ")"; + break; + + case VTableComponent::CK_RTTI: + Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; + break; + + case VTableComponent::CK_FunctionPointer: { + const CXXMethodDecl *MD = Component.getFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << Str; + if (MD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this function pointer has a return adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "\n [return adjustment: "; + Out << Thunk.Return.NonVirtual << " non-virtual"; + + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + Out << ']'; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { + bool IsComplete = + Component.getKind() == VTableComponent::CK_CompleteDtorPointer; + + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString(); + if (IsComplete) + Out << "() [complete]"; + else + Out << "() [deleting]"; + + if (DD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this destructor has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_UnusedFunctionPointer: { + const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << "[unused] " << Str; + if (MD->isPure()) + Out << " [pure]"; + } + + } + + Out << '\n'; + + // Dump the next address point. + uint64_t NextIndex = Index + 1; + if (AddressPointsByIndex.count(NextIndex)) { + if (AddressPointsByIndex.count(NextIndex) == 1) { + const BaseSubobject &Base = + AddressPointsByIndex.find(NextIndex)->second; + + Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); + Out << ", " << Base.getBaseOffset().getQuantity(); + Out << ") vtable address --\n"; + } else { + CharUnits BaseOffset = + AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); + + // We store the class names in a set to get a stable order. + std::set<std::string> ClassNames; + for (std::multimap<uint64_t, BaseSubobject>::const_iterator I = + AddressPointsByIndex.lower_bound(NextIndex), E = + AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { + assert(I->second.getBaseOffset() == BaseOffset && + "Invalid base offset!"); + const CXXRecordDecl *RD = I->second.getBase(); + ClassNames.insert(RD->getQualifiedNameAsString()); + } + + for (std::set<std::string>::const_iterator I = ClassNames.begin(), + E = ClassNames.end(); I != E; ++I) { + Out << " -- (" << *I; + Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n"; + } + } + } + } + + Out << '\n'; + + if (isBuildingConstructorVTable()) + return; + + if (MostDerivedClass->getNumVBases()) { + // We store the virtual base class names and their offsets in a map to get + // a stable order. + + std::map<std::string, CharUnits> ClassNamesAndOffsets; + for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), + E = VBaseOffsetOffsets.end(); I != E; ++I) { + std::string ClassName = I->first->getQualifiedNameAsString(); + CharUnits OffsetOffset = I->second; + ClassNamesAndOffsets.insert( + std::make_pair(ClassName, OffsetOffset)); + } + + Out << "Virtual base offset offsets for '"; + Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; + Out << ClassNamesAndOffsets.size(); + Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; + + for (std::map<std::string, CharUnits>::const_iterator I = + ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); + I != E; ++I) + Out << " " << I->first << " | " << I->second.getQuantity() << '\n'; + + Out << "\n"; + } + + if (!Thunks.empty()) { + // We store the method names in a map to get a stable order. + std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; + + for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); + I != E; ++I) { + const CXXMethodDecl *MD = I->first; + std::string MethodName = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + + MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); + } + + for (std::map<std::string, const CXXMethodDecl *>::const_iterator I = + MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); + I != E; ++I) { + const std::string &MethodName = I->first; + const CXXMethodDecl *MD = I->second; + + ThunkInfoVectorTy ThunksVector = Thunks[MD]; + std::sort(ThunksVector.begin(), ThunksVector.end()); + + Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); + Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; + + for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { + const ThunkInfo &Thunk = ThunksVector[I]; + + Out << llvm::format("%4d | ", I); + + // If this function pointer has a return pointer adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "return adjustment: " << Thunk.This.NonVirtual; + Out << " non-virtual"; + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + if (!Thunk.This.isEmpty()) + Out << "\n "; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + } + + Out << '\n'; + } + + Out << '\n'; + } + } + + // Compute the vtable indices for all the member functions. + // Store them in a map keyed by the index so we'll get a sorted table. + std::map<uint64_t, std::string> IndicesMap; + + for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(), + e = MostDerivedClass->method_end(); i != e; ++i) { + const CXXMethodDecl *MD = *i; + + // We only want virtual member functions. + if (!MD->isVirtual()) + continue; + + std::string MethodName = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] = + MethodName + " [complete]"; + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] = + MethodName + " [deleting]"; + } else { + IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; + } + } + + // Print the vtable indices for all the member functions. + if (!IndicesMap.empty()) { + Out << "VTable indices for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + Out << "' (" << IndicesMap.size() << " entries).\n"; + + for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(), + E = IndicesMap.end(); I != E; ++I) { + uint64_t VTableIndex = I->first; + const std::string &MethodName = I->second; + + Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n'; + } + } + + Out << '\n'; +} + +} + +VTableLayout::VTableLayout(uint64_t NumVTableComponents, + const VTableComponent *VTableComponents, + uint64_t NumVTableThunks, + const VTableThunkTy *VTableThunks, + const AddressPointsMapTy &AddressPoints) + : NumVTableComponents(NumVTableComponents), + VTableComponents(new VTableComponent[NumVTableComponents]), + NumVTableThunks(NumVTableThunks), + VTableThunks(new VTableThunkTy[NumVTableThunks]), + AddressPoints(AddressPoints) { + std::copy(VTableComponents, VTableComponents+NumVTableComponents, + this->VTableComponents); + std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks); +} + +VTableLayout::~VTableLayout() { + delete[] VTableComponents; +} + +VTableContext::~VTableContext() { + llvm::DeleteContainerSeconds(VTableLayouts); +} + +static void +CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, + VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + return; + + CollectPrimaryBases(PrimaryBase, Context, PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + llvm_unreachable("Found a duplicate primary base!"); +} + +void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { + + // Itanium C++ ABI 2.5.2: + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. + // + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. + + int64_t CurrentIndex = 0; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (PrimaryBase) { + assert(PrimaryBase->isCompleteDefinition() && + "Should have the definition decl of the primary base!"); + + // Since the record decl shares its vtable pointer with the primary base + // we need to start counting at the end of the primary base's vtable. + CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); + } + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + CollectPrimaryBases(RD, Context, PrimaryBases); + + const CXXDestructorDecl *ImplicitVirtualDtor = 0; + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + const CXXMethodDecl *MD = *i; + + // We only want virtual methods. + if (!MD->isVirtual()) + continue; + + // Check if this method overrides a method in the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + if (ComputeReturnAdjustmentBaseOffset(Context, MD, + OverriddenMD).isEmpty()) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + const CXXDestructorDecl *OverriddenDD = + cast<CXXDestructorDecl>(OverriddenMD); + + // Add both the complete and deleting entries. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + } else { + MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); + } + + // We don't need to add an entry for this method. + continue; + } + } + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + if (MD->isImplicit()) { + assert(!ImplicitVirtualDtor && + "Did already see an implicit virtual dtor!"); + ImplicitVirtualDtor = DD; + continue; + } + + // Add the complete dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + + // Add the deleting dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + } else { + // Add the entry. + MethodVTableIndices[MD] = CurrentIndex++; + } + } + + if (ImplicitVirtualDtor) { + // Itanium C++ ABI 2.5.2: + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. + + // Add the complete dtor. + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = + CurrentIndex++; + + // Add the deleting dtor. + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = + CurrentIndex++; + } + + NumVirtualFunctionPointers[RD] = CurrentIndex; +} + +uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { + llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + NumVirtualFunctionPointers.find(RD); + if (I != NumVirtualFunctionPointers.end()) + return I->second; + + ComputeMethodVTableIndices(RD); + + I = NumVirtualFunctionPointers.find(RD); + assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); + return I->second; +} + +uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) { + MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); + if (I != MethodVTableIndices.end()) + return I->second; + + const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); + + ComputeMethodVTableIndices(RD); + + I = MethodVTableIndices.find(GD); + assert(I != MethodVTableIndices.end() && "Did not find index!"); + return I->second; +} + +CharUnits +VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { + ClassPairTy ClassPair(RD, VBase); + + VirtualBaseClassOffsetOffsetsMapTy::iterator I = + VirtualBaseClassOffsetOffsets.find(ClassPair); + if (I != VirtualBaseClassOffsetOffsets.end()) + return I->second; + + VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, + BaseSubobject(RD, CharUnits::Zero()), + /*BaseIsVirtual=*/false, + /*OffsetInLayoutClass=*/CharUnits::Zero()); + + for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassOffsetOffsets.insert( + std::make_pair(ClassPair, I->second)); + } + + I = VirtualBaseClassOffsetOffsets.find(ClassPair); + assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); + + return I->second; +} + +static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) { + SmallVector<VTableLayout::VTableThunkTy, 1> + VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); + std::sort(VTableThunks.begin(), VTableThunks.end()); + + return new VTableLayout(Builder.getNumVTableComponents(), + Builder.vtable_component_begin(), + VTableThunks.size(), + VTableThunks.data(), + Builder.getAddressPoints()); +} + +void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { + const VTableLayout *&Entry = VTableLayouts[RD]; + + // Check if we've computed this information before. + if (Entry) + return; + + VTableBuilder Builder(*this, RD, CharUnits::Zero(), + /*MostDerivedClassIsVirtual=*/0, RD); + Entry = CreateVTableLayout(Builder); + + // Add the known thunks. + Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); + + // If we don't have the vbase information for this class, insert it. + // getVirtualBaseOffsetOffset will compute it separately without computing + // the rest of the vtable related information. + if (!RD->getNumVBases()) + return; + + const RecordType *VBaseRT = + RD->vbases_begin()->getType()->getAs<RecordType>(); + const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl()); + + if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) + return; + + for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + } +} + +VTableLayout *VTableContext::createConstructionVTableLayout( + const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass) { + VTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset, + MostDerivedClassIsVirtual, LayoutClass); + return CreateVTableLayout(Builder); +} diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp index 678f02f..3dd194b 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp @@ -24,25 +24,44 @@ #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Support/BumpVector.h" +#include "clang/Analysis/Support/SaveAndRestore.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; +typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap; + AnalysisContext::AnalysisContext(const Decl *d, idx::TranslationUnit *tu, - bool useUnoptimizedCFG, - bool addehedges, - bool addImplicitDtors, - bool addInitializers) + const CFG::BuildOptions &buildOptions) : D(d), TU(tu), + cfgBuildOptions(buildOptions), forcedBlkExprs(0), - builtCFG(false), builtCompleteCFG(false), - useUnoptimizedCFG(useUnoptimizedCFG), - ReferencedBlockVars(0) -{ + builtCFG(false), + builtCompleteCFG(false), + ReferencedBlockVars(0), + ManagedAnalyses(0) +{ + cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; +} + +AnalysisContext::AnalysisContext(const Decl *d, + idx::TranslationUnit *tu) +: D(d), TU(tu), + forcedBlkExprs(0), + builtCFG(false), + builtCompleteCFG(false), + ReferencedBlockVars(0), + ManagedAnalyses(0) +{ cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; - cfgBuildOptions.AddEHEdges = addehedges; +} + +AnalysisContextManager::AnalysisContextManager(bool useUnoptimizedCFG, + bool addImplicitDtors, + bool addInitializers) { + cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; } @@ -53,7 +72,7 @@ void AnalysisContextManager::clear() { Contexts.clear(); } -Stmt *AnalysisContext::getBody() { +Stmt *AnalysisContext::getBody() const { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) return FD->getBody(); else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) @@ -95,7 +114,7 @@ AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) { } CFG *AnalysisContext::getCFG() { - if (useUnoptimizedCFG) + if (!cfgBuildOptions.PruneTriviallyFalseEdges) return getUnoptimizedCFG(); if (!builtCFG) { @@ -110,9 +129,10 @@ CFG *AnalysisContext::getCFG() { CFG *AnalysisContext::getUnoptimizedCFG() { if (!builtCompleteCFG) { - CFG::BuildOptions B = cfgBuildOptions; - B.PruneTriviallyFalseEdges = false; - completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), B)); + SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges, + false); + completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), + cfgBuildOptions)); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCompleteCFG = true; @@ -160,36 +180,11 @@ PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() { return PCA.get(); } -LiveVariables *AnalysisContext::getLiveVariables() { - if (!liveness) { - if (CFG *c = getCFG()) { - liveness.reset(new LiveVariables(*this)); - liveness->runOnCFG(*c); - liveness->runOnAllBlocks(*c, 0, true); - } - } - - return liveness.get(); -} - -LiveVariables *AnalysisContext::getRelaxedLiveVariables() { - if (!relaxedLiveness) - if (CFG *c = getCFG()) { - relaxedLiveness.reset(new LiveVariables(*this, false)); - relaxedLiveness->runOnCFG(*c); - relaxedLiveness->runOnAllBlocks(*c, 0, true); - } - - return relaxedLiveness.get(); -} - AnalysisContext *AnalysisContextManager::getContext(const Decl *D, idx::TranslationUnit *TU) { AnalysisContext *&AC = Contexts[D]; if (!AC) - AC = new AnalysisContext(D, TU, UseUnoptimizedCFG, false, - AddImplicitDtors, AddInitializers); - + AC = new AnalysisContext(D, TU, cfgBuildOptions); return AC; } @@ -201,7 +196,7 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck, AnalysisContext *ctx, const LocationContext *parent, - const void* data) { + const void *data) { ID.AddInteger(ck); ID.AddPointer(ctx); ID.AddPointer(parent); @@ -392,13 +387,29 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { return std::make_pair(V->begin(), V->end()); } +ManagedAnalysis *&AnalysisContext::getAnalysisImpl(const void *tag) { + if (!ManagedAnalyses) + ManagedAnalyses = new ManagedAnalysisMap(); + ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; + return (*M)[tag]; +} + //===----------------------------------------------------------------------===// // Cleanup. //===----------------------------------------------------------------------===// +ManagedAnalysis::~ManagedAnalysis() {} + AnalysisContext::~AnalysisContext() { delete forcedBlkExprs; delete ReferencedBlockVars; + // Release the managed analyses. + if (ManagedAnalyses) { + ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; + for (ManagedAnalysisMap::iterator I = M->begin(), E = M->end(); I!=E; ++I) + delete I->second; + delete M; + } } AnalysisContextManager::~AnalysisContextManager() { diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index f231c14..83c7384 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp @@ -29,9 +29,9 @@ using namespace clang; namespace { -static SourceLocation GetEndLoc(Decl* D) { - if (VarDecl* VD = dyn_cast<VarDecl>(D)) - if (Expr* Ex = VD->getInit()) +static SourceLocation GetEndLoc(Decl *D) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (Expr *Ex = VD->getInit()) return Ex->getSourceRange().getEnd(); return D->getLocation(); } @@ -121,16 +121,16 @@ public: *this = Scope->Prev; } - VarDecl* const* operator->() const { + VarDecl *const* operator->() const { assert (Scope && "Dereferencing invalid iterator is not allowed"); assert (VarIter != 0 && "Iterator has invalid value of VarIter member"); return &Scope->Vars[VarIter - 1]; } - VarDecl* operator*() const { + VarDecl *operator*() const { return *this->operator->(); } - const_iterator& operator++() { + const_iterator &operator++() { if (!Scope) return *this; @@ -146,10 +146,10 @@ public: return P; } - bool operator==(const const_iterator& rhs) const { + bool operator==(const const_iterator &rhs) const { return Scope == rhs.Scope && VarIter == rhs.VarIter; } - bool operator!=(const const_iterator& rhs) const { + bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } @@ -179,7 +179,7 @@ public: /// Begin of scope in direction of CFG building (backwards). const_iterator begin() const { return const_iterator(*this, Vars.size()); } - void addVar(VarDecl* VD) { + void addVar(VarDecl *VD) { Vars.push_back(VD, ctx); } }; @@ -205,7 +205,7 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { /// and LocalScope::const_iterator that specifies position in LocalScope graph. struct BlockScopePosPair { BlockScopePosPair() : block(0) {} - BlockScopePosPair(CFGBlock* b, LocalScope::const_iterator scopePos) + BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos) : block(b), scopePosition(scopePos) {} CFGBlock *block; @@ -252,13 +252,13 @@ class CFGBuilder { ASTContext *Context; llvm::OwningPtr<CFG> cfg; - CFGBlock* Block; - CFGBlock* Succ; + CFGBlock *Block; + CFGBlock *Succ; JumpTarget ContinueJumpTarget; JumpTarget BreakJumpTarget; - CFGBlock* SwitchTerminatedBlock; - CFGBlock* DefaultCaseBlock; - CFGBlock* TryTerminatedBlock; + CFGBlock *SwitchTerminatedBlock; + CFGBlock *DefaultCaseBlock; + CFGBlock *TryTerminatedBlock; // Current position in local scope. LocalScope::const_iterator ScopePos; @@ -305,7 +305,7 @@ private: // Visitors to walk an AST and construct the CFG. CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); - CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); + CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, @@ -328,11 +328,11 @@ private: AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); CFGBlock *VisitDeclStmt(DeclStmt *DS); - CFGBlock *VisitDeclSubExpr(DeclStmt* DS); + CFGBlock *VisitDeclSubExpr(DeclStmt *DS); CFGBlock *VisitDefaultStmt(DefaultStmt *D); CFGBlock *VisitDoStmt(DoStmt *D); CFGBlock *VisitForStmt(ForStmt *F); - CFGBlock *VisitGotoStmt(GotoStmt* G); + CFGBlock *VisitGotoStmt(GotoStmt *G); CFGBlock *VisitIfStmt(IfStmt *I); CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); @@ -343,7 +343,7 @@ private: CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); - CFGBlock *VisitReturnStmt(ReturnStmt* R); + CFGBlock *VisitReturnStmt(ReturnStmt *R); CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, AddStmtChoice asc); CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); @@ -353,7 +353,7 @@ private: CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); - CFGBlock *VisitChildren(Stmt* S); + CFGBlock *VisitChildren(Stmt *S); // Visitors to walk an AST and generate destructors of temporaries in // full expression. @@ -367,34 +367,35 @@ private: bool BindToTemporary); // NYS == Not Yet Supported - CFGBlock* NYS() { + CFGBlock *NYS() { badCFG = true; return Block; } void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); + CFGBlock *createNoReturnBlock(); CFGBlock *addStmt(Stmt *S) { return Visit(S, AddStmtChoice::AlwaysAdd); } CFGBlock *addInitializer(CXXCtorInitializer *I); void addAutomaticObjDtors(LocalScope::const_iterator B, - LocalScope::const_iterator E, Stmt* S); + LocalScope::const_iterator E, Stmt *S); void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); // Local scopes creation. LocalScope* createOrReuseLocalScope(LocalScope* Scope); - void addLocalScopeForStmt(Stmt* S); - LocalScope* addLocalScopeForDeclStmt(DeclStmt* DS, LocalScope* Scope = NULL); - LocalScope* addLocalScopeForVarDecl(VarDecl* VD, LocalScope* Scope = NULL); + void addLocalScopeForStmt(Stmt *S); + LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL); + LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL); - void addLocalScopeAndDtors(Stmt* S); + void addLocalScopeAndDtors(Stmt *S); // Interface to CFGBlock - adding CFGElements. void appendStmt(CFGBlock *B, const Stmt *S) { - if (alwaysAdd(S)) + if (alwaysAdd(S) && cachedEntry) cachedEntry->second = B; // All block-level expressions should have already been IgnoreParens()ed. @@ -413,12 +414,11 @@ private: void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) { B->appendTemporaryDtor(E, cfg->getBumpVectorContext()); } + void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) { + B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext()); + } - void insertAutomaticObjDtors(CFGBlock* Blk, CFGBlock::iterator I, - LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S); - void appendAutomaticObjDtors(CFGBlock* Blk, LocalScope::const_iterator B, - LocalScope::const_iterator E, Stmt* S); - void prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk, + void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E); void addSuccessor(CFGBlock *B, CFGBlock *S) { @@ -437,20 +437,12 @@ private: /// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 /// if we can evaluate to a known value, otherwise return -1. TryResult tryEvaluateBool(Expr *S) { - Expr::EvalResult Result; - if (!tryEvaluate(S, Result)) + bool Result; + if (!BuildOpts.PruneTriviallyFalseEdges || + S->isTypeDependent() || S->isValueDependent() || + !S->EvaluateAsBooleanCondition(Result, *Context)) return TryResult(); - - if (Result.Val.isInt()) - return Result.Val.getInt().getBoolValue(); - - if (Result.Val.isLValue()) { - const Expr *e = Result.Val.getLValueBase(); - const CharUnits &c = Result.Val.getLValueOffset(); - if (!e && c.isZero()) - return false; - } - return TryResult(); + return Result; } }; @@ -461,15 +453,17 @@ inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, } bool CFGBuilder::alwaysAdd(const Stmt *stmt) { + bool shouldAdd = BuildOpts.alwaysAdd(stmt); + if (!BuildOpts.forcedBlkExprs) - return false; + return shouldAdd; if (lastLookup == stmt) { if (cachedEntry) { assert(cachedEntry->first == stmt); return true; } - return false; + return shouldAdd; } lastLookup = stmt; @@ -480,13 +474,13 @@ bool CFGBuilder::alwaysAdd(const Stmt *stmt) { if (!fb) { // No need to update 'cachedEntry', since it will always be null. assert(cachedEntry == 0); - return false; + return shouldAdd; } CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt); if (itr == fb->end()) { cachedEntry = 0; - return false; + return shouldAdd; } cachedEntry = &*itr; @@ -512,7 +506,7 @@ static const VariableArrayType *FindVA(const Type *t) { /// body (compound statement). The ownership of the returned CFG is /// transferred to the caller. If CFG construction fails, this method returns /// NULL. -CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) { +CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { assert(cfg.get()); if (!Statement) return NULL; @@ -552,8 +546,8 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) { for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), E = BackpatchBlocks.end(); I != E; ++I ) { - CFGBlock* B = I->block; - GotoStmt* G = cast<GotoStmt>(B->getTerminator()); + CFGBlock *B = I->block; + GotoStmt *G = cast<GotoStmt>(B->getTerminator()); LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); // If there is no target for the goto, then we are looking at an @@ -567,7 +561,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) { } // Add successors to the Indirect Goto Dispatch block (if we have one). - if (CFGBlock* B = cfg->getIndirectGotoBlock()) + if (CFGBlock *B = cfg->getIndirectGotoBlock()) for (LabelSetTy::iterator I = AddressTakenLabels.begin(), E = AddressTakenLabels.end(); I != E; ++I ) { @@ -589,13 +583,23 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) { /// createBlock - Used to lazily create blocks that are connected /// to the current (global) succcessor. -CFGBlock* CFGBuilder::createBlock(bool add_successor) { - CFGBlock* B = cfg->createBlock(); +CFGBlock *CFGBuilder::createBlock(bool add_successor) { + CFGBlock *B = cfg->createBlock(); if (add_successor && Succ) addSuccessor(B, Succ); return B; } +/// createNoReturnBlock - Used to create a block is a 'noreturn' point in the +/// CFG. It is *not* connected to the current (global) successor, and instead +/// directly tied to the exit block in order to be reachable. +CFGBlock *CFGBuilder::createNoReturnBlock() { + CFGBlock *B = createBlock(false); + B->setHasNoReturnElement(); + addSuccessor(B, &cfg->getExit()); + return B; +} + /// addInitializer - Add C++ base or member initializer element to CFG. CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { if (!BuildOpts.AddInitializers) @@ -638,15 +642,41 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { /// for objects in range of local scope positions. Use S as trigger statement /// for destructors. void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, - LocalScope::const_iterator E, Stmt* S) { + LocalScope::const_iterator E, Stmt *S) { if (!BuildOpts.AddImplicitDtors) return; if (B == E) return; - autoCreateBlock(); - appendAutomaticObjDtors(Block, B, E, S); + CFGBlock::iterator InsertPos; + + // We need to append the destructors in reverse order, but any one of them + // may be a no-return destructor which changes the CFG. As a result, buffer + // this sequence up and replay them in reverse order when appending onto the + // CFGBlock(s). + SmallVector<VarDecl*, 10> Decls; + Decls.reserve(B.distance(E)); + for (LocalScope::const_iterator I = B; I != E; ++I) + Decls.push_back(*I); + + for (SmallVectorImpl<VarDecl*>::reverse_iterator I = Decls.rbegin(), + E = Decls.rend(); + I != E; ++I) { + // If this destructor is marked as a no-return destructor, we need to + // create a new block for the destructor which does not have as a successor + // anything built thus far: control won't flow out of this block. + QualType Ty = (*I)->getType().getNonReferenceType(); + if (const ArrayType *AT = Context->getAsArrayType(Ty)) + Ty = AT->getElementType(); + const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); + if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) + Block = createNoReturnBlock(); + else + autoCreateBlock(); + + appendAutomaticObjDtor(Block, *I, S); + } } /// addImplicitDtorsForDestructor - Add implicit destructors generated for @@ -711,7 +741,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement /// that should create implicit scope (e.g. if/else substatements). -void CFGBuilder::addLocalScopeForStmt(Stmt* S) { +void CFGBuilder::addLocalScopeForStmt(Stmt *S) { if (!BuildOpts.AddImplicitDtors) return; @@ -721,9 +751,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) { if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end() ; BI != BE; ++BI) { - Stmt *SI = *BI; - if (LabelStmt *LS = dyn_cast<LabelStmt>(SI)) - SI = LS->getSubStmt(); + Stmt *SI = (*BI)->stripLabelLikeStatements(); if (DeclStmt *DS = dyn_cast<DeclStmt>(SI)) Scope = addLocalScopeForDeclStmt(DS, Scope); } @@ -732,22 +760,20 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) { // For any other statement scope will be implicit and as such will be // interesting only for DeclStmt. - if (LabelStmt *LS = dyn_cast<LabelStmt>(S)) - S = LS->getSubStmt(); - if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) + if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements())) addLocalScopeForDeclStmt(DS); } /// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will /// reuse Scope if not NULL. -LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt* DS, +LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope) { if (!BuildOpts.AddImplicitDtors) return Scope; for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end() ; DI != DE; ++DI) { - if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) + if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) Scope = addLocalScopeForVarDecl(VD, Scope); } return Scope; @@ -756,7 +782,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt* DS, /// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will /// create add scope for automatic objects and temporary objects bound to /// const reference. Will reuse Scope if not NULL. -LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD, +LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope) { if (!BuildOpts.AddImplicitDtors) return Scope; @@ -788,7 +814,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD, } // Check if type is a C++ class with non-trivial destructor. - if (const CXXRecordDecl* CD = QT->getAsCXXRecordDecl()) + if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) if (!CD->hasTrivialDestructor()) { // Add the variable to scope Scope = createOrReuseLocalScope(Scope); @@ -800,7 +826,7 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl* VD, /// addLocalScopeAndDtors - For given statement add local scope for it and /// add destructors that will cleanup the scope. Will reuse Scope if not NULL. -void CFGBuilder::addLocalScopeAndDtors(Stmt* S) { +void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { if (!BuildOpts.AddImplicitDtors) return; @@ -809,40 +835,27 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt* S) { addAutomaticObjDtors(ScopePos, scopeBeginPos, S); } -/// insertAutomaticObjDtors - Insert destructor CFGElements for variables with -/// automatic storage duration to CFGBlock's elements vector. Insertion will be -/// performed in place specified with iterator. -void CFGBuilder::insertAutomaticObjDtors(CFGBlock* Blk, CFGBlock::iterator I, - LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S) { - BumpVectorContext& C = cfg->getBumpVectorContext(); - I = Blk->beginAutomaticObjDtorsInsert(I, B.distance(E), C); - while (B != E) - I = Blk->insertAutomaticObjDtor(I, *B++, S); -} - -/// appendAutomaticObjDtors - Append destructor CFGElements for variables with -/// automatic storage duration to CFGBlock's elements vector. Elements will be -/// appended to physical end of the vector which happens to be logical -/// beginning. -void CFGBuilder::appendAutomaticObjDtors(CFGBlock* Blk, - LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S) { - insertAutomaticObjDtors(Blk, Blk->begin(), B, E, S); -} - /// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for /// variables with automatic storage duration to CFGBlock's elements vector. /// Elements will be prepended to physical beginning of the vector which /// happens to be logical end. Use blocks terminator as statement that specifies /// destructors call site. -void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk, +/// FIXME: This mechanism for adding automatic destructors doesn't handle +/// no-return destructors properly. +void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { - insertAutomaticObjDtors(Blk, Blk->end(), B, E, Blk->getTerminator()); + BumpVectorContext &C = cfg->getBumpVectorContext(); + CFGBlock::iterator InsertPos + = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C); + for (LocalScope::const_iterator I = B; I != E; ++I) + InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I, + Blk->getTerminator()); } /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). -CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { +CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { if (!S) { badCFG = true; return 0; @@ -996,7 +1009,7 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { } /// VisitChildren - Visit the children of a Stmt. -CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) { +CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) { CFGBlock *lastBlock = Block; for (Stmt::child_range I = Terminator->children(); I; ++I) if (Stmt *child = *I) @@ -1031,20 +1044,20 @@ CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc) { if (B->isLogicalOp()) { // && or || - CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); appendStmt(ConfluenceBlock, B); if (badCFG) return 0; // create the block evaluating the LHS - CFGBlock* LHSBlock = createBlock(false); + CFGBlock *LHSBlock = createBlock(false); LHSBlock->setTerminator(B); // create the block evaluating the RHS Succ = ConfluenceBlock; Block = NULL; - CFGBlock* RHSBlock = addStmt(B->getRHS()); + CFGBlock *RHSBlock = addStmt(B->getRHS()); if (RHSBlock) { if (badCFG) @@ -1191,13 +1204,13 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { return 0; } - Block = createBlock(!NoReturn); + if (NoReturn) + Block = createNoReturnBlock(); + else + Block = createBlock(); + appendStmt(Block, C); - if (NoReturn) { - // Wire this to the exit block directly. - addSuccessor(Block, &cfg->getExit()); - } if (AddEHEdge) { // Add exceptional edges. if (TryTerminatedBlock) @@ -1211,7 +1224,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc) { - CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); appendStmt(ConfluenceBlock, C); if (badCFG) return 0; @@ -1219,13 +1232,13 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true); Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = Visit(C->getLHS(), alwaysAdd); + CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd); if (badCFG) return 0; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* RHSBlock = Visit(C->getRHS(), alwaysAdd); + CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd); if (badCFG) return 0; @@ -1239,9 +1252,9 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, } -CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { +CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { addLocalScopeAndDtors(C); - CFGBlock* LastBlock = Block; + CFGBlock *LastBlock = Block; for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); I != E; ++I ) { @@ -1264,7 +1277,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, // Create the confluence block that will "merge" the results of the ternary // expression. - CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); appendStmt(ConfluenceBlock, C); if (badCFG) return 0; @@ -1277,7 +1290,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, // e.g: x ?: y is shorthand for: x ? x : y; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = 0; + CFGBlock *LHSBlock = 0; const Expr *trueExpr = C->getTrueExpr(); if (trueExpr != opaqueValue) { LHSBlock = Visit(C->getTrueExpr(), alwaysAdd); @@ -1290,7 +1303,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, // Create the block for the RHS expression. Succ = ConfluenceBlock; - CFGBlock* RHSBlock = Visit(C->getFalseExpr(), alwaysAdd); + CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd); if (badCFG) return 0; @@ -1331,7 +1344,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { CFGBlock *B = 0; // FIXME: Add a reverse iterator for DeclStmt to avoid this extra copy. - typedef llvm::SmallVector<Decl*,10> BufTy; + typedef SmallVector<Decl*,10> BufTy; BufTy Buf(DS->decl_begin(), DS->decl_end()); for (BufTy::reverse_iterator I = Buf.rbegin(), E = Buf.rend(); I != E; ++I) { @@ -1355,7 +1368,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { /// VisitDeclSubExpr - Utility method to add block-level expressions for /// DeclStmts and initializers in them. -CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) { +CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { assert(DS->isSingleDecl() && "Can handle single declarations only."); Decl *D = DS->getSingleDecl(); @@ -1414,7 +1427,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) { return Block; } -CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { +CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { // We may see an if statement in the middle of a basic block, or it may be the // first statement we are processing. In either case, we create a new basic // block. First, we create the blocks for the then...else statements, and @@ -1428,7 +1441,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { // Create local scope for possible condition variable. // Store scope position. Add implicit destructor. - if (VarDecl* VD = I->getConditionVariable()) { + if (VarDecl *VD = I->getConditionVariable()) { LocalScope::const_iterator BeginScopePos = ScopePos; addLocalScopeForVarDecl(VD); addAutomaticObjDtors(ScopePos, BeginScopePos, I); @@ -1443,9 +1456,9 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { } // Process the false branch. - CFGBlock* ElseBlock = Succ; + CFGBlock *ElseBlock = Succ; - if (Stmt* Else = I->getElse()) { + if (Stmt *Else = I->getElse()) { SaveAndRestore<CFGBlock*> sv(Succ); // NULL out Block so that the recursive call to Visit will @@ -1468,9 +1481,9 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { } // Process the true branch. - CFGBlock* ThenBlock; + CFGBlock *ThenBlock; { - Stmt* Then = I->getThen(); + Stmt *Then = I->getThen(); assert(Then); SaveAndRestore<CFGBlock*> sv(Succ); Block = NULL; @@ -1526,7 +1539,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { } -CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { +CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { // If we were in the middle of a block we stop processing that block. // // NOTE: If a "return" appears in the middle of a block, this means that the @@ -1546,7 +1559,7 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { return VisitStmt(R, AddStmtChoice::AlwaysAdd); } -CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt *L) { +CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) { // Get the block of the labeled statement. Add it to our map. addStmt(L->getSubStmt()); CFGBlock *LabelBlock = Block; @@ -1575,7 +1588,7 @@ CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt *L) { return LabelBlock; } -CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { +CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) { // Goto is a control-flow statement. Thus we stop processing the current // block and create a new one. @@ -1597,8 +1610,8 @@ CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { return Block; } -CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { - CFGBlock* LoopSuccessor = NULL; +CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { + CFGBlock *LoopSuccessor = NULL; // Save local scope position because in case of condition variable ScopePos // won't be restored when traversing AST. @@ -1607,11 +1620,11 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Create local scope for init statement and possible condition variable. // Add destructor for init statement and condition variable. // Store scope position for continue statement. - if (Stmt* Init = F->getInit()) + if (Stmt *Init = F->getInit()) addLocalScopeForStmt(Init); LocalScope::const_iterator LoopBeginScopePos = ScopePos; - if (VarDecl* VD = F->getConditionVariable()) + if (VarDecl *VD = F->getConditionVariable()) addLocalScopeForVarDecl(VD); LocalScope::const_iterator ContinueScopePos = ScopePos; @@ -1634,15 +1647,15 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Because of short-circuit evaluation, the condition of the loop can span // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that // evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; + CFGBlock *ExitConditionBlock = createBlock(false); + CFGBlock *EntryConditionBlock = ExitConditionBlock; // Set the terminator for the "exit" condition block. ExitConditionBlock->setTerminator(F); // Now add the actual condition to the condition block. Because the condition // itself may contain control-flow, new blocks may be created. - if (Stmt* C = F->getCond()) { + if (Stmt *C = F->getCond()) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); if (badCFG) @@ -1691,7 +1704,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Loop body should end with destructor of Condition variable (if any). addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); - if (Stmt* I = F->getInc()) { + if (Stmt *I = F->getInc()) { // Generate increment code in its own basic block. This is the target of // continue statements. Succ = addStmt(I); @@ -1723,7 +1736,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Now populate the body block, and in the process create new blocks as we // walk the body of the loop. - CFGBlock* BodyBlock = addStmt(F->getBody()); + CFGBlock *BodyBlock = addStmt(F->getBody()); if (!BodyBlock) BodyBlock = ContinueJumpTarget.block;//can happen for "for (...;...;...);" @@ -1740,7 +1753,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // If the loop contains initialization, create a new block for those // statements. This block can also contain statements that precede the loop. - if (Stmt* I = F->getInit()) { + if (Stmt *I = F->getInit()) { Block = createBlock(); return addStmt(I); } @@ -1760,7 +1773,7 @@ CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { return Visit(M->getBase()); } -CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { +CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { // Objective-C fast enumeration 'for' statements: // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC // @@ -1793,7 +1806,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // a DeclStmt and the other returns a DeclRefExpr. // - CFGBlock* LoopSuccessor = 0; + CFGBlock *LoopSuccessor = 0; if (Block) { if (badCFG) @@ -1804,8 +1817,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { LoopSuccessor = Succ; // Build the condition blocks. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; + CFGBlock *ExitConditionBlock = createBlock(false); // Set the terminator for the "exit" condition block. ExitConditionBlock->setTerminator(S); @@ -1819,7 +1831,8 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Walk the 'element' expression to see if there are any side-effects. We // generate new blocks as necessary. We DON'T add the statement by default to // the CFG unless it contains control-flow. - EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd); + CFGBlock *EntryConditionBlock = Visit(S->getElement(), + AddStmtChoice::NotAlwaysAdd); if (Block) { if (badCFG) return 0; @@ -1840,7 +1853,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos); - CFGBlock* BodyBlock = addStmt(S->getBody()); + CFGBlock *BodyBlock = addStmt(S->getBody()); if (!BodyBlock) BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;" @@ -1862,7 +1875,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { return addStmt(S->getCollection()); } -CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { +CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { // FIXME: Add locking 'primitives' to CFG for @synchronized. // Inline the body. @@ -1886,13 +1899,13 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { return addStmt(S->getSynchExpr()); } -CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) { +CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { // FIXME return NYS(); } -CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { - CFGBlock* LoopSuccessor = NULL; +CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { + CFGBlock *LoopSuccessor = NULL; // Save local scope position because in case of condition variable ScopePos // won't be restored when traversing AST. @@ -1901,7 +1914,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { // Create local scope for possible condition variable. // Store scope position for continue statement. LocalScope::const_iterator LoopBeginScopePos = ScopePos; - if (VarDecl* VD = W->getConditionVariable()) { + if (VarDecl *VD = W->getConditionVariable()) { addLocalScopeForVarDecl(VD); addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); } @@ -1919,8 +1932,8 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { // Because of short-circuit evaluation, the condition of the loop can span // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that // evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; + CFGBlock *ExitConditionBlock = createBlock(false); + CFGBlock *EntryConditionBlock = ExitConditionBlock; // Set the terminator for the "exit" condition block. ExitConditionBlock->setTerminator(W); @@ -1928,7 +1941,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { // Now add the actual condition to the condition block. Because the condition // itself may contain control-flow, new blocks may be created. Thus we update // "Succ" after adding the condition. - if (Stmt* C = W->getCond()) { + if (Stmt *C = W->getCond()) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); // The condition might finish the current 'Block'. @@ -1990,7 +2003,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { addLocalScopeAndDtors(W->getBody()); // Create the body. The returned block is the entry to the loop body. - CFGBlock* BodyBlock = addStmt(W->getBody()); + CFGBlock *BodyBlock = addStmt(W->getBody()); if (!BodyBlock) BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;" @@ -2017,13 +2030,13 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { } -CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) { +CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { // FIXME: For now we pretend that @catch and the code it contains does not // exit. return Block; } -CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { +CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { // FIXME: This isn't complete. We basically treat @throw like a return // statement. @@ -2042,7 +2055,7 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { return VisitStmt(S, AddStmtChoice::AlwaysAdd); } -CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { +CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) { // If we were in the middle of a block we stop processing that block. if (badCFG) return 0; @@ -2062,8 +2075,8 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { return VisitStmt(T, AddStmtChoice::AlwaysAdd); } -CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { - CFGBlock* LoopSuccessor = NULL; +CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) { + CFGBlock *LoopSuccessor = NULL; // "do...while" is a control-flow statement. Thus we stop processing the // current block. @@ -2077,15 +2090,15 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { // Because of short-circuit evaluation, the condition of the loop can span // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that // evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; + CFGBlock *ExitConditionBlock = createBlock(false); + CFGBlock *EntryConditionBlock = ExitConditionBlock; // Set the terminator for the "exit" condition block. ExitConditionBlock->setTerminator(D); // Now add the actual condition to the condition block. Because the condition // itself may contain control-flow, new blocks may be created. - if (Stmt* C = D->getCond()) { + if (Stmt *C = D->getCond()) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); if (Block) { @@ -2101,7 +2114,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { const TryResult &KnownVal = tryEvaluateBool(D->getCond()); // Process the loop body. - CFGBlock* BodyBlock = NULL; + CFGBlock *BodyBlock = NULL; { assert(D->getBody()); @@ -2165,7 +2178,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { return BodyBlock; } -CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { +CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { // "continue" is a control-flow statement. Thus we stop processing the // current block. if (badCFG) @@ -2202,13 +2215,12 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) lastBlock = addStmt(VA->getSizeExpr()); } - return lastBlock; } /// VisitStmtExpr - Utility method to handle (nested) statement /// expressions (a GCC extension). -CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { +CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { if (asc.alwaysAdd(*this, SE)) { autoCreateBlock(); appendStmt(Block, SE); @@ -2216,10 +2228,10 @@ CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { return VisitCompoundStmt(SE->getSubStmt()); } -CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { +CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { // "switch" is a control-flow statement. Thus we stop processing the current // block. - CFGBlock* SwitchSuccessor = NULL; + CFGBlock *SwitchSuccessor = NULL; // Save local scope position because in case of condition variable ScopePos // won't be restored when traversing AST. @@ -2227,7 +2239,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { // Create local scope for possible condition variable. // Store scope position. Add implicit destructor. - if (VarDecl* VD = Terminator->getConditionVariable()) { + if (VarDecl *VD = Terminator->getConditionVariable()) { LocalScope::const_iterator SwitchBeginScopePos = ScopePos; addLocalScopeForVarDecl(VD); addAutomaticObjDtors(ScopePos, SwitchBeginScopePos, Terminator); @@ -2323,11 +2335,8 @@ static bool shouldAddCase(bool &switchExclusivelyCovered, if (!switchExclusivelyCovered) { if (switchCond->Val.isInt()) { // Evaluate the LHS of the case value. - Expr::EvalResult V1; - CS->getLHS()->Evaluate(V1, Ctx); - assert(V1.Val.isInt()); + const llvm::APSInt &lhsInt = CS->getLHS()->EvaluateKnownConstInt(Ctx); const llvm::APSInt &condInt = switchCond->Val.getInt(); - const llvm::APSInt &lhsInt = V1.Val.getInt(); if (condInt == lhsInt) { addCase = true; @@ -2336,10 +2345,8 @@ static bool shouldAddCase(bool &switchExclusivelyCovered, else if (condInt < lhsInt) { if (const Expr *RHS = CS->getRHS()) { // Evaluate the RHS of the case value. - Expr::EvalResult V2; - RHS->Evaluate(V2, Ctx); - assert(V2.Val.isInt()); - if (V2.Val.getInt() <= condInt) { + const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx); + if (V2 <= condInt) { addCase = true; switchExclusivelyCovered = true; } @@ -2352,7 +2359,7 @@ static bool shouldAddCase(bool &switchExclusivelyCovered, return addCase; } -CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { +CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) { // CaseStmts are essentially labels, so they are the first statement in a // block. CFGBlock *TopBlock = 0, *LastBlock = 0; @@ -2383,7 +2390,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { addStmt(Sub); } - CFGBlock* CaseBlock = Block; + CFGBlock *CaseBlock = Block; if (!CaseBlock) CaseBlock = createBlock(); @@ -2416,7 +2423,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { return Succ; } -CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { +CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) { if (Terminator->getSubStmt()) addStmt(Terminator->getSubStmt()); @@ -2450,7 +2457,7 @@ CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { // "try"/"catch" is a control-flow statement. Thus we stop processing the // current block. - CFGBlock* TrySuccessor = NULL; + CFGBlock *TrySuccessor = NULL; if (Block) { if (badCFG) @@ -2492,8 +2499,8 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { Succ = TrySuccessor; // Save the current "try" context. - SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock); - TryTerminatedBlock = NewTryTerminatedBlock; + SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock, NewTryTerminatedBlock); + cfg->addTryDispatchBlock(TryTerminatedBlock); assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); Block = NULL; @@ -2501,7 +2508,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { return Block; } -CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { +CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { // CXXCatchStmt are treated like labels, so they are the first statement in a // block. @@ -2511,7 +2518,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { // Create local scope for possible exception variable. // Store scope position. Add implicit destructor. - if (VarDecl* VD = CS->getExceptionDecl()) { + if (VarDecl *VD = CS->getExceptionDecl()) { LocalScope::const_iterator BeginScopePos = ScopePos; addLocalScopeForVarDecl(VD); addAutomaticObjDtors(ScopePos, BeginScopePos, CS); @@ -2520,7 +2527,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { if (CS->getHandlerBlock()) addStmt(CS->getHandlerBlock()); - CFGBlock* CatchBlock = Block; + CFGBlock *CatchBlock = Block; if (!CatchBlock) CatchBlock = createBlock(); @@ -2535,7 +2542,7 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } -CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) { +CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { // C++0x for-range statements are specified as [stmt.ranged]: // // { @@ -2563,7 +2570,7 @@ CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) { // "for" is a control-flow statement. Thus we stop processing the current // block. - CFGBlock* LoopSuccessor = NULL; + CFGBlock *LoopSuccessor = NULL; if (Block) { if (badCFG) return 0; @@ -2577,7 +2584,7 @@ CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) { BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); // The block for the __begin != __end expression. - CFGBlock* ConditionBlock = createBlock(false); + CFGBlock *ConditionBlock = createBlock(false); ConditionBlock->setTerminator(S); // Now add the actual condition to the condition block. @@ -2713,9 +2720,9 @@ CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E, return Visit(E->getSubExpr(), AddStmtChoice()); } -CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { +CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) { // Lazily create the indirect-goto dispatch block if there isn't one already. - CFGBlock* IBlock = cfg->getIndirectGotoBlock(); + CFGBlock *IBlock = cfg->getIndirectGotoBlock(); if (!IBlock) { IBlock = createBlock(false); @@ -2774,7 +2781,7 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) { // When visiting children for destructors we want to visit them in reverse // order. Because there's no reverse iterator for children must to reverse // them in helper vector. - typedef llvm::SmallVector<Stmt *, 4> ChildrenVect; + typedef SmallVector<Stmt *, 4> ChildrenVect; ChildrenVect ChildrenRev; for (Stmt::child_range I = E->children(); I; ++I) { if (*I) ChildrenRev.push_back(*I); @@ -2864,7 +2871,16 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( if (!BindToTemporary) { // If lifetime of temporary is not prolonged (by assigning to constant // reference) add destructor for it. - autoCreateBlock(); + + // If the destructor is marked as a no-return destructor, we need to create + // a new block for the destructor which does not have as a successor + // anything built thus far. Control won't flow out of this block. + const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor(); + if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) + Block = createNoReturnBlock(); + else + autoCreateBlock(); + appendTemporaryDtor(Block, E); B = Block; } @@ -2937,7 +2953,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( /// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has /// no successors or predecessors. If this is the first block created in the /// CFG, it is automatically set to be the Entry and Exit of the CFG. -CFGBlock* CFG::createBlock() { +CFGBlock *CFG::createBlock() { bool first_block = begin() == end(); // Create the block. @@ -2955,7 +2971,7 @@ CFGBlock* CFG::createBlock() { /// buildCFG - Constructs a CFG from an AST. Ownership of the returned /// CFG is returned to the caller. -CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, +CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, const BuildOptions &BO) { CFGBuilder Builder(C, BO); return Builder.buildCFG(D, Statement); @@ -3013,17 +3029,17 @@ namespace { typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy; } -static void FindSubExprAssignments(Stmt *S, - llvm::SmallPtrSet<Expr*,50>& Set) { +static void FindSubExprAssignments(const Stmt *S, + llvm::SmallPtrSet<const Expr*,50>& Set) { if (!S) return; - for (Stmt::child_range I = S->children(); I; ++I) { - Stmt *child = *I; + for (Stmt::const_child_range I = S->children(); I; ++I) { + const Stmt *child = *I; if (!child) continue; - if (BinaryOperator* B = dyn_cast<BinaryOperator>(child)) + if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child)) if (B->isAssignmentOp()) Set.insert(B); FindSubExprAssignments(child, Set); @@ -3037,7 +3053,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { // assignments that we want to *possibly* register as a block-level // expression. Basically, if an assignment occurs both in a subexpression and // at the block-level, it is a block-level expression. - llvm::SmallPtrSet<Expr*,50> SubExprAssignments; + llvm::SmallPtrSet<const Expr*,50> SubExprAssignments; for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) @@ -3053,19 +3069,19 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { const CFGStmt *CS = BI->getAs<CFGStmt>(); if (!CS) continue; - if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) { + if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) { assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps"); - if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { + if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { // Assignment expressions that are not nested within another // expression are really "statements" whose value is never used by // another expression. if (B->isAssignmentOp() && !SubExprAssignments.count(Exp)) continue; - } else if (const StmtExpr* SE = dyn_cast<StmtExpr>(Exp)) { + } else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) { // Special handling for statement expressions. The last statement in // the statement expression is also a block-level expr. - const CompoundStmt* C = SE->getSubStmt(); + const CompoundStmt *C = SE->getSubStmt(); if (!C->body_empty()) { const Stmt *Last = C->body_back(); if (const Expr *LastEx = dyn_cast<Expr>(Last)) @@ -3082,7 +3098,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { // Look at terminators. The condition is a block-level expression. - Stmt* S = (*I)->getTerminatorCondition(); + Stmt *S = (*I)->getTerminatorCondition(); if (S && M->find(S) == M->end()) { unsigned x = M->size(); @@ -3093,7 +3109,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { return M; } -CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { +CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) { assert(S != NULL); if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } @@ -3223,7 +3239,7 @@ public: void setBlockID(signed i) { currentBlock = i; } void setStmtID(unsigned i) { currentStmt = i; } - virtual bool handledStmt(Stmt* S, llvm::raw_ostream& OS) { + virtual bool handledStmt(Stmt *S, raw_ostream &OS) { StmtMapTy::iterator I = StmtMap.find(S); if (I == StmtMap.end()) @@ -3238,7 +3254,7 @@ public: return true; } - bool handleDecl(const Decl* D, llvm::raw_ostream& OS) { + bool handleDecl(const Decl *D, raw_ostream &OS) { DeclMapTy::iterator I = DeclMap.find(D); if (I == DeclMap.end()) @@ -3260,30 +3276,30 @@ namespace { class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint,void> { - llvm::raw_ostream& OS; + raw_ostream &OS; StmtPrinterHelper* Helper; PrintingPolicy Policy; public: - CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper, + CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper, const PrintingPolicy &Policy) : OS(os), Helper(helper), Policy(Policy) {} - void VisitIfStmt(IfStmt* I) { + void VisitIfStmt(IfStmt *I) { OS << "if "; I->getCond()->printPretty(OS,Helper,Policy); } // Default case. - void VisitStmt(Stmt* Terminator) { + void VisitStmt(Stmt *Terminator) { Terminator->printPretty(OS, Helper, Policy); } - void VisitForStmt(ForStmt* F) { + void VisitForStmt(ForStmt *F) { OS << "for (" ; if (F->getInit()) OS << "..."; OS << "; "; - if (Stmt* C = F->getCond()) + if (Stmt *C = F->getCond()) C->printPretty(OS, Helper, Policy); OS << "; "; if (F->getInc()) @@ -3291,24 +3307,24 @@ public: OS << ")"; } - void VisitWhileStmt(WhileStmt* W) { + void VisitWhileStmt(WhileStmt *W) { OS << "while " ; - if (Stmt* C = W->getCond()) + if (Stmt *C = W->getCond()) C->printPretty(OS, Helper, Policy); } - void VisitDoStmt(DoStmt* D) { + void VisitDoStmt(DoStmt *D) { OS << "do ... while "; - if (Stmt* C = D->getCond()) + if (Stmt *C = D->getCond()) C->printPretty(OS, Helper, Policy); } - void VisitSwitchStmt(SwitchStmt* Terminator) { + void VisitSwitchStmt(SwitchStmt *Terminator) { OS << "switch "; Terminator->getCond()->printPretty(OS, Helper, Policy); } - void VisitCXXTryStmt(CXXTryStmt* CS) { + void VisitCXXTryStmt(CXXTryStmt *CS) { OS << "try ..."; } @@ -3317,13 +3333,13 @@ public: OS << " ? ... : ..."; } - void VisitChooseExpr(ChooseExpr* C) { + void VisitChooseExpr(ChooseExpr *C) { OS << "__builtin_choose_expr( "; C->getCond()->printPretty(OS, Helper, Policy); OS << " )"; } - void VisitIndirectGotoStmt(IndirectGotoStmt* I) { + void VisitIndirectGotoStmt(IndirectGotoStmt *I) { OS << "goto *"; I->getTarget()->printPretty(OS, Helper, Policy); } @@ -3344,26 +3360,26 @@ public: OS << " && ..."; return; default: - assert(false && "Invalid logical operator."); + llvm_unreachable("Invalid logical operator."); } } - void VisitExpr(Expr* E) { + void VisitExpr(Expr *E) { E->printPretty(OS, Helper, Policy); } }; } // end anonymous namespace -static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, +static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper, const CFGElement &E) { if (const CFGStmt *CS = E.getAs<CFGStmt>()) { - Stmt *S = CS->getStmt(); + const Stmt *S = CS->getStmt(); if (Helper) { // special printing for statement-expressions. - if (StmtExpr* SE = dyn_cast<StmtExpr>(S)) { - CompoundStmt* Sub = SE->getSubStmt(); + if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) { + const CompoundStmt *Sub = SE->getSubStmt(); if (Sub->children()) { OS << "({ ... ; "; @@ -3373,7 +3389,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, } } // special printing for comma expressions. - if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { + if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { if (B->getOpcode() == BO_Comma) { OS << "... , "; Helper->handledStmt(B->getRHS(),OS); @@ -3401,7 +3417,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, else OS << I->getAnyMember()->getName(); OS << "("; - if (Expr* IE = I->getInit()) + if (Expr *IE = I->getInit()) IE->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); OS << ")"; @@ -3410,7 +3426,7 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, else OS << " (Member initializer)\n"; } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){ - const VarDecl* VD = DE->getVarDecl(); + const VarDecl *VD = DE->getVarDecl(); Helper->handleDecl(VD, OS); const Type* T = VD->getType().getTypePtr(); @@ -3445,8 +3461,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, } } -static void print_block(llvm::raw_ostream& OS, const CFG* cfg, - const CFGBlock& B, +static void print_block(raw_ostream &OS, const CFG* cfg, + const CFGBlock &B, StmtPrinterHelper* Helper, bool print_edges) { if (Helper) Helper->setBlockID(B.getBlockID()); @@ -3464,14 +3480,14 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, OS << " ]\n"; // Print the label of this block. - if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) { + if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) { if (print_edges) OS << " "; - if (LabelStmt* L = dyn_cast<LabelStmt>(Label)) + if (LabelStmt *L = dyn_cast<LabelStmt>(Label)) OS << L->getName(); - else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) { + else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) { OS << "case "; C->getLHS()->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); @@ -3492,7 +3508,7 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, OS << ")"; } else - assert(false && "Invalid label statement in CFGBlock."); + llvm_unreachable("Invalid label statement in CFGBlock."); OS << ":\n"; } @@ -3571,7 +3587,7 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); } /// print - A simple pretty printer of a CFG that outputs to an ostream. -void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const { +void CFG::print(raw_ostream &OS, const LangOptions &LO) const { StmtPrinterHelper Helper(this, LO); // Print the entry block. @@ -3598,25 +3614,25 @@ void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const { /// print - A simple pretty printer of a CFGBlock that outputs to an ostream. /// Generally this will only be called from CFG::print. -void CFGBlock::print(llvm::raw_ostream& OS, const CFG* cfg, +void CFGBlock::print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const { StmtPrinterHelper Helper(cfg, LO); print_block(OS, cfg, *this, &Helper, true); } /// printTerminator - A simple pretty printer of the terminator of a CFGBlock. -void CFGBlock::printTerminator(llvm::raw_ostream &OS, +void CFGBlock::printTerminator(raw_ostream &OS, const LangOptions &LO) const { CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO)); TPrinter.Visit(const_cast<Stmt*>(getTerminator().getStmt())); } -Stmt* CFGBlock::getTerminatorCondition() { +Stmt *CFGBlock::getTerminatorCondition() { Stmt *Terminator = this->Terminator; if (!Terminator) return NULL; - Expr* E = NULL; + Expr *E = NULL; switch (Terminator->getStmtClass()) { default: @@ -3693,7 +3709,7 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} - static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { + static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) { #ifndef NDEBUG std::string OutSStr; diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp index 65cd089..e77e72f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp @@ -40,7 +40,7 @@ bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src, // Maps reachability to a common node by walking the predecessors of the // destination node. void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) { - llvm::SmallVector<const CFGBlock *, 11> worklist; + SmallVector<const CFGBlock *, 11> worklist; llvm::BitVector visited(analyzed.size()); ReachableSet &DstReachability = reachable[Dst->getBlockID()]; diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp index 1fd5eed..16df676 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp @@ -19,7 +19,7 @@ using namespace clang; -typedef llvm::DenseMap<Stmt*,CFGBlock*> SMap; +typedef llvm::DenseMap<const Stmt*, CFGBlock*> SMap; static SMap *AsMap(void *m) { return (SMap*) m; } CFGStmtMap::~CFGStmtMap() { delete AsMap(M); } diff --git a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp index 90f7092..8acd189 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp @@ -17,12 +17,9 @@ #include "clang/AST/DeclObjC.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" - using namespace clang; using namespace ento; -using llvm::StringRef; - // The "fundamental rule" for naming conventions of methods: // (url broken into two lines) // http://developer.apple.com/documentation/Cocoa/Conceptual/ @@ -43,6 +40,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S, case OMF_None: case OMF_autorelease: case OMF_dealloc: + case OMF_finalize: case OMF_release: case OMF_retain: case OMF_retainCount: @@ -63,11 +61,11 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S, return NoConvention; } -bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix, - llvm::StringRef Name) { +bool cocoa::isRefType(QualType RetTy, StringRef Prefix, + StringRef Name) { // Recursively walk the typedef stack, allowing typedefs of reference types. while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { - llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName(); + StringRef TDName = TD->getDecl()->getIdentifier()->getName(); if (TDName.startswith(Prefix) && TDName.endswith("Ref")) return true; @@ -127,10 +125,16 @@ bool cocoa::isCocoaObjectRef(QualType Ty) { return false; } -bool coreFoundation::followsCreateRule(llvm::StringRef functionName) { - llvm::StringRef::iterator it = functionName.begin(); - llvm::StringRef::iterator start = it; - llvm::StringRef::iterator endI = functionName.end(); +bool coreFoundation::followsCreateRule(const FunctionDecl *fn) { + // For now, *just* base this on the function name, not on anything else. + + const IdentifierInfo *ident = fn->getIdentifier(); + if (!ident) return false; + StringRef functionName = ident->getName(); + + StringRef::iterator it = functionName.begin(); + StringRef::iterator start = it; + StringRef::iterator endI = functionName.end(); while (true) { // Scan for the start of 'create' or 'copy'. @@ -138,6 +142,10 @@ bool coreFoundation::followsCreateRule(llvm::StringRef functionName) { // Search for the first character. It can either be 'C' or 'c'. char ch = *it; if (ch == 'C' || ch == 'c') { + // Make sure this isn't something like 'recreate' or 'Scopy'. + if (ch == 'c' && it != start && isalpha(*(it - 1))) + continue; + ++it; break; } @@ -149,14 +157,13 @@ bool coreFoundation::followsCreateRule(llvm::StringRef functionName) { // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase // character. - llvm::StringRef suffix = functionName.substr(it - start); + StringRef suffix = functionName.substr(it - start); if (suffix.startswith("reate")) { it += 5; } else if (suffix.startswith("opy")) { it += 3; - } - else { + } else { // Keep scanning. continue; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp index 7c1e453..a26f0ad 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp @@ -209,8 +209,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { switch (K) { case InvalidTy: - assert(false && "ArgTypeResult must be valid"); - return true; + llvm_unreachable("ArgTypeResult must be valid"); case UnknownTy: return true; @@ -312,8 +311,7 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { switch (K) { case InvalidTy: - assert(false && "No representative type for Invalid ArgTypeResult"); - // Fall-through. + llvm_unreachable("No representative type for Invalid ArgTypeResult"); case UnknownTy: return QualType(); case SpecificTy: @@ -379,7 +377,7 @@ analyze_format_string::LengthModifier::toString() const { // Methods on OptionalAmount. //===----------------------------------------------------------------------===// -void OptionalAmount::toString(llvm::raw_ostream &os) const { +void OptionalAmount::toString(raw_ostream &os) const { switch (hs) { case Invalid: case NotSpecified: diff --git a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp index 7b36f85..62c5455 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp @@ -1,392 +1,674 @@ -//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Live Variables analysis for source-level CFGs. -// -//===----------------------------------------------------------------------===// - #include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Basic/SourceManager.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/FlowSensitive/DataflowSolver.h" -#include "clang/Analysis/Support/SaveAndRestore.h" #include "clang/Analysis/AnalysisContext.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" +#include "clang/AST/StmtVisitor.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Useful constants. -//===----------------------------------------------------------------------===// +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" -static const bool Alive = true; -static const bool Dead = false; +#include <deque> +#include <algorithm> +#include <vector> -//===----------------------------------------------------------------------===// -// Dataflow initialization logic. -//===----------------------------------------------------------------------===// +using namespace clang; namespace { -class RegisterDecls - : public CFGRecStmtDeclVisitor<RegisterDecls> { - - LiveVariables::AnalysisDataTy& AD; - typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy; - AlwaysLiveTy AlwaysLive; +// FIXME: This is copy-pasted from ThreadSafety.c. I wanted a patch that +// contained working code before refactoring the implementation of both +// files. +class CFGBlockSet { + llvm::BitVector VisitedBlockIDs; + +public: + // po_iterator requires this iterator, but the only interface needed is the + // value_type typedef. + struct iterator { + typedef const CFGBlock *value_type; + }; + + CFGBlockSet() {} + CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} + + /// \brief Set the bit associated with a particular CFGBlock. + /// This is the important method for the SetType template parameter. + bool insert(const CFGBlock *Block) { + // Note that insert() is called by po_iterator, which doesn't check to make + // sure that Block is non-null. Moreover, the CFGBlock iterator will + // occasionally hand out null pointers for pruned edges, so we catch those + // here. + if (Block == 0) + return false; // if an edge is trivially false. + if (VisitedBlockIDs.test(Block->getBlockID())) + return false; + VisitedBlockIDs.set(Block->getBlockID()); + return true; + } + + /// \brief Check if the bit for a CFGBlock has been already set. + /// This method is for tracking visited blocks in the main threadsafety loop. + /// Block must not be null. + bool alreadySet(const CFGBlock *Block) { + return VisitedBlockIDs.test(Block->getBlockID()); + } +}; +/// \brief We create a helper class which we use to iterate through CFGBlocks in +/// the topological order. +class TopologicallySortedCFG { + typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; + + std::vector<const CFGBlock*> Blocks; + + typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy; + BlockOrderTy BlockOrder; + + +public: + typedef std::vector<const CFGBlock*>::reverse_iterator iterator; + + TopologicallySortedCFG(const CFG *CFGraph) { + Blocks.reserve(CFGraph->getNumBlockIDs()); + CFGBlockSet BSet(CFGraph); + + for (po_iterator I = po_iterator::begin(CFGraph, BSet), + E = po_iterator::end(CFGraph, BSet); I != E; ++I) { + BlockOrder[*I] = Blocks.size() + 1; + Blocks.push_back(*I); + } + } + + iterator begin() { + return Blocks.rbegin(); + } + + iterator end() { + return Blocks.rend(); + } + + bool empty() { + return begin() == end(); + } + + struct BlockOrderCompare; + friend struct BlockOrderCompare; + + struct BlockOrderCompare { + const TopologicallySortedCFG &TSC; + public: + BlockOrderCompare(const TopologicallySortedCFG &tsc) : TSC(tsc) {} + + bool operator()(const CFGBlock *b1, const CFGBlock *b2) const { + TopologicallySortedCFG::BlockOrderTy::const_iterator b1It = TSC.BlockOrder.find(b1); + TopologicallySortedCFG::BlockOrderTy::const_iterator b2It = TSC.BlockOrder.find(b2); + + unsigned b1V = (b1It == TSC.BlockOrder.end()) ? 0 : b1It->second; + unsigned b2V = (b2It == TSC.BlockOrder.end()) ? 0 : b2It->second; + return b1V > b2V; + } + }; + + BlockOrderCompare getComparator() const { + return BlockOrderCompare(*this); + } +}; +class DataflowWorklist { + SmallVector<const CFGBlock *, 20> worklist; + llvm::BitVector enqueuedBlocks; + TopologicallySortedCFG TSC; public: - RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} + DataflowWorklist(const CFG &cfg) + : enqueuedBlocks(cfg.getNumBlockIDs()), + TSC(&cfg) {} + + void enqueueBlock(const CFGBlock *block); + void enqueueSuccessors(const CFGBlock *block); + void enqueuePredecessors(const CFGBlock *block); - ~RegisterDecls() { + const CFGBlock *dequeue(); - AD.AlwaysLive.resetValues(AD); + void sortWorklist(); +}; - for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end(); - I != E; ++ I) - AD.AlwaysLive(*I, AD) = Alive; - } +} - void VisitImplicitParamDecl(ImplicitParamDecl* IPD) { - // Register the VarDecl for tracking. - AD.Register(IPD); +void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) { + if (block && !enqueuedBlocks[block->getBlockID()]) { + enqueuedBlocks[block->getBlockID()] = true; + worklist.push_back(block); + } +} + +void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { + const unsigned OldWorklistSize = worklist.size(); + for (CFGBlock::const_succ_iterator I = block->succ_begin(), + E = block->succ_end(); I != E; ++I) { + enqueueBlock(*I); } - void VisitVarDecl(VarDecl* VD) { - // Register the VarDecl for tracking. - AD.Register(VD); + if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) + return; - // Does the variable have global storage? If so, it is always live. - if (VD->hasGlobalStorage()) - AlwaysLive.push_back(VD); + sortWorklist(); +} + +void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) { + const unsigned OldWorklistSize = worklist.size(); + for (CFGBlock::const_pred_iterator I = block->pred_begin(), + E = block->pred_end(); I != E; ++I) { + enqueueBlock(*I); } + + if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) + return; - CFG& getCFG() { return AD.getCFG(); } -}; -} // end anonymous namespace + sortWorklist(); +} + +void DataflowWorklist::sortWorklist() { + std::sort(worklist.begin(), worklist.end(), TSC.getComparator()); +} -LiveVariables::LiveVariables(AnalysisContext &AC, bool killAtAssign) { - // Register all referenced VarDecls. - CFG &cfg = *AC.getCFG(); - getAnalysisData().setCFG(cfg); - getAnalysisData().setContext(AC.getASTContext()); - getAnalysisData().AC = &AC; - getAnalysisData().killAtAssign = killAtAssign; - RegisterDecls R(getAnalysisData()); - cfg.VisitBlockStmts(R); +const CFGBlock *DataflowWorklist::dequeue() { + if (worklist.empty()) + return 0; + const CFGBlock *b = worklist.back(); + worklist.pop_back(); + enqueuedBlocks[b->getBlockID()] = false; + return b; +} - // Register all parameters even if they didn't occur in the function body. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(AC.getDecl())) - for (FunctionDecl::param_const_iterator PI = FD->param_begin(), - PE = FD->param_end(); PI != PE; ++PI) - getAnalysisData().Register(*PI); +namespace { +class LiveVariablesImpl { +public: + AnalysisContext &analysisContext; + std::vector<LiveVariables::LivenessValues> cfgBlockValues; + llvm::ImmutableSet<const Stmt *>::Factory SSetFact; + llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; + llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; + llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness; + llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness; + llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment; + const bool killAtAssign; + + LiveVariables::LivenessValues + merge(LiveVariables::LivenessValues valsA, + LiveVariables::LivenessValues valsB); + + LiveVariables::LivenessValues runOnBlock(const CFGBlock *block, + LiveVariables::LivenessValues val, + LiveVariables::Observer *obs = 0); + + void dumpBlockLiveness(const SourceManager& M); + + LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign) + : analysisContext(ac), + SSetFact(false), // Do not canonicalize ImmutableSets by default. + DSetFact(false), // This is a *major* performance win. + killAtAssign(KillAtAssign) {} +}; +} + +static LiveVariablesImpl &getImpl(void *x) { + return *((LiveVariablesImpl *) x); } //===----------------------------------------------------------------------===// -// Transfer functions. +// Operations and queries on LivenessValues. //===----------------------------------------------------------------------===// +bool LiveVariables::LivenessValues::isLive(const Stmt *S) const { + return liveStmts.contains(S); +} + +bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const { + return liveDecls.contains(D); +} + namespace { + template <typename SET> + SET mergeSets(SET A, SET B) { + if (A.isEmpty()) + return B; + + for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) { + A = A.add(*it); + } + return A; + } +} -class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{ - LiveVariables::AnalysisDataTy& AD; - LiveVariables::ValTy LiveState; - const CFGBlock *currentBlock; -public: - TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad), currentBlock(0) {} - - LiveVariables::ValTy& getVal() { return LiveState; } - CFG& getCFG() { return AD.getCFG(); } - - void VisitDeclRefExpr(DeclRefExpr* DR); - void VisitBinaryOperator(BinaryOperator* B); - void VisitBlockExpr(BlockExpr *B); - void VisitAssign(BinaryOperator* B); - void VisitDeclStmt(DeclStmt* DS); - void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); - void VisitUnaryOperator(UnaryOperator* U); - void Visit(Stmt *S); - void VisitTerminator(CFGBlock* B); +LiveVariables::LivenessValues +LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA, + LiveVariables::LivenessValues valsB) { + + llvm::ImmutableSetRef<const Stmt *> + SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()), + SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()); + + + llvm::ImmutableSetRef<const VarDecl *> + DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()), + DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()); - /// VisitConditionVariableInit - Handle the initialization of condition - /// variables at branches. Valid statements include IfStmt, ForStmt, - /// WhileStmt, and SwitchStmt. - void VisitConditionVariableInit(Stmt *S); - void SetTopValue(LiveVariables::ValTy& V) { - V = AD.AlwaysLive; - } + SSetRefA = mergeSets(SSetRefA, SSetRefB); + DSetRefA = mergeSets(DSetRefA, DSetRefB); - void setCurrentBlock(const CFGBlock *block) { - currentBlock = block; - } -}; + // asImmutableSet() canonicalizes the tree, allowing us to do an easy + // comparison afterwards. + return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(), + DSetRefA.asImmutableSet()); +} -void TransferFuncs::Visit(Stmt *S) { +bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const { + return liveStmts == V.liveStmts && liveDecls == V.liveDecls; +} - if (S == getCurrentBlkStmt()) { +//===----------------------------------------------------------------------===// +// Query methods. +//===----------------------------------------------------------------------===// - if (AD.Observer) - AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState); +static bool isAlwaysAlive(const VarDecl *D) { + return D->hasGlobalStorage(); +} - if (getCFG().isBlkExpr(S)) - LiveState(S, AD) = Dead; +bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) { + return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D); +} - StmtVisitor<TransferFuncs,void>::Visit(S); - } - else if (!getCFG().isBlkExpr(S)) { +bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) { + return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D); +} - if (AD.Observer) - AD.Observer->ObserveStmt(S, currentBlock, AD, LiveState); +bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) { + return getImpl(impl).stmtsToLiveness[Loc].isLive(S); +} - StmtVisitor<TransferFuncs,void>::Visit(S); +//===----------------------------------------------------------------------===// +// Dataflow computation. +//===----------------------------------------------------------------------===// - } - else { - // For block-level expressions, mark that they are live. - LiveState(S, AD) = Alive; - } +namespace { +class TransferFunctions : public StmtVisitor<TransferFunctions> { + LiveVariablesImpl &LV; + LiveVariables::LivenessValues &val; + LiveVariables::Observer *observer; + const CFGBlock *currentBlock; +public: + TransferFunctions(LiveVariablesImpl &im, + LiveVariables::LivenessValues &Val, + LiveVariables::Observer *Observer, + const CFGBlock *CurrentBlock) + : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {} + + void VisitBinaryOperator(BinaryOperator *BO); + void VisitBlockExpr(BlockExpr *BE); + void VisitDeclRefExpr(DeclRefExpr *DR); + void VisitDeclStmt(DeclStmt *DS); + void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE); + void VisitUnaryOperator(UnaryOperator *UO); + void Visit(Stmt *S); +}; } + +static const VariableArrayType *FindVA(QualType Ty) { + const Type *ty = Ty.getTypePtr(); + while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) { + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT)) + if (VAT->getSizeExpr()) + return VAT; + + ty = VT->getElementType().getTypePtr(); + } -void TransferFuncs::VisitConditionVariableInit(Stmt *S) { - assert(!getCFG().isBlkExpr(S)); - CFGRecStmtVisitor<TransferFuncs>::VisitConditionVariableInit(S); + return 0; } -void TransferFuncs::VisitTerminator(CFGBlock* B) { - - const Stmt* E = B->getTerminatorCondition(); - - if (!E) - return; +void TransferFunctions::Visit(Stmt *S) { + if (observer) + observer->observeStmt(S, currentBlock, val); + + StmtVisitor<TransferFunctions>::Visit(S); + + if (isa<Expr>(S)) { + val.liveStmts = LV.SSetFact.remove(val.liveStmts, S); + } - assert (getCFG().isBlkExpr(E)); - LiveState(E, AD) = Alive; + // Mark all children expressions live. + + switch (S->getStmtClass()) { + default: + break; + case Stmt::StmtExprClass: { + // For statement expressions, look through the compound statement. + S = cast<StmtExpr>(S)->getSubStmt(); + break; + } + case Stmt::CXXMemberCallExprClass: { + // Include the implicit "this" pointer as being live. + CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S); + if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) { + ImplicitObj = ImplicitObj->IgnoreParens(); + val.liveStmts = LV.SSetFact.add(val.liveStmts, ImplicitObj); + } + break; + } + case Stmt::DeclStmtClass: { + const DeclStmt *DS = cast<DeclStmt>(S); + if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) { + for (const VariableArrayType* VA = FindVA(VD->getType()); + VA != 0; VA = FindVA(VA->getElementType())) { + val.liveStmts = LV.SSetFact.add(val.liveStmts, + VA->getSizeExpr()->IgnoreParens()); + } + } + break; + } + // FIXME: These cases eventually shouldn't be needed. + case Stmt::ExprWithCleanupsClass: { + S = cast<ExprWithCleanups>(S)->getSubExpr(); + break; + } + case Stmt::CXXBindTemporaryExprClass: { + S = cast<CXXBindTemporaryExpr>(S)->getSubExpr(); + break; + } + case Stmt::UnaryExprOrTypeTraitExprClass: { + // No need to unconditionally visit subexpressions. + return; + } + } + + for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end(); + it != ei; ++it) { + if (Stmt *child = *it) { + if (Expr *Ex = dyn_cast<Expr>(child)) + child = Ex->IgnoreParens(); + + val.liveStmts = LV.SSetFact.add(val.liveStmts, child); + } + } } -void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl())) - LiveState(V, AD) = Alive; +void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { + if (B->isAssignmentOp()) { + if (!LV.killAtAssign) + return; + + // Assigning to a variable? + Expr *LHS = B->getLHS()->IgnoreParens(); + + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + // Assignments to references don't kill the ref's address + if (VD->getType()->isReferenceType()) + return; + + if (!isAlwaysAlive(VD)) { + // The variable is now dead. + val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); + } + + if (observer) + observer->observerKill(DR); + } + } } - -void TransferFuncs::VisitBlockExpr(BlockExpr *BE) { + +void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { AnalysisContext::referenced_decls_iterator I, E; - llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl()); + llvm::tie(I, E) = + LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); for ( ; I != E ; ++I) { - DeclBitVector_Types::Idx i = AD.getIdx(*I); - if (i.isValid()) - LiveState.getBit(i) = Alive; + const VarDecl *VD = *I; + if (isAlwaysAlive(VD)) + continue; + val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); } } -void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { - if (B->isAssignmentOp()) VisitAssign(B); - else VisitStmt(B); +void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) { + if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) + if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end()) + val.liveDecls = LV.DSetFact.add(val.liveDecls, D); } -void -TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { - - // This is a block-level expression. Its value is 'dead' before this point. - LiveState(S, AD) = Dead; - - // This represents a 'use' of the collection. - Visit(S->getCollection()); +void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { + for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) + if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) { + if (!isAlwaysAlive(VD)) + val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); + } +} - // This represents a 'kill' for the variable. - Stmt* Element = S->getElement(); - DeclRefExpr* DR = 0; - VarDecl* VD = 0; +void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { + // Kill the iteration variable. + DeclRefExpr *DR = 0; + const VarDecl *VD = 0; - if (DeclStmt* DS = dyn_cast<DeclStmt>(Element)) + Stmt *element = OS->getElement(); + if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) { VD = cast<VarDecl>(DS->getSingleDecl()); - else { - Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens(); - if ((DR = dyn_cast<DeclRefExpr>(ElemExpr))) - VD = cast<VarDecl>(DR->getDecl()); - else { - Visit(ElemExpr); - return; - } } - + else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) { + VD = cast<VarDecl>(DR->getDecl()); + } + if (VD) { - LiveState(VD, AD) = Dead; - if (AD.Observer && DR) { AD.Observer->ObserverKill(DR); } + val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); + if (observer && DR) + observer->observerKill(DR); } } +void TransferFunctions:: +VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) +{ + // While sizeof(var) doesn't technically extend the liveness of 'var', it + // does extent the liveness of metadata if 'var' is a VariableArrayType. + // We handle that special case here. + if (UE->getKind() != UETT_SizeOf || UE->isArgumentType()) + return; -void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { - Expr *E = U->getSubExpr(); + const Expr *subEx = UE->getArgumentExpr(); + if (subEx->getType()->isVariableArrayType()) { + assert(subEx->isLValue()); + val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens()); + } +} - switch (U->getOpcode()) { +void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) { + // Treat ++/-- as a kill. + // Note we don't actually have to do anything if we don't have an observer, + // since a ++/-- acts as both a kill and a "use". + if (!observer) + return; + + switch (UO->getOpcode()) { + default: + return; case UO_PostInc: - case UO_PostDec: + case UO_PostDec: case UO_PreInc: case UO_PreDec: - // Walk through the subexpressions, blasting through ParenExprs - // until we either find a DeclRefExpr or some non-DeclRefExpr - // expression. - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParens())) - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) { - // Treat the --/++ operator as a kill. - if (AD.Observer) { AD.Observer->ObserverKill(DR); } - LiveState(VD, AD) = Alive; - return VisitDeclRefExpr(DR); - } - - // Fall-through. - - default: - return Visit(E); + break; } + + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) + if (isa<VarDecl>(DR->getDecl())) { + // Treat ++/-- as a kill. + observer->observerKill(DR); + } } -void TransferFuncs::VisitAssign(BinaryOperator* B) { - Expr* LHS = B->getLHS(); +LiveVariables::LivenessValues +LiveVariablesImpl::runOnBlock(const CFGBlock *block, + LiveVariables::LivenessValues val, + LiveVariables::Observer *obs) { - // Assigning to a variable? - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) { - // Assignments to references don't kill the ref's address - if (DR->getDecl()->getType()->isReferenceType()) { - VisitDeclRefExpr(DR); - } else { - if (AD.killAtAssign) { - // Update liveness inforamtion. - unsigned bit = AD.getIdx(DR->getDecl()); - LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); - - if (AD.Observer) { AD.Observer->ObserverKill(DR); } - } - // Handle things like +=, etc., which also generate "uses" - // of a variable. Do this just by visiting the subexpression. - if (B->getOpcode() != BO_Assign) - VisitDeclRefExpr(DR); - } + TransferFunctions TF(*this, val, obs, block); + + // Visit the terminator (if any). + if (const Stmt *term = block->getTerminator()) + TF.Visit(const_cast<Stmt*>(term)); + + // Apply the transfer function for all Stmts in the block. + for (CFGBlock::const_reverse_iterator it = block->rbegin(), + ei = block->rend(); it != ei; ++it) { + const CFGElement &elem = *it; + if (!isa<CFGStmt>(elem)) + continue; + + const Stmt *S = cast<CFGStmt>(elem).getStmt(); + TF.Visit(const_cast<Stmt*>(S)); + stmtsToLiveness[S] = val; } - else // Not assigning to a variable. Process LHS as usual. - Visit(LHS); - - Visit(B->getRHS()); + return val; } -void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { - // Declarations effectively "kill" a variable since they cannot - // possibly be live before they are declared. - for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) - if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) { - // Update liveness information by killing the VarDecl. - unsigned bit = AD.getIdx(VD); - LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); - - // The initializer is evaluated after the variable comes into scope, but - // before the DeclStmt (which binds the value to the variable). - // Since this is a reverse dataflow analysis, we must evaluate the - // transfer function for this expression after the DeclStmt. If the - // initializer references the variable (which is bad) then we extend - // its liveness. - if (Expr* Init = VD->getInit()) - Visit(Init); - - if (const VariableArrayType* VT = - AD.getContext().getAsVariableArrayType(VD->getType())) { - StmtIterator I(const_cast<VariableArrayType*>(VT)); - StmtIterator E; - for (; I != E; ++I) Visit(*I); - } - } +void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) { + const CFG *cfg = getImpl(impl).analysisContext.getCFG(); + for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) + getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs); } -} // end anonymous namespace +LiveVariables::LiveVariables(void *im) : impl(im) {} -//===----------------------------------------------------------------------===// -// Merge operator: if something is live on any successor block, it is live -// in the current block (a set union). -//===----------------------------------------------------------------------===// - -namespace { - typedef StmtDeclBitVector_Types::Union Merge; - typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver; -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// External interface to run Liveness analysis. -//===----------------------------------------------------------------------===// - -void LiveVariables::runOnCFG(CFG& cfg) { - Solver S(*this); - S.runOnCFG(cfg); -} - -void LiveVariables::runOnAllBlocks(const CFG& cfg, - LiveVariables::ObserverTy* Obs, - bool recordStmtValues) { - Solver S(*this); - SaveAndRestore<LiveVariables::ObserverTy*> SRObs(getAnalysisData().Observer, - Obs); - S.runOnAllBlocks(cfg, recordStmtValues); +LiveVariables::~LiveVariables() { + delete (LiveVariablesImpl*) impl; } -//===----------------------------------------------------------------------===// -// liveness queries -// - -bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const { - DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); - return i.isValid() ? getBlockData(B).getBit(i) : false; +LiveVariables * +LiveVariables::computeLiveness(AnalysisContext &AC, + bool killAtAssign) { + + // No CFG? Bail out. + CFG *cfg = AC.getCFG(); + if (!cfg) + return 0; + + LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign); + + // Construct the dataflow worklist. Enqueue the exit block as the + // start of the analysis. + DataflowWorklist worklist(*cfg); + llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs()); + + // FIXME: we should enqueue using post order. + for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { + const CFGBlock *block = *it; + worklist.enqueueBlock(block); + + // FIXME: Scan for DeclRefExprs using in the LHS of an assignment. + // We need to do this because we lack context in the reverse analysis + // to determine if a DeclRefExpr appears in such a context, and thus + // doesn't constitute a "use". + if (killAtAssign) + for (CFGBlock::const_iterator bi = block->begin(), be = block->end(); + bi != be; ++bi) { + if (const CFGStmt *cs = bi->getAs<CFGStmt>()) { + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) { + if (BO->getOpcode() == BO_Assign) { + if (const DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) { + LV->inAssignment[DR] = 1; + } + } + } + } + } + } + + worklist.sortWorklist(); + + while (const CFGBlock *block = worklist.dequeue()) { + // Determine if the block's end value has changed. If not, we + // have nothing left to do for this block. + LivenessValues &prevVal = LV->blocksEndToLiveness[block]; + + // Merge the values of all successor blocks. + LivenessValues val; + for (CFGBlock::const_succ_iterator it = block->succ_begin(), + ei = block->succ_end(); it != ei; ++it) { + if (const CFGBlock *succ = *it) { + val = LV->merge(val, LV->blocksBeginToLiveness[succ]); + } + } + + if (!everAnalyzedBlock[block->getBlockID()]) + everAnalyzedBlock[block->getBlockID()] = true; + else if (prevVal.equals(val)) + continue; + + prevVal = val; + + // Update the dataflow value for the start of this block. + LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val); + + // Enqueue the value to the predecessors. + worklist.enqueuePredecessors(block); + } + + return new LiveVariables(LV); } -bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const { - DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); - return i.isValid() ? Live.getBit(i) : false; +static bool compare_entries(const CFGBlock *A, const CFGBlock *B) { + return A->getBlockID() < B->getBlockID(); } -bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const { - return getStmtData(Loc)(StmtVal,getAnalysisData()); +static bool compare_vd_entries(const Decl *A, const Decl *B) { + SourceLocation ALoc = A->getLocStart(); + SourceLocation BLoc = B->getLocStart(); + return ALoc.getRawEncoding() < BLoc.getRawEncoding(); } -bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const { - return getStmtData(Loc)(D,getAnalysisData()); +void LiveVariables::dumpBlockLiveness(const SourceManager &M) { + getImpl(impl).dumpBlockLiveness(M); } -//===----------------------------------------------------------------------===// -// printing liveness state for debugging -// +void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) { + std::vector<const CFGBlock *> vec; + for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator + it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end(); + it != ei; ++it) { + vec.push_back(it->first); + } + std::sort(vec.begin(), vec.end(), compare_entries); -void LiveVariables::dumpLiveness(const ValTy& V, const SourceManager& SM) const { - const AnalysisDataTy& AD = getAnalysisData(); + std::vector<const VarDecl*> declVec; - for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), - E = AD.end_decl(); I!=E; ++I) - if (V.getDeclBit(I->second)) { - llvm::errs() << " " << I->first->getIdentifier()->getName() << " <"; - I->first->getLocation().dump(SM); + for (std::vector<const CFGBlock *>::iterator + it = vec.begin(), ei = vec.end(); it != ei; ++it) { + llvm::errs() << "\n[ B" << (*it)->getBlockID() + << " (live variables at block exit) ]\n"; + + LiveVariables::LivenessValues vals = blocksEndToLiveness[*it]; + declVec.clear(); + + for (llvm::ImmutableSet<const VarDecl *>::iterator si = + vals.liveDecls.begin(), + se = vals.liveDecls.end(); si != se; ++si) { + declVec.push_back(*si); + } + + std::sort(declVec.begin(), declVec.end(), compare_vd_entries); + + for (std::vector<const VarDecl*>::iterator di = declVec.begin(), + de = declVec.end(); di != de; ++di) { + llvm::errs() << " " << (*di)->getDeclName().getAsString() + << " <"; + (*di)->getLocation().dump(M); llvm::errs() << ">\n"; } -} - -void LiveVariables::dumpBlockLiveness(const SourceManager& M) const { - for (BlockDataMapTy::const_iterator I = getBlockDataMap().begin(), - E = getBlockDataMap().end(); I!=E; ++I) { - llvm::errs() << "\n[ B" << I->first->getBlockID() - << " (live variables at block exit) ]\n"; - dumpLiveness(I->second,M); } - - llvm::errs() << "\n"; + llvm::errs() << "\n"; } + +const void *LiveVariables::getTag() { static int x; return &x; } +const void *RelaxedLiveVariables::getTag() { static int x; return &x; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp index ce2690f..2bb39cf 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp @@ -38,8 +38,7 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, unsigned *argIndex) { if (argIndex) { FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); - } - else { + } else { const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, analyze_format_string::PrecisionPos); if (Amt.isInvalid()) @@ -404,6 +403,7 @@ bool PrintfSpecifier::fixType(QualType QT) { case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: + case BuiltinType::Half: // Integral types which are non-trivial to correct. return false; @@ -477,15 +477,14 @@ bool PrintfSpecifier::fixType(QualType QT) { CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; - } - else { - assert(0 && "Unexpected type"); + } else { + llvm_unreachable("Unexpected type"); } return true; } -void PrintfSpecifier::toString(llvm::raw_ostream &os) const { +void PrintfSpecifier::toString(raw_ostream &os) const { // Whilst some features have no defined order, we are using the order // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) os << "%"; diff --git a/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp b/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp new file mode 100644 index 0000000..3a0bbd5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp @@ -0,0 +1,51 @@ +//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/ProgramPoint.h" + +using namespace clang; + +ProgramPointTag::~ProgramPointTag() {} + +ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, + const ProgramPointTag *tag){ + switch (K) { + default: + llvm_unreachable("Unhandled ProgramPoint kind"); + case ProgramPoint::PreStmtKind: + return PreStmt(S, LC, tag); + case ProgramPoint::PostStmtKind: + return PostStmt(S, LC, tag); + case ProgramPoint::PreLoadKind: + return PreLoad(S, LC, tag); + case ProgramPoint::PostLoadKind: + return PostLoad(S, LC, tag); + case ProgramPoint::PreStoreKind: + return PreStore(S, LC, tag); + case ProgramPoint::PostStoreKind: + return PostStore(S, LC, tag); + case ProgramPoint::PostLValueKind: + return PostLValue(S, LC, tag); + case ProgramPoint::PostPurgeDeadSymbolsKind: + return PostPurgeDeadSymbols(S, LC, tag); + } +} + +SimpleProgramPointTag::SimpleProgramPointTag(StringRef description) + : desc(description) {} + +StringRef SimpleProgramPointTag::getTagDescription() const { + return desc; +} diff --git a/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp b/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp index ff96eb4..8f24c43 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp @@ -83,7 +83,7 @@ void PseudoConstantAnalysis::RunAnalysis() { WorkList.push_back(DeclBody); while (!WorkList.empty()) { - const Stmt* Head = WorkList.front(); + const Stmt *Head = WorkList.front(); WorkList.pop_front(); if (const Expr *Ex = dyn_cast<Expr>(Head)) diff --git a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp index c5b17fc..4931771 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp @@ -25,22 +25,163 @@ using namespace clang; -static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, - SourceRange &R2) { - const Stmt *S = 0; - unsigned sn = 0; - R1 = R2 = SourceRange(); +namespace { +class DeadCodeScan { + llvm::BitVector Visited; + llvm::BitVector &Reachable; + llvm::SmallVector<const CFGBlock *, 10> WorkList; + + typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12> + DeferredLocsTy; + + DeferredLocsTy DeferredLocs; + +public: + DeadCodeScan(llvm::BitVector &reachable) + : Visited(reachable.size()), + Reachable(reachable) {} + + void enqueue(const CFGBlock *block); + unsigned scanBackwards(const CFGBlock *Start, + clang::reachable_code::Callback &CB); + + bool isDeadCodeRoot(const CFGBlock *Block); + + const Stmt *findDeadCode(const CFGBlock *Block); + + void reportDeadCode(const Stmt *S, + clang::reachable_code::Callback &CB); +}; +} + +void DeadCodeScan::enqueue(const CFGBlock *block) { + unsigned blockID = block->getBlockID(); + if (Reachable[blockID] || Visited[blockID]) + return; + Visited[blockID] = true; + WorkList.push_back(block); +} + +bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) { + bool isDeadRoot = true; + + for (CFGBlock::const_pred_iterator I = Block->pred_begin(), + E = Block->pred_end(); I != E; ++I) { + if (const CFGBlock *PredBlock = *I) { + unsigned blockID = PredBlock->getBlockID(); + if (Visited[blockID]) { + isDeadRoot = false; + continue; + } + if (!Reachable[blockID]) { + isDeadRoot = false; + Visited[blockID] = true; + WorkList.push_back(PredBlock); + continue; + } + } + } + + return isDeadRoot; +} + +static bool isValidDeadStmt(const Stmt *S) { + if (S->getLocStart().isInvalid()) + return false; + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) + return BO->getOpcode() != BO_Comma; + return true; +} + +const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { + for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I) + if (const CFGStmt *CS = I->getAs<CFGStmt>()) { + const Stmt *S = CS->getStmt(); + if (isValidDeadStmt(S)) + return S; + } + + if (CFGTerminator T = Block->getTerminator()) { + const Stmt *S = T.getStmt(); + if (isValidDeadStmt(S)) + return S; + } + + return 0; +} + +static int SrcCmp(const void *p1, const void *p2) { + return + ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() < + ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart(); +} + +unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, + clang::reachable_code::Callback &CB) { + + unsigned count = 0; + enqueue(Start); + + while (!WorkList.empty()) { + const CFGBlock *Block = WorkList.pop_back_val(); + + // It is possible that this block has been marked reachable after + // it was enqueued. + if (Reachable[Block->getBlockID()]) + continue; + + // Look for any dead code within the block. + const Stmt *S = findDeadCode(Block); + + if (!S) { + // No dead code. Possibly an empty block. Look at dead predecessors. + for (CFGBlock::const_pred_iterator I = Block->pred_begin(), + E = Block->pred_end(); I != E; ++I) { + if (const CFGBlock *predBlock = *I) + enqueue(predBlock); + } + continue; + } + + // Specially handle macro-expanded code. + if (S->getLocStart().isMacroID()) { + count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable); + continue; + } + + if (isDeadCodeRoot(Block)) { + reportDeadCode(S, CB); + count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable); + } + else { + // Record this statement as the possibly best location in a + // strongly-connected component of dead code for emitting a + // warning. + DeferredLocs.push_back(std::make_pair(Block, S)); + } + } - if (sn < b.size()) { - const CFGStmt *CS = b[sn].getAs<CFGStmt>(); - if (!CS) - return SourceLocation(); + // If we didn't find a dead root, then report the dead code with the + // earliest location. + if (!DeferredLocs.empty()) { + llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp); + for (DeferredLocsTy::iterator I = DeferredLocs.begin(), + E = DeferredLocs.end(); I != E; ++I) { + const CFGBlock *block = I->first; + if (Reachable[block->getBlockID()]) + continue; + reportDeadCode(I->second, CB); + count += clang::reachable_code::ScanReachableFromBlock(block, Reachable); + } + } + + return count; +} - S = CS->getStmt(); - } else if (b.getTerminator()) - S = b.getTerminator(); - else - return SourceLocation(); +static SourceLocation GetUnreachableLoc(const Stmt *S, + SourceRange &R1, + SourceRange &R2) { + R1 = R2 = SourceRange(); if (const Expr *Ex = dyn_cast<Expr>(S)) S = Ex->IgnoreParenImpCasts(); @@ -48,24 +189,6 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, switch (S->getStmtClass()) { case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(S); - if (BO->getOpcode() == BO_Comma) { - if (sn+1 < b.size()) - return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart(); - const CFGBlock *n = &b; - while (1) { - if (n->getTerminator()) - return n->getTerminator()->getLocStart(); - if (n->succ_size() != 1) - return SourceLocation(); - n = n[0].succ_begin()[0]; - if (n->pred_size() != 1) - return SourceLocation(); - if (!n->empty()) - return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart(); - } - } - R1 = BO->getLHS()->getSourceRange(); - R2 = BO->getRHS()->getSourceRange(); return BO->getOperatorLoc(); } case Expr::UnaryOperatorClass: { @@ -120,177 +243,87 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, return S->getLocStart(); } -static SourceLocation MarkLiveTop(const CFGBlock *Start, - llvm::BitVector &reachable, - SourceManager &SM) { - - // Prep work worklist. - llvm::SmallVector<const CFGBlock*, 32> WL; - WL.push_back(Start); - +void DeadCodeScan::reportDeadCode(const Stmt *S, + clang::reachable_code::Callback &CB) { SourceRange R1, R2; - SourceLocation top = GetUnreachableLoc(*Start, R1, R2); - - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - - // Solve - CFGBlock::FilterOptions FO; - FO.IgnoreDefaultsWithCoveredEnums = 1; - - while (!WL.empty()) { - const CFGBlock *item = WL.back(); - WL.pop_back(); - - SourceLocation c = GetUnreachableLoc(*item, R1, R2); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - - reachable.set(item->getBlockID()); - for (CFGBlock::filtered_succ_iterator I = - item->filtered_succ_start_end(FO); I.hasMore(); ++I) - if (const CFGBlock *B = *I) { - unsigned blockID = B->getBlockID(); - if (!reachable[blockID]) { - reachable.set(blockID); - WL.push_back(B); - } - } - } - - return top; + SourceLocation Loc = GetUnreachableLoc(S, R1, R2); + CB.HandleUnreachable(Loc, R1, R2); } -static int LineCmp(const void *p1, const void *p2) { - SourceLocation *Line1 = (SourceLocation *)p1; - SourceLocation *Line2 = (SourceLocation *)p2; - return !(*Line1 < *Line2); -} - -namespace { -struct ErrLoc { - SourceLocation Loc; - SourceRange R1; - SourceRange R2; - ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) - : Loc(l), R1(r1), R2(r2) { } -}; -} namespace clang { namespace reachable_code { - -/// ScanReachableFromBlock - Mark all blocks reachable from Start. -/// Returns the total number of blocks that were marked reachable. -unsigned ScanReachableFromBlock(const CFGBlock &Start, + +unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable) { unsigned count = 0; - llvm::SmallVector<const CFGBlock*, 32> WL; - + // Prep work queue - Reachable.set(Start.getBlockID()); - ++count; - WL.push_back(&Start); - + SmallVector<const CFGBlock*, 32> WL; + + // The entry block may have already been marked reachable + // by the caller. + if (!Reachable[Start->getBlockID()]) { + ++count; + Reachable[Start->getBlockID()] = true; + } + + WL.push_back(Start); + // Find the reachable blocks from 'Start'. - CFGBlock::FilterOptions FO; - FO.IgnoreDefaultsWithCoveredEnums = 1; - while (!WL.empty()) { - const CFGBlock *item = WL.back(); - WL.pop_back(); - - // Look at the successors and mark then reachable. - for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO); - I.hasMore(); ++I) + const CFGBlock *item = WL.pop_back_val(); + + // Look at the successors and mark then reachable. + for (CFGBlock::const_succ_iterator I = item->succ_begin(), + E = item->succ_end(); I != E; ++I) if (const CFGBlock *B = *I) { unsigned blockID = B->getBlockID(); if (!Reachable[blockID]) { Reachable.set(blockID); - ++count; WL.push_back(B); + ++count; } } } return count; } - + void FindUnreachableCode(AnalysisContext &AC, Callback &CB) { CFG *cfg = AC.getCFG(); if (!cfg) return; - // Scan for reachable blocks. + // Scan for reachable blocks from the entrance of the CFG. + // If there are no unreachable blocks, we're done. llvm::BitVector reachable(cfg->getNumBlockIDs()); - unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); - - // If there are no unreachable blocks, we're done. + unsigned numReachable = ScanReachableFromBlock(&cfg->getEntry(), reachable); if (numReachable == cfg->getNumBlockIDs()) return; - - SourceRange R1, R2; - - llvm::SmallVector<ErrLoc, 24> lines; - bool AddEHEdges = AC.getAddEHEdges(); - - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!reachable[b.getBlockID()]) { - if (b.pred_empty()) { - if (!AddEHEdges - && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) { - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - numReachable += ScanReachableFromBlock(b, reachable); - continue; - } - SourceLocation c = GetUnreachableLoc(b, R1, R2); - if (!c.isValid()) { - // Blocks without a location can't produce a warning, so don't mark - // reachable blocks from here as live. - reachable.set(b.getBlockID()); - ++numReachable; - continue; - } - lines.push_back(ErrLoc(c, R1, R2)); - // Avoid excessive errors by marking everything reachable from here - numReachable += ScanReachableFromBlock(b, reachable); - } + + // If there aren't explicit EH edges, we should include the 'try' dispatch + // blocks as roots. + if (!AC.getCFGBuildOptions().AddEHEdges) { + for (CFG::try_block_iterator I = cfg->try_blocks_begin(), + E = cfg->try_blocks_end() ; I != E; ++I) { + numReachable += ScanReachableFromBlock(*I, reachable); } + if (numReachable == cfg->getNumBlockIDs()) + return; } - if (numReachable < cfg->getNumBlockIDs()) { - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!reachable[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, - AC.getASTContext().getSourceManager()), - SourceRange(), SourceRange())); - } + // There are some unreachable blocks. We need to find the root blocks that + // contain code that should be considered unreachable. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + const CFGBlock *block = *I; + // A block may have been marked reachable during this loop. + if (reachable[block->getBlockID()]) + continue; + + DeadCodeScan DS(reachable); + numReachable += DS.scanBackwards(block, CB); + + if (numReachable == cfg->getNumBlockIDs()) + return; } - - llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); - - for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end(); - I != E; ++I) - if (I->Loc.isValid()) - CB.HandleUnreachable(I->Loc, I->R1, I->R2); } }} // end namespace clang::reachable_code diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp new file mode 100644 index 0000000..5a12913 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp @@ -0,0 +1,799 @@ +//===- ThreadSafety.cpp ----------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A intra-procedural analysis for thread safety (e.g. deadlocks and race +// conditions), based off of an annotation system. +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more +// information. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/ThreadSafety.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <algorithm> +#include <vector> + +using namespace clang; +using namespace thread_safety; + +// Key method definition +ThreadSafetyHandler::~ThreadSafetyHandler() {} + +// Helper function +static Expr *getParent(Expr *Exp) { + if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) + return ME->getBase(); + if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) + return CE->getImplicitObjectArgument(); + return 0; +} + +namespace { +/// \brief Implements a set of CFGBlocks using a BitVector. +/// +/// This class contains a minimal interface, primarily dictated by the SetType +/// template parameter of the llvm::po_iterator template, as used with external +/// storage. We also use this set to keep track of which CFGBlocks we visit +/// during the analysis. +class CFGBlockSet { + llvm::BitVector VisitedBlockIDs; + +public: + // po_iterator requires this iterator, but the only interface needed is the + // value_type typedef. + struct iterator { + typedef const CFGBlock *value_type; + }; + + CFGBlockSet() {} + CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} + + /// \brief Set the bit associated with a particular CFGBlock. + /// This is the important method for the SetType template parameter. + bool insert(const CFGBlock *Block) { + // Note that insert() is called by po_iterator, which doesn't check to make + // sure that Block is non-null. Moreover, the CFGBlock iterator will + // occasionally hand out null pointers for pruned edges, so we catch those + // here. + if (Block == 0) + return false; // if an edge is trivially false. + if (VisitedBlockIDs.test(Block->getBlockID())) + return false; + VisitedBlockIDs.set(Block->getBlockID()); + return true; + } + + /// \brief Check if the bit for a CFGBlock has been already set. + /// This method is for tracking visited blocks in the main threadsafety loop. + /// Block must not be null. + bool alreadySet(const CFGBlock *Block) { + return VisitedBlockIDs.test(Block->getBlockID()); + } +}; + +/// \brief We create a helper class which we use to iterate through CFGBlocks in +/// the topological order. +class TopologicallySortedCFG { + typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; + + std::vector<const CFGBlock*> Blocks; + +public: + typedef std::vector<const CFGBlock*>::reverse_iterator iterator; + + TopologicallySortedCFG(const CFG *CFGraph) { + Blocks.reserve(CFGraph->getNumBlockIDs()); + CFGBlockSet BSet(CFGraph); + + for (po_iterator I = po_iterator::begin(CFGraph, BSet), + E = po_iterator::end(CFGraph, BSet); I != E; ++I) { + Blocks.push_back(*I); + } + } + + iterator begin() { + return Blocks.rbegin(); + } + + iterator end() { + return Blocks.rend(); + } + + bool empty() { + return begin() == end(); + } +}; + +/// \brief A MutexID object uniquely identifies a particular mutex, and +/// is built from an Expr* (i.e. calling a lock function). +/// +/// Thread-safety analysis works by comparing lock expressions. Within the +/// body of a function, an expression such as "x->foo->bar.mu" will resolve to +/// a particular mutex object at run-time. Subsequent occurrences of the same +/// expression (where "same" means syntactic equality) will refer to the same +/// run-time object if three conditions hold: +/// (1) Local variables in the expression, such as "x" have not changed. +/// (2) Values on the heap that affect the expression have not changed. +/// (3) The expression involves only pure function calls. +/// The current implementation assumes, but does not verify, that multiple uses +/// of the same lock expression satisfies these criteria. +/// +/// Clang introduces an additional wrinkle, which is that it is difficult to +/// derive canonical expressions, or compare expressions directly for equality. +/// Thus, we identify a mutex not by an Expr, but by the set of named +/// declarations that are referenced by the Expr. In other words, +/// x->foo->bar.mu will be a four element vector with the Decls for +/// mu, bar, and foo, and x. The vector will uniquely identify the expression +/// for all practical purposes. +/// +/// Note we will need to perform substitution on "this" and function parameter +/// names when constructing a lock expression. +/// +/// For example: +/// class C { Mutex Mu; void lock() EXCLUSIVE_LOCK_FUNCTION(this->Mu); }; +/// void myFunc(C *X) { ... X->lock() ... } +/// The original expression for the mutex acquired by myFunc is "this->Mu", but +/// "X" is substituted for "this" so we get X->Mu(); +/// +/// For another example: +/// foo(MyList *L) EXCLUSIVE_LOCKS_REQUIRED(L->Mu) { ... } +/// MyList *MyL; +/// foo(MyL); // requires lock MyL->Mu to be held +class MutexID { + SmallVector<NamedDecl*, 2> DeclSeq; + + /// Build a Decl sequence representing the lock from the given expression. + /// Recursive function that bottoms out when the final DeclRefExpr is reached. + // FIXME: Lock expressions that involve array indices or function calls. + // FIXME: Deal with LockReturned attribute. + void buildMutexID(Expr *Exp, Expr *Parent) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) { + NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); + DeclSeq.push_back(ND); + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { + NamedDecl *ND = ME->getMemberDecl(); + DeclSeq.push_back(ND); + buildMutexID(ME->getBase(), Parent); + } else if (isa<CXXThisExpr>(Exp)) { + if (Parent) + buildMutexID(Parent, 0); + else + return; // mutexID is still valid in this case + } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) + buildMutexID(CE->getSubExpr(), Parent); + else + DeclSeq.clear(); // invalid lock expression + } + +public: + MutexID(Expr *LExpr, Expr *ParentExpr) { + buildMutexID(LExpr, ParentExpr); + } + + /// If we encounter part of a lock expression we cannot parse + bool isValid() const { + return !DeclSeq.empty(); + } + + bool operator==(const MutexID &other) const { + return DeclSeq == other.DeclSeq; + } + + bool operator!=(const MutexID &other) const { + return !(*this == other); + } + + // SmallVector overloads Operator< to do lexicographic ordering. Note that + // we use pointer equality (and <) to compare NamedDecls. This means the order + // of MutexIDs in a lockset is nondeterministic. In order to output + // diagnostics in a deterministic ordering, we must order all diagnostics to + // output by SourceLocation when iterating through this lockset. + bool operator<(const MutexID &other) const { + return DeclSeq < other.DeclSeq; + } + + /// \brief Returns the name of the first Decl in the list for a given MutexID; + /// e.g. the lock expression foo.bar() has name "bar". + /// The caret will point unambiguously to the lock expression, so using this + /// name in diagnostics is a way to get simple, and consistent, mutex names. + /// We do not want to output the entire expression text for security reasons. + StringRef getName() const { + assert(isValid()); + return DeclSeq.front()->getName(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + for (SmallVectorImpl<NamedDecl*>::const_iterator I = DeclSeq.begin(), + E = DeclSeq.end(); I != E; ++I) { + ID.AddPointer(*I); + } + } +}; + +/// \brief This is a helper class that stores info about the most recent +/// accquire of a Lock. +/// +/// The main body of the analysis maps MutexIDs to LockDatas. +struct LockData { + SourceLocation AcquireLoc; + + /// \brief LKind stores whether a lock is held shared or exclusively. + /// Note that this analysis does not currently support either re-entrant + /// locking or lock "upgrading" and "downgrading" between exclusive and + /// shared. + /// + /// FIXME: add support for re-entrant locking and lock up/downgrading + LockKind LKind; + + LockData(SourceLocation AcquireLoc, LockKind LKind) + : AcquireLoc(AcquireLoc), LKind(LKind) {} + + bool operator==(const LockData &other) const { + return AcquireLoc == other.AcquireLoc && LKind == other.LKind; + } + + bool operator!=(const LockData &other) const { + return !(*this == other); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(AcquireLoc.getRawEncoding()); + ID.AddInteger(LKind); + } +}; + +/// A Lockset maps each MutexID (defined above) to information about how it has +/// been locked. +typedef llvm::ImmutableMap<MutexID, LockData> Lockset; + +/// \brief We use this class to visit different types of expressions in +/// CFGBlocks, and build up the lockset. +/// An expression may cause us to add or remove locks from the lockset, or else +/// output error messages related to missing locks. +/// FIXME: In future, we may be able to not inherit from a visitor. +class BuildLockset : public StmtVisitor<BuildLockset> { + ThreadSafetyHandler &Handler; + Lockset LSet; + Lockset::Factory &LocksetFactory; + + // Helper functions + void removeLock(SourceLocation UnlockLoc, Expr *LockExp, Expr *Parent); + void addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent, + LockKind LK); + const ValueDecl *getValueDecl(Expr *Exp); + void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK, + Expr *MutexExp, ProtectedOperationKind POK); + void checkAccess(Expr *Exp, AccessKind AK); + void checkDereference(Expr *Exp, AccessKind AK); + + template <class AttrType> + void addLocksToSet(LockKind LK, Attr *Attr, CXXMemberCallExpr *Exp); + + /// \brief Returns true if the lockset contains a lock, regardless of whether + /// the lock is held exclusively or shared. + bool locksetContains(MutexID Lock) const { + return LSet.lookup(Lock); + } + + /// \brief Returns true if the lockset contains a lock with the passed in + /// locktype. + bool locksetContains(MutexID Lock, LockKind KindRequested) const { + const LockData *LockHeld = LSet.lookup(Lock); + return (LockHeld && KindRequested == LockHeld->LKind); + } + + /// \brief Returns true if the lockset contains a lock with at least the + /// passed in locktype. So for example, if we pass in LK_Shared, this function + /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in + /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive. + bool locksetContainsAtLeast(MutexID Lock, LockKind KindRequested) const { + switch (KindRequested) { + case LK_Shared: + return locksetContains(Lock); + case LK_Exclusive: + return locksetContains(Lock, KindRequested); + } + llvm_unreachable("Unknown LockKind"); + } + +public: + BuildLockset(ThreadSafetyHandler &Handler, Lockset LS, Lockset::Factory &F) + : StmtVisitor<BuildLockset>(), Handler(Handler), LSet(LS), + LocksetFactory(F) {} + + Lockset getLockset() { + return LSet; + } + + void VisitUnaryOperator(UnaryOperator *UO); + void VisitBinaryOperator(BinaryOperator *BO); + void VisitCastExpr(CastExpr *CE); + void VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp); +}; + +/// \brief Add a new lock to the lockset, warning if the lock is already there. +/// \param LockLoc The source location of the acquire +/// \param LockExp The lock expression corresponding to the lock to be added +void BuildLockset::addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent, + LockKind LK) { + // FIXME: deal with acquired before/after annotations. We can write a first + // pass that does the transitive lookup lazily, and refine afterwards. + MutexID Mutex(LockExp, Parent); + if (!Mutex.isValid()) { + Handler.handleInvalidLockExp(LockExp->getExprLoc()); + return; + } + + LockData NewLock(LockLoc, LK); + + // FIXME: Don't always warn when we have support for reentrant locks. + if (locksetContains(Mutex)) + Handler.handleDoubleLock(Mutex.getName(), LockLoc); + LSet = LocksetFactory.add(LSet, Mutex, NewLock); +} + +/// \brief Remove a lock from the lockset, warning if the lock is not there. +/// \param LockExp The lock expression corresponding to the lock to be removed +/// \param UnlockLoc The source location of the unlock (only used in error msg) +void BuildLockset::removeLock(SourceLocation UnlockLoc, Expr *LockExp, + Expr *Parent) { + MutexID Mutex(LockExp, Parent); + if (!Mutex.isValid()) { + Handler.handleInvalidLockExp(LockExp->getExprLoc()); + return; + } + + Lockset NewLSet = LocksetFactory.remove(LSet, Mutex); + if(NewLSet == LSet) + Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc); + + LSet = NewLSet; +} + +/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs +const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) { + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp)) + return DR->getDecl(); + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) + return ME->getMemberDecl(); + + return 0; +} + +/// \brief Warn if the LSet does not contain a lock sufficient to protect access +/// of at least the passed in AccessType. +void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, + AccessKind AK, Expr *MutexExp, + ProtectedOperationKind POK) { + LockKind LK = getLockKindFromAccessKind(AK); + Expr *Parent = getParent(Exp); + MutexID Mutex(MutexExp, Parent); + if (!Mutex.isValid()) + Handler.handleInvalidLockExp(MutexExp->getExprLoc()); + else if (!locksetContainsAtLeast(Mutex, LK)) + Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc()); +} + + +/// \brief This method identifies variable dereferences and checks pt_guarded_by +/// and pt_guarded_var annotations. Note that we only check these annotations +/// at the time a pointer is dereferenced. +/// FIXME: We need to check for other types of pointer dereferences +/// (e.g. [], ->) and deal with them here. +/// \param Exp An expression that has been read or written. +void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) { + UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp); + if (!UO || UO->getOpcode() != clang::UO_Deref) + return; + Exp = UO->getSubExpr()->IgnoreParenCasts(); + + const ValueDecl *D = getValueDecl(Exp); + if(!D || !D->hasAttrs()) + return; + + if (D->getAttr<PtGuardedVarAttr>() && LSet.isEmpty()) + Handler.handleNoMutexHeld(D, POK_VarDereference, AK, Exp->getExprLoc()); + + const AttrVec &ArgAttrs = D->getAttrs(); + for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) + if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i])) + warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference); +} + +/// \brief Checks guarded_by and guarded_var attributes. +/// Whenever we identify an access (read or write) of a DeclRefExpr or +/// MemberExpr, we need to check whether there are any guarded_by or +/// guarded_var attributes, and make sure we hold the appropriate mutexes. +void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) { + const ValueDecl *D = getValueDecl(Exp); + if(!D || !D->hasAttrs()) + return; + + if (D->getAttr<GuardedVarAttr>() && LSet.isEmpty()) + Handler.handleNoMutexHeld(D, POK_VarAccess, AK, Exp->getExprLoc()); + + const AttrVec &ArgAttrs = D->getAttrs(); + for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) + if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i])) + warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess); +} + +/// \brief For unary operations which read and write a variable, we need to +/// check whether we hold any required mutexes. Reads are checked in +/// VisitCastExpr. +void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) { + switch (UO->getOpcode()) { + case clang::UO_PostDec: + case clang::UO_PostInc: + case clang::UO_PreDec: + case clang::UO_PreInc: { + Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts(); + checkAccess(SubExp, AK_Written); + checkDereference(SubExp, AK_Written); + break; + } + default: + break; + } +} + +/// For binary operations which assign to a variable (writes), we need to check +/// whether we hold any required mutexes. +/// FIXME: Deal with non-primitive types. +void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) { + if (!BO->isAssignmentOp()) + return; + Expr *LHSExp = BO->getLHS()->IgnoreParenCasts(); + checkAccess(LHSExp, AK_Written); + checkDereference(LHSExp, AK_Written); +} + +/// Whenever we do an LValue to Rvalue cast, we are reading a variable and +/// need to ensure we hold any required mutexes. +/// FIXME: Deal with non-primitive types. +void BuildLockset::VisitCastExpr(CastExpr *CE) { + if (CE->getCastKind() != CK_LValueToRValue) + return; + Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts(); + checkAccess(SubExp, AK_Read); + checkDereference(SubExp, AK_Read); +} + +/// \brief This function, parameterized by an attribute type, is used to add a +/// set of locks specified as attribute arguments to the lockset. +template <typename AttrType> +void BuildLockset::addLocksToSet(LockKind LK, Attr *Attr, + CXXMemberCallExpr *Exp) { + typedef typename AttrType::args_iterator iterator_type; + SourceLocation ExpLocation = Exp->getExprLoc(); + Expr *Parent = Exp->getImplicitObjectArgument(); + AttrType *SpecificAttr = cast<AttrType>(Attr); + + if (SpecificAttr->args_size() == 0) { + // The mutex held is the "this" object. + addLock(ExpLocation, Parent, 0, LK); + return; + } + + for (iterator_type I = SpecificAttr->args_begin(), + E = SpecificAttr->args_end(); I != E; ++I) + addLock(ExpLocation, *I, Parent, LK); +} + +/// \brief When visiting CXXMemberCallExprs we need to examine the attributes on +/// the method that is being called and add, remove or check locks in the +/// lockset accordingly. +/// +/// FIXME: For classes annotated with one of the guarded annotations, we need +/// to treat const method calls as reads and non-const method calls as writes, +/// and check that the appropriate locks are held. Non-const method calls with +/// the same signature as const method calls can be also treated as reads. +/// +/// FIXME: We need to also visit CallExprs to catch/check global functions. +/// +/// FIXME: Do not flag an error for member variables accessed in constructors/ +/// destructors +void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) { + NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); + + SourceLocation ExpLocation = Exp->getExprLoc(); + Expr *Parent = Exp->getImplicitObjectArgument(); + + if(!D || !D->hasAttrs()) + return; + + AttrVec &ArgAttrs = D->getAttrs(); + for(unsigned i = 0; i < ArgAttrs.size(); ++i) { + Attr *Attr = ArgAttrs[i]; + switch (Attr->getKind()) { + // When we encounter an exclusive lock function, we need to add the lock + // to our lockset with kind exclusive. + case attr::ExclusiveLockFunction: + addLocksToSet<ExclusiveLockFunctionAttr>(LK_Exclusive, Attr, Exp); + break; + + // When we encounter a shared lock function, we need to add the lock + // to our lockset with kind shared. + case attr::SharedLockFunction: + addLocksToSet<SharedLockFunctionAttr>(LK_Shared, Attr, Exp); + break; + + // When we encounter an unlock function, we need to remove unlocked + // mutexes from the lockset, and flag a warning if they are not there. + case attr::UnlockFunction: { + UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr); + + if (UFAttr->args_size() == 0) { // The lock held is the "this" object. + removeLock(ExpLocation, Parent, 0); + break; + } + + for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(), + E = UFAttr->args_end(); I != E; ++I) + removeLock(ExpLocation, *I, Parent); + break; + } + + case attr::ExclusiveLocksRequired: { + ExclusiveLocksRequiredAttr *ELRAttr = + cast<ExclusiveLocksRequiredAttr>(Attr); + + for (ExclusiveLocksRequiredAttr::args_iterator + I = ELRAttr->args_begin(), E = ELRAttr->args_end(); I != E; ++I) + warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall); + break; + } + + case attr::SharedLocksRequired: { + SharedLocksRequiredAttr *SLRAttr = cast<SharedLocksRequiredAttr>(Attr); + + for (SharedLocksRequiredAttr::args_iterator I = SLRAttr->args_begin(), + E = SLRAttr->args_end(); I != E; ++I) + warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall); + break; + } + + case attr::LocksExcluded: { + LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr); + for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(), + E = LEAttr->args_end(); I != E; ++I) { + MutexID Mutex(*I, Parent); + if (!Mutex.isValid()) + Handler.handleInvalidLockExp((*I)->getExprLoc()); + else if (locksetContains(Mutex)) + Handler.handleFunExcludesLock(D->getName(), Mutex.getName(), + ExpLocation); + } + break; + } + + // Ignore other (non thread-safety) attributes + default: + break; + } + } +} + +} // end anonymous namespace + +/// \brief Compute the intersection of two locksets and issue warnings for any +/// locks in the symmetric difference. +/// +/// This function is used at a merge point in the CFG when comparing the lockset +/// of each branch being merged. For example, given the following sequence: +/// A; if () then B; else C; D; we need to check that the lockset after B and C +/// are the same. In the event of a difference, we use the intersection of these +/// two locksets at the start of D. +static Lockset intersectAndWarn(ThreadSafetyHandler &Handler, + const Lockset LSet1, const Lockset LSet2, + Lockset::Factory &Fact, LockErrorKind LEK) { + Lockset Intersection = LSet1; + for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) { + const MutexID &LSet2Mutex = I.getKey(); + const LockData &LSet2LockData = I.getData(); + if (const LockData *LD = LSet1.lookup(LSet2Mutex)) { + if (LD->LKind != LSet2LockData.LKind) { + Handler.handleExclusiveAndShared(LSet2Mutex.getName(), + LSet2LockData.AcquireLoc, + LD->AcquireLoc); + if (LD->LKind != LK_Exclusive) + Intersection = Fact.add(Intersection, LSet2Mutex, LSet2LockData); + } + } else { + Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(), + LSet2LockData.AcquireLoc, LEK); + } + } + + for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) { + if (!LSet2.contains(I.getKey())) { + const MutexID &Mutex = I.getKey(); + const LockData &MissingLock = I.getData(); + Handler.handleMutexHeldEndOfScope(Mutex.getName(), + MissingLock.AcquireLoc, LEK); + Intersection = Fact.remove(Intersection, Mutex); + } + } + return Intersection; +} + +static Lockset addLock(ThreadSafetyHandler &Handler, + Lockset::Factory &LocksetFactory, + Lockset &LSet, Expr *LockExp, LockKind LK, + SourceLocation Loc) { + MutexID Mutex(LockExp, 0); + if (!Mutex.isValid()) { + Handler.handleInvalidLockExp(LockExp->getExprLoc()); + return LSet; + } + LockData NewLock(Loc, LK); + return LocksetFactory.add(LSet, Mutex, NewLock); +} + +namespace clang { +namespace thread_safety { +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void runThreadSafetyAnalysis(AnalysisContext &AC, + ThreadSafetyHandler &Handler) { + CFG *CFGraph = AC.getCFG(); + if (!CFGraph) return; + const Decl *D = AC.getDecl(); + if (D && D->getAttr<NoThreadSafetyAnalysisAttr>()) return; + + Lockset::Factory LocksetFactory; + + // FIXME: Swith to SmallVector? Otherwise improve performance impact? + std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(), + LocksetFactory.getEmptyMap()); + std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(), + LocksetFactory.getEmptyMap()); + + // We need to explore the CFG via a "topological" ordering. + // That way, we will be guaranteed to have information about required + // predecessor locksets when exploring a new block. + TopologicallySortedCFG SortedGraph(CFGraph); + CFGBlockSet VisitedBlocks(CFGraph); + + if (!SortedGraph.empty() && D->hasAttrs()) { + const CFGBlock *FirstBlock = *SortedGraph.begin(); + Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()]; + const AttrVec &ArgAttrs = D->getAttrs(); + for(unsigned i = 0; i < ArgAttrs.size(); ++i) { + Attr *Attr = ArgAttrs[i]; + SourceLocation AttrLoc = Attr->getLocation(); + if (SharedLocksRequiredAttr *SLRAttr + = dyn_cast<SharedLocksRequiredAttr>(Attr)) { + for (SharedLocksRequiredAttr::args_iterator + SLRIter = SLRAttr->args_begin(), + SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter) + InitialLockset = addLock(Handler, LocksetFactory, InitialLockset, + *SLRIter, LK_Shared, + AttrLoc); + } else if (ExclusiveLocksRequiredAttr *ELRAttr + = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) { + for (ExclusiveLocksRequiredAttr::args_iterator + ELRIter = ELRAttr->args_begin(), + ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter) + InitialLockset = addLock(Handler, LocksetFactory, InitialLockset, + *ELRIter, LK_Exclusive, + AttrLoc); + } + } + } + + for (TopologicallySortedCFG::iterator I = SortedGraph.begin(), + E = SortedGraph.end(); I!= E; ++I) { + const CFGBlock *CurrBlock = *I; + int CurrBlockID = CurrBlock->getBlockID(); + + VisitedBlocks.insert(CurrBlock); + + // Use the default initial lockset in case there are no predecessors. + Lockset &Entryset = EntryLocksets[CurrBlockID]; + Lockset &Exitset = ExitLocksets[CurrBlockID]; + + // Iterate through the predecessor blocks and warn if the lockset for all + // predecessors is not the same. We take the entry lockset of the current + // block to be the intersection of all previous locksets. + // FIXME: By keeping the intersection, we may output more errors in future + // for a lock which is not in the intersection, but was in the union. We + // may want to also keep the union in future. As an example, let's say + // the intersection contains Mutex L, and the union contains L and M. + // Later we unlock M. At this point, we would output an error because we + // never locked M; although the real error is probably that we forgot to + // lock M on all code paths. Conversely, let's say that later we lock M. + // In this case, we should compare against the intersection instead of the + // union because the real error is probably that we forgot to unlock M on + // all code paths. + bool LocksetInitialized = false; + for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), + PE = CurrBlock->pred_end(); PI != PE; ++PI) { + + // if *PI -> CurrBlock is a back edge + if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) + continue; + + int PrevBlockID = (*PI)->getBlockID(); + if (!LocksetInitialized) { + Entryset = ExitLocksets[PrevBlockID]; + LocksetInitialized = true; + } else { + Entryset = intersectAndWarn(Handler, Entryset, + ExitLocksets[PrevBlockID], LocksetFactory, + LEK_LockedSomePredecessors); + } + } + + BuildLockset LocksetBuilder(Handler, Entryset, LocksetFactory); + for (CFGBlock::const_iterator BI = CurrBlock->begin(), + BE = CurrBlock->end(); BI != BE; ++BI) { + if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI)) + LocksetBuilder.Visit(const_cast<Stmt*>(CfgStmt->getStmt())); + } + Exitset = LocksetBuilder.getLockset(); + + // For every back edge from CurrBlock (the end of the loop) to another block + // (FirstLoopBlock) we need to check that the Lockset of Block is equal to + // the one held at the beginning of FirstLoopBlock. We can look up the + // Lockset held at the beginning of FirstLoopBlock in the EntryLockSets map. + for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), + SE = CurrBlock->succ_end(); SI != SE; ++SI) { + + // if CurrBlock -> *SI is *not* a back edge + if (*SI == 0 || !VisitedBlocks.alreadySet(*SI)) + continue; + + CFGBlock *FirstLoopBlock = *SI; + Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()]; + Lockset LoopEnd = ExitLocksets[CurrBlockID]; + intersectAndWarn(Handler, LoopEnd, PreLoop, LocksetFactory, + LEK_LockedSomeLoopIterations); + } + } + + Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()]; + Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()]; + + // FIXME: Should we call this function for all blocks which exit the function? + intersectAndWarn(Handler, InitialLockset, FinalLockset, LocksetFactory, + LEK_LockedAtEndOfFunction); +} + +/// \brief Helper function that returns a LockKind required for the given level +/// of access. +LockKind getLockKindFromAccessKind(AccessKind AK) { + switch (AK) { + case AK_Read : + return LK_Shared; + case AK_Written : + return LK_Exclusive; + } + llvm_unreachable("Unknown AccessKind"); +} +}} // end namespace clang::thread_safety diff --git a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index 1d6959d..9e98560 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -123,13 +123,7 @@ public: bool hasNoDeclarations() const { return declToIndex.size() == 0; } - - bool hasEntry(const VarDecl *vd) const { - return declToIndex.getValueIndex(vd).hasValue(); - } - - bool hasValues(const CFGBlock *block); - + void resetScratch(); ValueVector &getScratch() { return scratch; } @@ -170,7 +164,7 @@ ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) { /// This function pattern matches for a '&&' or '||' that appears at /// the beginning of a CFGBlock that also (1) has a terminator and /// (2) has no other elements. If such an expression is found, it is returned. -static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { +static const BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { if (block->empty()) return 0; @@ -178,7 +172,7 @@ static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { if (!cstmt) return 0; - BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt()); + const BinaryOperator *b = dyn_cast_or_null<BinaryOperator>(cstmt->getStmt()); if (!b || !b->isLogicalOp()) return 0; @@ -209,11 +203,6 @@ ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block, return lazyCreate(vals[idx].first); } -bool CFGBlockValues::hasValues(const CFGBlock *block) { - unsigned idx = block->getBlockID(); - return vals[idx].second != 0; -} - BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, bool shouldLazyCreate) { unsigned idx = block->getBlockID(); @@ -223,13 +212,6 @@ BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, return vals[idx]; } -void CFGBlockValues::mergeIntoScratch(ValueVector const &source, - bool isFirst) { - if (isFirst) - scratch = source; - else - scratch |= source; -} #if 0 static void printVector(const CFGBlock *block, ValueVector &bv, unsigned num) { @@ -240,8 +222,24 @@ static void printVector(const CFGBlock *block, ValueVector &bv, } llvm::errs() << " : " << num << '\n'; } + +static void printVector(const char *name, ValueVector const &bv) { + llvm::errs() << name << " : "; + for (unsigned i = 0; i < bv.size(); ++i) { + llvm::errs() << ' ' << bv[i]; + } + llvm::errs() << "\n"; +} #endif +void CFGBlockValues::mergeIntoScratch(ValueVector const &source, + bool isFirst) { + if (isFirst) + scratch = source; + else + scratch |= source; +} + bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) { ValueVector &dst = getValueVector(block, 0); bool changed = (dst != scratch); @@ -283,7 +281,7 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) { namespace { class DataflowWorklist { - llvm::SmallVector<const CFGBlock *, 20> worklist; + SmallVector<const CFGBlock *, 20> worklist; llvm::BitVector enqueuedBlocks; public: DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} @@ -336,23 +334,34 @@ public: const VarDecl *getDecl() const { return vd; } }; -class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> { +class TransferFunctions : public StmtVisitor<TransferFunctions> { CFGBlockValues &vals; const CFG &cfg; AnalysisContext ∾ UninitVariablesHandler *handler; - const DeclRefExpr *currentDR; - const Expr *currentVoidCast; - const bool flagBlockUses; + + /// The last DeclRefExpr seen when analyzing a block. Used to + /// cheat when detecting cases when the address of a variable is taken. + DeclRefExpr *lastDR; + + /// The last lvalue-to-rvalue conversion of a variable whose value + /// was uninitialized. Normally this results in a warning, but it is + /// possible to either silence the warning in some cases, or we + /// propagate the uninitialized value. + CastExpr *lastLoad; + + /// For some expressions, we want to ignore any post-processing after + /// visitation. + bool skipProcessUses; + public: TransferFunctions(CFGBlockValues &vals, const CFG &cfg, AnalysisContext &ac, - UninitVariablesHandler *handler, - bool flagBlockUses) - : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), - currentVoidCast(0), flagBlockUses(flagBlockUses) {} + UninitVariablesHandler *handler) + : vals(vals), cfg(cfg), ac(ac), handler(handler), + lastDR(0), lastLoad(0), + skipProcessUses(false) {} - const CFG &getCFG() { return cfg; } void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, bool isAlwaysUninit); @@ -362,53 +371,59 @@ public: void VisitUnaryOperator(UnaryOperator *uo); void VisitBinaryOperator(BinaryOperator *bo); void VisitCastExpr(CastExpr *ce); - void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se); - void VisitCXXTypeidExpr(CXXTypeidExpr *E); - void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); + void VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); + void Visit(Stmt *s); bool isTrackedVar(const VarDecl *vd) { return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); } FindVarResult findBlockVarDecl(Expr *ex); + + void ProcessUses(Stmt *s = 0); }; } +static const Expr *stripCasts(ASTContext &C, const Expr *Ex) { + while (Ex) { + Ex = Ex->IgnoreParenNoopCasts(C); + if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { + if (CE->getCastKind() == CK_LValueBitCast) { + Ex = CE->getSubExpr(); + continue; + } + } + break; + } + return Ex; +} + void TransferFunctions::reportUninit(const DeclRefExpr *ex, const VarDecl *vd, bool isAlwaysUnit) { if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); } -FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) { - if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) +FindVarResult TransferFunctions::findBlockVarDecl(Expr *ex) { + if (DeclRefExpr *dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) if (isTrackedVar(vd)) return FindVarResult(vd, dr); return FindVarResult(0, 0); } -void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt( - ObjCForCollectionStmt *fs) { - - Visit(fs->getCollection()); - +void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs) { // This represents an initialization of the 'element' value. Stmt *element = fs->getElement(); - const VarDecl* vd = 0; + const VarDecl *vd = 0; - if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) { + if (DeclStmt *ds = dyn_cast<DeclStmt>(element)) { vd = cast<VarDecl>(ds->getSingleDecl()); if (!isTrackedVar(vd)) vd = 0; - } - else { + } else { // Initialize the value of the reference variable. const FindVarResult &res = findBlockVarDecl(cast<Expr>(element)); vd = res.getDecl(); - if (!vd) { - Visit(element); - return; - } } if (vd) @@ -416,14 +431,10 @@ void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt( } void TransferFunctions::VisitBlockExpr(BlockExpr *be) { - if (!flagBlockUses || !handler) - return; const BlockDecl *bd = be->getBlockDecl(); for (BlockDecl::capture_const_iterator i = bd->capture_begin(), e = bd->capture_end() ; i != e; ++i) { const VarDecl *vd = i->getVariable(); - if (!vd->hasLocalStorage()) - continue; if (!isTrackedVar(vd)) continue; if (i->isByRef()) { @@ -431,19 +442,27 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) { continue; } Value v = vals[vd]; - if (isUninitialized(v)) + if (handler && isUninitialized(v)) handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); } } +void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { + // Record the last DeclRefExpr seen. This is an lvalue computation. + // We use this value to later detect if a variable "escapes" the analysis. + if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) + if (isTrackedVar(vd)) { + ProcessUses(); + lastDR = dr; + } +} + void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); DI != DE; ++DI) { if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) { if (isTrackedVar(vd)) { if (Expr *init = vd->getInit()) { - Visit(init); - // If the initializer consists solely of a reference to itself, we // explicitly mark the variable as uninitialized. This allows code // like the following: @@ -454,56 +473,48 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { // clients can detect this pattern and adjust their reporting // appropriately, but we need to continue to analyze subsequent uses // of the variable. - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init->IgnoreParenImpCasts()); - vals[vd] = (DRE && DRE->getDecl() == vd) ? Uninitialized - : Initialized; + if (init == lastLoad) { + const DeclRefExpr *DR + = cast<DeclRefExpr>(stripCasts(ac.getASTContext(), + lastLoad->getSubExpr())); + if (DR->getDecl() == vd) { + // int x = x; + // Propagate uninitialized value, but don't immediately report + // a problem. + vals[vd] = Uninitialized; + lastLoad = 0; + lastDR = 0; + if (handler) + handler->handleSelfInit(vd); + return; + } + } + + // All other cases: treat the new variable as initialized. + // This is a minor optimization to reduce the propagation + // of the analysis, since we will have already reported + // the use of the uninitialized value (which visiting the + // initializer). + vals[vd] = Initialized; } - } else if (Stmt *init = vd->getInit()) { - Visit(init); } } } } -void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { - // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - // If a DeclRefExpr is not involved in a load, we are essentially computing - // its address, either for assignment to a reference or via the '&' operator. - // In such cases, treat the variable as being initialized, since this - // analysis isn't powerful enough to do alias tracking. - if (dr != currentDR) - if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) - if (isTrackedVar(vd)) - vals[vd] = Initialized; -} - void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { if (bo->isAssignmentOp()) { const FindVarResult &res = findBlockVarDecl(bo->getLHS()); - if (const VarDecl* vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment" - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(bo->getRHS()); - Visit(bo->getLHS()); - + if (const VarDecl *vd = res.getDecl()) { ValueVector::reference val = vals[vd]; if (isUninitialized(val)) { if (bo->getOpcode() != BO_Assign) reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); - val = Initialized; + else + val = Initialized; } - return; } } - Visit(bo->getRHS()); - Visit(bo->getLHS()); } void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { @@ -514,86 +525,88 @@ void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { case clang::UO_PreInc: { const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); if (const VarDecl *vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in a unary operator ++/-- - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(uo->getSubExpr()); + assert(res.getDeclRefExpr() == lastDR); + // We null out lastDR to indicate we have fully processed it + // and we don't want the auto-value setting in Visit(). + lastDR = 0; ValueVector::reference val = vals[vd]; - if (isUninitialized(val)) { + if (isUninitialized(val)) reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); - // Don't cascade warnings. - val = Initialized; - } - return; } break; } default: break; } - Visit(uo->getSubExpr()); } void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { if (ce->getCastKind() == CK_LValueToRValue) { const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); - if (const VarDecl *vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - // Here we update 'currentDR' to be the one associated with this - // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we - // will know that we are not computing its lvalue for other purposes - // than to perform a load. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(ce->getSubExpr()); - if (currentVoidCast != ce) { - Value val = vals[vd]; - if (isUninitialized(val)) { - reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); - // Don't cascade warnings. - vals[vd] = Initialized; - } - } - return; + if (res.getDecl()) { + assert(res.getDeclRefExpr() == lastDR); + lastLoad = ce; } } + else if (ce->getCastKind() == CK_NoOp || + ce->getCastKind() == CK_LValueBitCast) { + skipProcessUses = true; + } else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) { if (cse->getType()->isVoidType()) { // e.g. (void) x; - SaveAndRestore<const Expr *> - lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens()); - Visit(cse->getSubExpr()); - return; + if (lastLoad == cse->getSubExpr()) { + // Squelch any detected load of an uninitialized value if + // we cast it to void. + lastLoad = 0; + lastDR = 0; + } } } - Visit(ce->getSubExpr()); } -void TransferFunctions::VisitUnaryExprOrTypeTraitExpr( - UnaryExprOrTypeTraitExpr *se) { - if (se->getKind() == UETT_SizeOf) { - if (se->getType()->isConstantSizeType()) +void TransferFunctions::Visit(clang::Stmt *s) { + skipProcessUses = false; + StmtVisitor<TransferFunctions>::Visit(s); + if (!skipProcessUses) + ProcessUses(s); +} + +void TransferFunctions::ProcessUses(Stmt *s) { + // This method is typically called after visiting a CFGElement statement + // in the CFG. We delay processing of reporting many loads of uninitialized + // values until here. + if (lastLoad) { + // If we just visited the lvalue-to-rvalue cast, there is nothing + // left to do. + if (lastLoad == s) + return; + + const DeclRefExpr *DR = + cast<DeclRefExpr>(stripCasts(ac.getASTContext(), + lastLoad->getSubExpr())); + const VarDecl *VD = cast<VarDecl>(DR->getDecl()); + + // If we reach here, we may have seen a load of an uninitialized value + // and it hasn't been casted to void or otherwise handled. In this + // situation, report the incident. + if (isUninitialized(vals[VD])) + reportUninit(DR, VD, isAlwaysUninit(vals[VD])); + + lastLoad = 0; + + if (DR == lastDR) { + lastDR = 0; return; - // Handle VLAs. - Visit(se->getArgumentExpr()); + } } -} -void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) { - // typeid(expression) is potentially evaluated when the argument is - // a glvalue of polymorphic type. (C++ 5.2.8p2-3) - if (!E->isTypeOperand() && E->Classify(ac.getASTContext()).isGLValue()) { - QualType SubExprTy = E->getExprOperand()->getType(); - if (const RecordType *Record = SubExprTy->getAs<RecordType>()) - if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic()) - Visit(E->getExprOperand()); + // Any other uses of 'lastDR' involve taking an lvalue of variable. + // In this case, it "escapes" the analysis. + if (lastDR && lastDR != s) { + vals[cast<VarDecl>(lastDR->getDecl())] = Initialized; + lastDR = 0; } } @@ -604,8 +617,7 @@ void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) { static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisContext &ac, CFGBlockValues &vals, llvm::BitVector &wasAnalyzed, - UninitVariablesHandler *handler = 0, - bool flagBlockUses = false) { + UninitVariablesHandler *handler = 0) { wasAnalyzed[block->getBlockID()] = true; @@ -623,8 +635,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); valsAB.first = vA.first; valsAB.second = &vals.getScratch(); - } - else { + } else { // Merge the 'T' bits from the first and second. assert(b->getOpcode() == BO_LOr); vals.mergeIntoScratch(*vA.first, true); @@ -640,17 +651,21 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, bool isFirst = true; for (CFGBlock::const_pred_iterator I = block->pred_begin(), E = block->pred_end(); I != E; ++I) { - vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst); - isFirst = false; + const CFGBlock *pred = *I; + if (wasAnalyzed[pred->getBlockID()]) { + vals.mergeIntoScratch(vals.getValueVector(pred, block), isFirst); + isFirst = false; + } } // Apply the transfer function. - TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses); + TransferFunctions tf(vals, cfg, ac, handler); for (CFGBlock::const_iterator I = block->begin(), E = block->end(); I != E; ++I) { if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) { - tf.BlockStmt_Visit(cs->getStmt()); + tf.Visit(const_cast<Stmt*>(cs->getStmt())); } } + tf.ProcessUses(); return vals.updateValueVectorWithScratch(block); } @@ -685,6 +700,7 @@ void clang::runUninitializedVariablesAnalysis( llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); worklist.enqueueSuccessors(&cfg.getEntry()); llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); + wasAnalyzed[cfg.getEntry().getBlockID()] = true; while (const CFGBlock *block = worklist.dequeue()) { // Did the block change? @@ -697,9 +713,9 @@ void clang::runUninitializedVariablesAnalysis( // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { - if (wasAnalyzed[(*BI)->getBlockID()]) { - runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler, - /* flagBlockUses */ true); + const CFGBlock *block = *BI; + if (wasAnalyzed[block->getBlockID()]) { + runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler); ++stats.NumBlockVisits; } } diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp index 7df24a0..7bdcdc6 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp @@ -32,11 +32,15 @@ const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { return TSRecords[ID - Builtin::FirstTSBuiltin]; } -Builtin::Context::Context(const TargetInfo &Target) { +Builtin::Context::Context() { // Get the target specific builtins from the target. TSRecords = 0; NumTSRecords = 0; - Target.getTargetBuiltins(TSRecords, NumTSRecords); +} + +void Builtin::Context::InitializeTarget(const TargetInfo &Target) { + assert(NumTSRecords == 0 && "Already initialized target?"); + Target.getTargetBuiltins(TSRecords, NumTSRecords); } /// InitializeBuiltins - Mark the identifiers for all the builtins with their @@ -59,7 +63,7 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, } void -Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, +Builtin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names, bool NoBuiltins) { // Final all target-independent names for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index ae363a0..e5f3901 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -20,21 +20,22 @@ using namespace clang; -static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, +static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, const char *Modifier, unsigned ML, const char *Argument, unsigned ArgLen, - const Diagnostic::ArgumentValue *PrevArgs, + const DiagnosticsEngine::ArgumentValue *PrevArgs, unsigned NumPrevArgs, - llvm::SmallVectorImpl<char> &Output, + SmallVectorImpl<char> &Output, void *Cookie, - llvm::SmallVectorImpl<intptr_t> &QualTypeVals) { + SmallVectorImpl<intptr_t> &QualTypeVals) { const char *Str = "<can't format argument>"; Output.append(Str, Str+strlen(Str)); } -Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, - DiagnosticClient *client, bool ShouldOwnClient) +DiagnosticsEngine::DiagnosticsEngine( + const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, + DiagnosticConsumer *client, bool ShouldOwnClient) : Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient), SourceMgr(0) { ArgToStringFn = DummyArgToStringFn; @@ -43,6 +44,7 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, AllExtensionsSilenced = 0; IgnoreAllWarnings = false; WarningsAsErrors = false; + EnableAllWarnings = false; ErrorsAsFatal = false; SuppressSystemWarnings = false; SuppressAllDiagnostics = false; @@ -55,12 +57,13 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, Reset(); } -Diagnostic::~Diagnostic() { +DiagnosticsEngine::~DiagnosticsEngine() { if (OwnsDiagClient) delete Client; } -void Diagnostic::setClient(DiagnosticClient *client, bool ShouldOwnClient) { +void DiagnosticsEngine::setClient(DiagnosticConsumer *client, + bool ShouldOwnClient) { if (OwnsDiagClient && Client) delete Client; @@ -68,11 +71,11 @@ void Diagnostic::setClient(DiagnosticClient *client, bool ShouldOwnClient) { OwnsDiagClient = ShouldOwnClient; } -void Diagnostic::pushMappings(SourceLocation Loc) { +void DiagnosticsEngine::pushMappings(SourceLocation Loc) { DiagStateOnPushStack.push_back(GetCurDiagState()); } -bool Diagnostic::popMappings(SourceLocation Loc) { +bool DiagnosticsEngine::popMappings(SourceLocation Loc) { if (DiagStateOnPushStack.empty()) return false; @@ -84,7 +87,7 @@ bool Diagnostic::popMappings(SourceLocation Loc) { return true; } -void Diagnostic::Reset() { +void DiagnosticsEngine::Reset() { ErrorOccurred = false; FatalErrorOccurred = false; UnrecoverableErrorOccurred = false; @@ -92,11 +95,13 @@ void Diagnostic::Reset() { NumWarnings = 0; NumErrors = 0; NumErrorsSuppressed = 0; + TrapNumErrorsOccurred = 0; + TrapNumUnrecoverableErrorsOccurred = 0; CurDiagID = ~0U; // Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes - // using a Diagnostic associated to a translation unit that follow - // diagnostics from a Diagnostic associated to anoter t.u. will not be + // using a DiagnosticsEngine associated to a translation unit that follow + // diagnostics from a DiagnosticsEngine associated to anoter t.u. will not be // displayed. LastDiagLevel = (DiagnosticIDs::Level)-1; DelayedDiagID = 0; @@ -112,8 +117,8 @@ void Diagnostic::Reset() { PushDiagStatePoint(&DiagStates.back(), SourceLocation()); } -void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, - llvm::StringRef Arg2) { +void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, + StringRef Arg2) { if (DelayedDiagID) return; @@ -122,15 +127,15 @@ void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, DelayedDiagArg2 = Arg2.str(); } -void Diagnostic::ReportDelayed() { +void DiagnosticsEngine::ReportDelayed() { Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2; DelayedDiagID = 0; DelayedDiagArg1.clear(); DelayedDiagArg2.clear(); } -Diagnostic::DiagStatePointsTy::iterator -Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const { +DiagnosticsEngine::DiagStatePointsTy::iterator +DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const { assert(!DiagStatePoints.empty()); assert(DiagStatePoints.front().Loc.isInvalid() && "Should have created a DiagStatePoint for command-line"); @@ -155,7 +160,7 @@ Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const { /// /// \param The source location that this change of diagnostic state should /// take affect. It can be null if we are setting the latest state. -void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, +void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, SourceLocation L) { assert(Diag < diag::DIAG_UPPER_LIMIT && "Can only map builtin diagnostics"); @@ -167,10 +172,19 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, bool isPragma = L.isValid(); FullSourceLoc Loc(L, *SourceMgr); FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc; + DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make( + Map, /*IsUser=*/true, isPragma); + + // If this is a pragma mapping, then set the diagnostic mapping flags so that + // we override command line options. + if (isPragma) { + MappingInfo.setNoWarningAsError(true); + MappingInfo.setNoErrorAsFatal(true); + } // Common case; setting all the diagnostics of a group in one place. if (Loc.isInvalid() || Loc == LastStateChangePos) { - setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma); + GetCurDiagState()->setMappingInfo(Diag, MappingInfo); return; } @@ -183,7 +197,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, // the new state became active. DiagStates.push_back(*GetCurDiagState()); PushDiagStatePoint(&DiagStates.back(), Loc); - setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma); + GetCurDiagState()->setMappingInfo(Diag, MappingInfo); return; } @@ -196,12 +210,12 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, // Update all diagnostic states that are active after the given location. for (DiagStatePointsTy::iterator I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) { - setDiagnosticMappingInternal(Diag, Map, I->State, true, isPragma); + GetCurDiagState()->setMappingInfo(Diag, MappingInfo); } // If the location corresponds to an existing point, just update its state. if (Pos->Loc == Loc) { - setDiagnosticMappingInternal(Diag, Map, Pos->State, true, isPragma); + GetCurDiagState()->setMappingInfo(Diag, MappingInfo); return; } @@ -210,12 +224,86 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, Pos->Loc.isBeforeInTranslationUnitThan(Loc); DiagStates.push_back(*Pos->State); DiagState *NewState = &DiagStates.back(); - setDiagnosticMappingInternal(Diag, Map, NewState, true, isPragma); + GetCurDiagState()->setMappingInfo(Diag, MappingInfo); DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState, FullSourceLoc(Loc, *SourceMgr))); } -void Diagnostic::Report(const StoredDiagnostic &storedDiag) { +bool DiagnosticsEngine::setDiagnosticGroupMapping( + StringRef Group, diag::Mapping Map, SourceLocation Loc) +{ + // Get the diagnostics in this group. + llvm::SmallVector<diag::kind, 8> GroupDiags; + if (Diags->getDiagnosticsInGroup(Group, GroupDiags)) + return true; + + // Set the mapping. + for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) + setDiagnosticMapping(GroupDiags[i], Map, Loc); + + return false; +} + +bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group, + bool Enabled) { + // If we are enabling this feature, just set the diagnostic mappings to map to + // errors. + if (Enabled) + return setDiagnosticGroupMapping(Group, diag::MAP_ERROR); + + // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and + // potentially downgrade anything already mapped to be a warning. + + // Get the diagnostics in this group. + llvm::SmallVector<diag::kind, 8> GroupDiags; + if (Diags->getDiagnosticsInGroup(Group, GroupDiags)) + return true; + + // Perform the mapping change. + for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { + DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo( + GroupDiags[i]); + + if (Info.getMapping() == diag::MAP_ERROR || + Info.getMapping() == diag::MAP_FATAL) + Info.setMapping(diag::MAP_WARNING); + + Info.setNoWarningAsError(true); + } + + return false; +} + +bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group, + bool Enabled) { + // If we are enabling this feature, just set the diagnostic mappings to map to + // fatal errors. + if (Enabled) + return setDiagnosticGroupMapping(Group, diag::MAP_FATAL); + + // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and + // potentially downgrade anything already mapped to be an error. + + // Get the diagnostics in this group. + llvm::SmallVector<diag::kind, 8> GroupDiags; + if (Diags->getDiagnosticsInGroup(Group, GroupDiags)) + return true; + + // Perform the mapping change. + for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { + DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo( + GroupDiags[i]); + + if (Info.getMapping() == diag::MAP_FATAL) + Info.setMapping(diag::MAP_ERROR); + + Info.setNoErrorAsFatal(true); + } + + return false; +} + +void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); CurDiagLoc = storedDiag.getLocation(); @@ -232,19 +320,20 @@ void Diagnostic::Report(const StoredDiagnostic &storedDiag) { DiagRanges[i++] = *RI; NumFixItHints = storedDiag.fixit_size(); - assert(NumFixItHints < Diagnostic::MaxFixItHints && "Too many fix-it hints!"); + assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints && + "Too many fix-it hints!"); i = 0; for (StoredDiagnostic::fixit_iterator FI = storedDiag.fixit_begin(), FE = storedDiag.fixit_end(); FI != FE; ++FI) FixItHints[i++] = *FI; - assert(Client && "DiagnosticClient not set!"); + assert(Client && "DiagnosticConsumer not set!"); Level DiagLevel = storedDiag.getLevel(); - DiagnosticInfo Info(this, storedDiag.getMessage()); + Diagnostic Info(this, storedDiag.getMessage()); Client->HandleDiagnostic(DiagLevel, Info); if (Client->IncludeInDiagnosticCounts()) { - if (DiagLevel == Diagnostic::Warning) + if (DiagLevel == DiagnosticsEngine::Warning) ++NumWarnings; } @@ -263,11 +352,11 @@ bool DiagnosticBuilder::Emit() { if (DiagObj == 0) return false; // When emitting diagnostics, we set the final argument count into - // the Diagnostic object. + // the DiagnosticsEngine object. FlushCounts(); // Process the diagnostic, sending the accumulated information to the - // DiagnosticClient. + // DiagnosticConsumer. bool Emitted = DiagObj->ProcessDiag(); // Clear out the current diagnostic object. @@ -285,16 +374,16 @@ bool DiagnosticBuilder::Emit() { } -DiagnosticClient::~DiagnosticClient() {} +DiagnosticConsumer::~DiagnosticConsumer() {} -void DiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { +void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { if (!IncludeInDiagnosticCounts()) return; - if (DiagLevel == Diagnostic::Warning) + if (DiagLevel == DiagnosticsEngine::Warning) ++NumWarnings; - else if (DiagLevel >= Diagnostic::Error) + else if (DiagLevel >= DiagnosticsEngine::Error) ++NumErrors; } @@ -337,9 +426,9 @@ static const char *ScanFormat(const char *I, const char *E, char Target) { /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. /// This is very useful for certain classes of variant diagnostics. -static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo, +static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, - llvm::SmallVectorImpl<char> &OutStr) { + SmallVectorImpl<char> &OutStr) { const char *ArgumentEnd = Argument+ArgumentLen; // Skip over 'ValNo' |'s. @@ -362,7 +451,7 @@ static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo, /// letter 's' to the string if the value is not 1. This is used in cases like /// this: "you idiot, you have %4 parameter%s4!". static void HandleIntegerSModifier(unsigned ValNo, - llvm::SmallVectorImpl<char> &OutStr) { + SmallVectorImpl<char> &OutStr) { if (ValNo != 1) OutStr.push_back('s'); } @@ -372,7 +461,7 @@ static void HandleIntegerSModifier(unsigned ValNo, /// to the first ordinal. Currently this is hard-coded to use the /// English form. static void HandleOrdinalModifier(unsigned ValNo, - llvm::SmallVectorImpl<char> &OutStr) { + SmallVectorImpl<char> &OutStr) { assert(ValNo != 0 && "ValNo must be strictly positive!"); llvm::raw_svector_ostream Out(OutStr); @@ -495,9 +584,9 @@ static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) { /// {1:form0|[2,4]:form1|:form2} /// Polish (requires repeated form): /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2} -static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo, +static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, - llvm::SmallVectorImpl<char> &OutStr) { + SmallVectorImpl<char> &OutStr) { const char *ArgumentEnd = Argument + ArgumentLen; while (1) { assert(Argument < ArgumentEnd && "Plural expression didn't match."); @@ -523,34 +612,34 @@ static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo, /// FormatDiagnostic - Format this diagnostic into a string, substituting the /// formal arguments into the %0 slots. The result is appended onto the Str /// array. -void DiagnosticInfo:: -FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { +void Diagnostic:: +FormatDiagnostic(SmallVectorImpl<char> &OutStr) const { if (!StoredDiagMessage.empty()) { OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end()); return; } - llvm::StringRef Diag = + StringRef Diag = getDiags()->getDiagnosticIDs()->getDescription(getID()); FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); } -void DiagnosticInfo:: +void Diagnostic:: FormatDiagnostic(const char *DiagStr, const char *DiagEnd, - llvm::SmallVectorImpl<char> &OutStr) const { + SmallVectorImpl<char> &OutStr) const { /// FormattedArgs - Keep track of all of the arguments formatted by /// ConvertArgToString and pass them into subsequent calls to /// ConvertArgToString, allowing the implementation to avoid redundancies in /// obvious cases. - llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs; + SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs; /// QualTypeVals - Pass a vector of arrays so that QualType names can be /// compared to see if more information is needed to be printed. - llvm::SmallVector<intptr_t, 2> QualTypeVals; + SmallVector<intptr_t, 2> QualTypeVals; for (unsigned i = 0, e = getNumArgs(); i < e; ++i) - if (getArgKind(i) == Diagnostic::ak_qualtype) + if (getArgKind(i) == DiagnosticsEngine::ak_qualtype) QualTypeVals.push_back(getRawArg(i)); while (DiagStr != DiagEnd) { @@ -600,17 +689,17 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); unsigned ArgNo = *DiagStr++ - '0'; - Diagnostic::ArgumentKind Kind = getArgKind(ArgNo); + DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo); switch (Kind) { // ---- STRINGS ---- - case Diagnostic::ak_std_string: { + case DiagnosticsEngine::ak_std_string: { const std::string &S = getArgStdStr(ArgNo); assert(ModifierLen == 0 && "No modifiers for strings yet"); OutStr.append(S.begin(), S.end()); break; } - case Diagnostic::ak_c_string: { + case DiagnosticsEngine::ak_c_string: { const char *S = getArgCStr(ArgNo); assert(ModifierLen == 0 && "No modifiers for strings yet"); @@ -622,7 +711,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, break; } // ---- INTEGERS ---- - case Diagnostic::ak_sint: { + case DiagnosticsEngine::ak_sint: { int Val = getArgSInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { @@ -641,7 +730,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, } break; } - case Diagnostic::ak_uint: { + case DiagnosticsEngine::ak_uint: { unsigned Val = getArgUInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { @@ -660,7 +749,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, break; } // ---- NAMES and TYPES ---- - case Diagnostic::ak_identifierinfo: { + case DiagnosticsEngine::ak_identifierinfo: { const IdentifierInfo *II = getArgIdentifier(ArgNo); assert(ModifierLen == 0 && "No modifiers for strings yet"); @@ -674,11 +763,11 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } - case Diagnostic::ak_qualtype: - case Diagnostic::ak_declarationname: - case Diagnostic::ak_nameddecl: - case Diagnostic::ak_nestednamespec: - case Diagnostic::ak_declcontext: + case DiagnosticsEngine::ak_qualtype: + case DiagnosticsEngine::ak_declarationname: + case DiagnosticsEngine::ak_nameddecl: + case DiagnosticsEngine::ak_nestednamespec: + case DiagnosticsEngine::ak_declcontext: getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), Modifier, ModifierLen, Argument, ArgumentLen, @@ -690,10 +779,10 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, // Remember this argument info for subsequent formatting operations. Turn // std::strings into a null terminated string to make it be the same case as // all the other ones. - if (Kind != Diagnostic::ak_std_string) + if (Kind != DiagnosticsEngine::ak_std_string) FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); else - FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string, + FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string, (intptr_t)getArgStdStr(ArgNo).c_str())); } @@ -701,12 +790,12 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, StoredDiagnostic::StoredDiagnostic() { } -StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, unsigned ID, - llvm::StringRef Message) +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message) : ID(ID), Level(Level), Loc(), Message(Message) { } -StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) : ID(Info.getID()), Level(Level) { assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && @@ -726,13 +815,23 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, FixIts.push_back(Info.getFixItHint(I)); } +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message, FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Fixits) + : ID(ID), Level(Level), Loc(Loc), Message(Message) +{ + this->Ranges.assign(Ranges.begin(), Ranges.end()); + this->FixIts.assign(FixIts.begin(), FixIts.end()); +} + StoredDiagnostic::~StoredDiagnostic() { } /// IncludeInDiagnosticCounts - This method (whose default implementation /// returns true) indicates whether the diagnostics handled by this -/// DiagnosticClient should be included in the number of diagnostics -/// reported by Diagnostic. -bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; } +/// DiagnosticConsumer should be included in the number of diagnostics +/// reported by DiagnosticsEngine. +bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; } PartialDiagnostic::StorageAllocator::StorageAllocator() { for (unsigned I = 0; I != NumCached; ++I) diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index 147ba7e..9481287 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -21,6 +21,8 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorHandling.h" #include <map> using namespace clang; @@ -45,6 +47,8 @@ struct StaticDiagInfoRec { unsigned Class : 3; unsigned SFINAE : 1; unsigned AccessControl : 1; + unsigned WarnNoWerror : 1; + unsigned WarnShowInSystemHeader : 1; unsigned Category : 5; uint8_t NameLen; @@ -61,21 +65,21 @@ struct StaticDiagInfoRec { const char *BriefExplanationStr; const char *FullExplanationStr; - llvm::StringRef getName() const { - return llvm::StringRef(NameStr, NameLen); + StringRef getName() const { + return StringRef(NameStr, NameLen); } - llvm::StringRef getOptionGroup() const { - return llvm::StringRef(OptionGroupStr, OptionGroupLen); + StringRef getOptionGroup() const { + return StringRef(OptionGroupStr, OptionGroupLen); } - llvm::StringRef getDescription() const { - return llvm::StringRef(DescriptionStr, DescriptionLen); + StringRef getDescription() const { + return StringRef(DescriptionStr, DescriptionLen); } - llvm::StringRef getBriefExplanation() const { - return llvm::StringRef(BriefExplanationStr, BriefExplanationLen); + StringRef getBriefExplanation() const { + return StringRef(BriefExplanationStr, BriefExplanationLen); } - llvm::StringRef getFullExplanation() const { - return llvm::StringRef(FullExplanationStr, FullExplanationLen); + StringRef getFullExplanation() const { + return StringRef(FullExplanationStr, FullExplanationLen); } bool operator<(const StaticDiagInfoRec &RHS) const { @@ -88,8 +92,8 @@ struct StaticDiagNameIndexRec { unsigned short DiagID; uint8_t NameLen; - llvm::StringRef getName() const { - return llvm::StringRef(NameStr, NameLen); + StringRef getName() const { + return StringRef(NameStr, NameLen); } bool operator<(const StaticDiagNameIndexRec &RHS) const { @@ -114,8 +118,10 @@ public: static const StaticDiagInfoRec StaticDiagInfo[] = { #define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ - SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \ + CATEGORY,BRIEF,FULL) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, \ + NOWERROR, SHOWINSYSHEADER, CATEGORY, \ STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \ STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \ STR_SIZE(FULL, uint16_t), \ @@ -129,7 +135,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static const unsigned StaticDiagInfoSize = @@ -166,7 +172,8 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 }; + StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find); @@ -177,19 +184,36 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { return Found; } -static unsigned GetDefaultDiagMapping(unsigned DiagID) { - if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return Info->Mapping; - return diag::MAP_FATAL; +static DiagnosticMappingInfo GetDefaultDiagMappingInfo(unsigned DiagID) { + DiagnosticMappingInfo Info = DiagnosticMappingInfo::Make( + diag::MAP_FATAL, /*IsUser=*/false, /*IsPragma=*/false); + + if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) { + Info.setMapping((diag::Mapping) StaticInfo->Mapping); + + if (StaticInfo->WarnNoWerror) { + assert(Info.getMapping() == diag::MAP_WARNING && + "Unexpected mapping with no-Werror bit!"); + Info.setNoWarningAsError(true); + } + + if (StaticInfo->WarnShowInSystemHeader) { + assert(Info.getMapping() == diag::MAP_WARNING && + "Unexpected mapping with show-in-system-header bit!"); + Info.setShowInSystemHeader(true); + } + } + + return Info; } /// getWarningOptionForDiag - Return the lowest-level warning option that /// enables the specified diagnostic. If there is no -Wfoo flag that controls /// the diagnostic, this returns null. -llvm::StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { +StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) return Info->getOptionGroup(); - return llvm::StringRef(); + return StringRef(); } /// getCategoryNumberForDiag - Return the category number that a specified @@ -206,12 +230,28 @@ namespace { const char *NameStr; uint8_t NameLen; - llvm::StringRef getName() const { - return llvm::StringRef(NameStr, NameLen); + StringRef getName() const { + return StringRef(NameStr, NameLen); } }; } +// Unfortunately, the split between DiagnosticIDs and Diagnostic is not +// particularly clean, but for now we just implement this method here so we can +// access GetDefaultDiagMapping. +DiagnosticMappingInfo &DiagnosticsEngine::DiagState::getOrAddMappingInfo( + diag::kind Diag) +{ + std::pair<iterator, bool> Result = DiagMap.insert( + std::make_pair(Diag, DiagnosticMappingInfo())); + + // Initialize the entry if we added it. + if (Result.second) + Result.first->second = GetDefaultDiagMappingInfo(Diag); + + return Result.first->second; +} + static const StaticDiagCategoryRec CategoryNameTable[] = { #define GET_CATEGORY_TABLE #define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) }, @@ -228,9 +268,9 @@ unsigned DiagnosticIDs::getNumberOfCategories() { /// getCategoryNameFromID - Given a category ID, return the name of the /// category, an empty string if CategoryID is zero, or null if CategoryID is /// invalid. -llvm::StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { +StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { if (CategoryID >= getNumberOfCategories()) - return llvm::StringRef(); + return StringRef(); return CategoryNameTable[CategoryID].getName(); } @@ -256,20 +296,23 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { } /// getName - Given a diagnostic ID, return its name -llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) { +StringRef DiagnosticIDs::getName(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) return Info->getName(); - return llvm::StringRef(); + return StringRef(); } /// getIdFromName - Given a diagnostic name, return its ID, or 0 -unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) { +unsigned DiagnosticIDs::getIdFromName(StringRef Name) { const StaticDiagNameIndexRec *StaticDiagNameIndexEnd = StaticDiagNameIndex + StaticDiagNameIndexSize; if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; } - StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() }; + assert(Name.size() == static_cast<uint8_t>(Name.size()) && + "Name is too long"); + StaticDiagNameIndexRec Find = { Name.data(), 0, + static_cast<uint8_t>(Name.size()) }; const StaticDiagNameIndexRec *Found = std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find); @@ -282,18 +325,18 @@ unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) { /// getBriefExplanation - Given a diagnostic ID, return a brief explanation /// of the issue -llvm::StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) { +StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) return Info->getBriefExplanation(); - return llvm::StringRef(); + return StringRef(); } /// getFullExplanation - Given a diagnostic ID, return a full explanation /// of the issue -llvm::StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) { +StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) return Info->getFullExplanation(); - return llvm::StringRef(); + return StringRef(); } /// getBuiltinDiagClass - Return the class field of the diagnostic. @@ -305,6 +348,35 @@ static unsigned getBuiltinDiagClass(unsigned DiagID) { } //===----------------------------------------------------------------------===// +// diag_iterator +//===----------------------------------------------------------------------===// + +llvm::StringRef DiagnosticIDs::diag_iterator::getDiagName() const { + return static_cast<const StaticDiagNameIndexRec*>(impl)->getName(); +} + +unsigned DiagnosticIDs::diag_iterator::getDiagID() const { + return static_cast<const StaticDiagNameIndexRec*>(impl)->DiagID; +} + +DiagnosticIDs::diag_iterator &DiagnosticIDs::diag_iterator::operator++() { + const StaticDiagNameIndexRec* ptr = + static_cast<const StaticDiagNameIndexRec*>(impl);; + ++ptr; + impl = ptr; + return *this; +} + +DiagnosticIDs::diag_iterator DiagnosticIDs::diags_begin() { + return DiagnosticIDs::diag_iterator(StaticDiagNameIndex); +} + +DiagnosticIDs::diag_iterator DiagnosticIDs::diags_end() { + return DiagnosticIDs::diag_iterator(StaticDiagNameIndex + + StaticDiagNameIndexSize); +} + +//===----------------------------------------------------------------------===// // Custom Diagnostic information //===----------------------------------------------------------------------===// @@ -318,7 +390,7 @@ namespace clang { /// getDescription - Return the description of the specified custom /// diagnostic. - llvm::StringRef getDescription(unsigned DiagID) const { + StringRef getDescription(unsigned DiagID) const { assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && "Invalid diagnosic ID"); return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second; @@ -331,7 +403,7 @@ namespace clang { return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; } - unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message, + unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, DiagnosticIDs &Diags) { DiagDesc D(L, Message); // Check to see if it already exists. @@ -366,7 +438,7 @@ DiagnosticIDs::~DiagnosticIDs() { /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. -unsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) { +unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) { if (CustomDiagInfo == 0) CustomDiagInfo = new diag::CustomDiagInfo(); return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); @@ -400,32 +472,39 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID, getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) return false; - EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE; + EnabledByDefault = + GetDefaultDiagMappingInfo(DiagID).getMapping() != diag::MAP_IGNORE; return true; } +bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) { + if (DiagID >= diag::DIAG_UPPER_LIMIT) + return false; + + return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR; +} + /// getDescription - Given a diagnostic ID, return a description of the /// issue. -llvm::StringRef DiagnosticIDs::getDescription(unsigned DiagID) const { +StringRef DiagnosticIDs::getDescription(unsigned DiagID) const { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) return Info->getDescription(); return CustomDiagInfo->getDescription(DiagID); } -/// getDiagnosticLevel - Based on the way the client configured the Diagnostic -/// object, classify the specified diagnostic ID into a Level, consumable by -/// the DiagnosticClient. +/// getDiagnosticLevel - Based on the way the client configured the +/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level, +/// by consumable the DiagnosticClient. DiagnosticIDs::Level DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, - const Diagnostic &Diag, - diag::Mapping *mapping) const { + const DiagnosticsEngine &Diag) const { // Handle custom diagnostics, which cannot be mapped. if (DiagID >= diag::DIAG_UPPER_LIMIT) return CustomDiagInfo->getLevel(DiagID); unsigned DiagClass = getBuiltinDiagClass(DiagID); assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!"); - return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping); + return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag); } /// \brief Based on the way the client configured the Diagnostic @@ -437,130 +516,119 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, DiagnosticIDs::Level DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, SourceLocation Loc, - const Diagnostic &Diag, - diag::Mapping *mapping) const { + const DiagnosticsEngine &Diag) const { // Specific non-error diagnostics may be mapped to various levels from ignored // to error. Errors can only be mapped to fatal. DiagnosticIDs::Level Result = DiagnosticIDs::Fatal; - Diagnostic::DiagStatePointsTy::iterator + DiagnosticsEngine::DiagStatePointsTy::iterator Pos = Diag.GetDiagStatePointForLoc(Loc); - Diagnostic::DiagState *State = Pos->State; - - // Get the mapping information, if unset, compute it lazily. - unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID, - State); - if (MappingInfo == 0) { - MappingInfo = GetDefaultDiagMapping(DiagID); - Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false); - } - - if (mapping) - *mapping = (diag::Mapping) (MappingInfo & 7); + DiagnosticsEngine::DiagState *State = Pos->State; - bool ShouldEmitInSystemHeader = false; + // Get the mapping information, or compute it lazily. + DiagnosticMappingInfo &MappingInfo = State->getOrAddMappingInfo( + (diag::kind)DiagID); - switch (MappingInfo & 7) { - default: assert(0 && "Unknown mapping!"); + switch (MappingInfo.getMapping()) { + default: llvm_unreachable("Unknown mapping!"); case diag::MAP_IGNORE: - // Ignore this, unless this is an extension diagnostic and we're mapping - // them onto warnings or errors. - if (!isBuiltinExtensionDiag(DiagID) || // Not an extension - Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored - (MappingInfo & 8) != 0) // User explicitly mapped it. - return DiagnosticIDs::Ignored; + Result = DiagnosticIDs::Ignored; + break; + case diag::MAP_WARNING: Result = DiagnosticIDs::Warning; - if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error; - if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) - Result = DiagnosticIDs::Fatal; break; case diag::MAP_ERROR: Result = DiagnosticIDs::Error; - if (Diag.ErrorsAsFatal) - Result = DiagnosticIDs::Fatal; break; case diag::MAP_FATAL: Result = DiagnosticIDs::Fatal; break; - case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER: - ShouldEmitInSystemHeader = true; - // continue as MAP_WARNING. - case diag::MAP_WARNING: - // If warnings are globally mapped to ignore or error, do it. - if (Diag.IgnoreAllWarnings) - return DiagnosticIDs::Ignored; + } + // Upgrade ignored diagnostics if -Weverything is enabled. + if (Diag.EnableAllWarnings && Result == DiagnosticIDs::Ignored && + !MappingInfo.isUser()) Result = DiagnosticIDs::Warning; - // If this is an extension diagnostic and we're in -pedantic-error mode, and - // if the user didn't explicitly map it, upgrade to an error. - if (Diag.ExtBehavior == Diagnostic::Ext_Error && - (MappingInfo & 8) == 0 && - isBuiltinExtensionDiag(DiagID)) - Result = DiagnosticIDs::Error; - - if (Diag.WarningsAsErrors) - Result = DiagnosticIDs::Error; - if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) - Result = DiagnosticIDs::Fatal; - break; + // Ignore -pedantic diagnostics inside __extension__ blocks. + // (The diagnostics controlled by -pedantic are the extension diagnostics + // that are not enabled by default.) + bool EnabledByDefault; + bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault); + if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault) + return DiagnosticIDs::Ignored; - case diag::MAP_WARNING_NO_WERROR: - // Diagnostics specified with -Wno-error=foo should be set to warnings, but - // not be adjusted by -Werror or -pedantic-errors. - Result = DiagnosticIDs::Warning; + // For extension diagnostics that haven't been explicitly mapped, check if we + // should upgrade the diagnostic. + if (IsExtensionDiag && !MappingInfo.isUser()) { + switch (Diag.ExtBehavior) { + case DiagnosticsEngine::Ext_Ignore: + break; + case DiagnosticsEngine::Ext_Warn: + // Upgrade ignored diagnostics to warnings. + if (Result == DiagnosticIDs::Ignored) + Result = DiagnosticIDs::Warning; + break; + case DiagnosticsEngine::Ext_Error: + // Upgrade ignored or warning diagnostics to errors. + if (Result == DiagnosticIDs::Ignored || Result == DiagnosticIDs::Warning) + Result = DiagnosticIDs::Error; + break; + } + } - // If warnings are globally mapped to ignore or error, do it. - if (Diag.IgnoreAllWarnings) - return DiagnosticIDs::Ignored; + // At this point, ignored errors can no longer be upgraded. + if (Result == DiagnosticIDs::Ignored) + return Result; - break; + // Honor -w, which is lower in priority than pedantic-errors, but higher than + // -Werror. + if (Result == DiagnosticIDs::Warning && Diag.IgnoreAllWarnings) + return DiagnosticIDs::Ignored; - case diag::MAP_ERROR_NO_WFATAL: - // Diagnostics specified as -Wno-fatal-error=foo should be errors, but - // unaffected by -Wfatal-errors. - Result = DiagnosticIDs::Error; - break; + // If -Werror is enabled, map warnings to errors unless explicitly disabled. + if (Result == DiagnosticIDs::Warning) { + if (Diag.WarningsAsErrors && !MappingInfo.hasNoWarningAsError()) + Result = DiagnosticIDs::Error; } - // Okay, we're about to return this as a "diagnostic to emit" one last check: - // if this is any sort of extension warning, and if we're in an __extension__ - // block, silence it. - if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) - return DiagnosticIDs::Ignored; + // If -Wfatal-errors is enabled, map errors to fatal unless explicity + // disabled. + if (Result == DiagnosticIDs::Error) { + if (Diag.ErrorsAsFatal && !MappingInfo.hasNoErrorAsFatal()) + Result = DiagnosticIDs::Fatal; + } - // If we are in a system header, we ignore it. - // We also want to ignore extensions and warnings in -Werror and + // If we are in a system header, we ignore it. We look at the diagnostic class + // because we also want to ignore extensions and warnings in -Werror and // -pedantic-errors modes, which *map* warnings/extensions to errors. if (Result >= DiagnosticIDs::Warning && DiagClass != CLASS_ERROR && // Custom diagnostics always are emitted in system headers. DiagID < diag::DIAG_UPPER_LIMIT && - !ShouldEmitInSystemHeader && + !MappingInfo.hasShowInSystemHeader() && Diag.SuppressSystemWarnings && Loc.isValid() && Diag.getSourceManager().isInSystemHeader( - Diag.getSourceManager().getInstantiationLoc(Loc))) + Diag.getSourceManager().getExpansionLoc(Loc))) return DiagnosticIDs::Ignored; return Result; } -namespace { - struct WarningOption { - // Be safe with the size of 'NameLen' because we don't statically check if - // the size will fit in the field; the struct size won't decrease with a - // shorter type anyway. - size_t NameLen; - const char *NameStr; - const short *Members; - const short *SubGroups; +struct clang::WarningOption { + // Be safe with the size of 'NameLen' because we don't statically check if + // the size will fit in the field; the struct size won't decrease with a + // shorter type anyway. + size_t NameLen; + const char *NameStr; + const short *Members; + const short *SubGroups; - llvm::StringRef getName() const { - return llvm::StringRef(NameStr, NameLen); - } - }; -} + StringRef getName() const { + return StringRef(NameStr, NameLen); + } +}; #define GET_DIAG_ARRAYS #include "clang/Basic/DiagnosticGroups.inc" @@ -580,54 +648,43 @@ static bool WarningOptionCompare(const WarningOption &LHS, return LHS.getName() < RHS.getName(); } -static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, - SourceLocation Loc, Diagnostic &Diag) { - // Option exists, poke all the members of its diagnostic set. +void DiagnosticIDs::getDiagnosticsInGroup( + const WarningOption *Group, + llvm::SmallVectorImpl<diag::kind> &Diags) const +{ + // Add the members of the option diagnostic set. if (const short *Member = Group->Members) { for (; *Member != -1; ++Member) - Diag.setDiagnosticMapping(*Member, Mapping, Loc); + Diags.push_back(*Member); } - // Enable/disable all subgroups along with this one. + // Add the members of the subgroups. if (const short *SubGroups = Group->SubGroups) { for (; *SubGroups != (short)-1; ++SubGroups) - MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag); + getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags); } } -/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. -/// "unknown-pragmas" to have the specified mapping. This returns true and -/// ignores the request if "Group" was unknown, false otherwise. -bool DiagnosticIDs::setDiagnosticGroupMapping(llvm::StringRef Group, - diag::Mapping Map, - SourceLocation Loc, - Diagnostic &Diag) const { - assert((Loc.isValid() || - Diag.DiagStatePoints.empty() || - Diag.DiagStatePoints.back().Loc.isInvalid()) && - "Loc should be invalid only when the mapping comes from command-line"); - assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() || - Diag.DiagStatePoints.back().Loc.isInvalid() || - !Diag.SourceMgr->isBeforeInTranslationUnit(Loc, - Diag.DiagStatePoints.back().Loc)) && - "Source location of new mapping is before the previous one!"); - +bool DiagnosticIDs::getDiagnosticsInGroup( + StringRef Group, + llvm::SmallVectorImpl<diag::kind> &Diags) const +{ WarningOption Key = { Group.size(), Group.data(), 0, 0 }; const WarningOption *Found = std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, WarningOptionCompare); if (Found == OptionTable + OptionTableSize || Found->getName() != Group) - return true; // Option not found. + return true; // Option not found. - MapGroupMembers(Found, Map, Loc, Diag); + getDiagnosticsInGroup(Found, Diags); return false; } /// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. -bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { - DiagnosticInfo Info(&Diag); +bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { + Diagnostic Info(&Diag); if (Diag.SuppressAllDiagnostics) return false; @@ -665,6 +722,13 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { Diag.LastDiagLevel = DiagLevel; } + // Update counts for DiagnosticErrorTrap even if a fatal error occurred. + if (DiagLevel >= DiagnosticIDs::Error) { + ++Diag.TrapNumErrorsOccurred; + if (isUnrecoverable(DiagID)) + ++Diag.TrapNumUnrecoverableErrorsOccurred; + } + // If a fatal error has already been emitted, silence all subsequent // diagnostics. if (Diag.FatalErrorOccurred) { @@ -685,27 +749,26 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { return false; if (DiagLevel >= DiagnosticIDs::Error) { - Diag.TrapErrorOccurred = true; - if (isUnrecoverable(DiagID)) { - Diag.TrapUnrecoverableErrorOccurred = true; + if (isUnrecoverable(DiagID)) Diag.UnrecoverableErrorOccurred = true; - } if (Diag.Client->IncludeInDiagnosticCounts()) { Diag.ErrorOccurred = true; ++Diag.NumErrors; } - // If we've emitted a lot of errors, emit a fatal error after it to stop a - // flood of bogus errors. - if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit && - DiagLevel == DiagnosticIDs::Error) + // If we've emitted a lot of errors, emit a fatal error instead of it to + // stop a flood of bogus errors. + if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit && + DiagLevel == DiagnosticIDs::Error) { Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors); + return false; + } } // If we have any Fix-Its, make sure that all of the Fix-Its point into - // source locations that aren't macro instantiations. If any point into - // macro instantiations, remove all of the Fix-Its. + // source locations that aren't macro expansions. If any point into macro + // expansions, remove all of the Fix-Its. for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) { const FixItHint &FixIt = Diag.FixItHints[I]; if (FixIt.RemoveRange.isInvalid() || @@ -717,7 +780,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { } // Finally, report it. - Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info); + Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info); if (Diag.Client->IncludeInDiagnosticCounts()) { if (DiagLevel == DiagnosticIDs::Warning) ++Diag.NumWarnings; diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp index f747c53..c1f715e 100644 --- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -217,25 +217,26 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) { /// \brief Retrieve the directory that the given file name resides in. /// Filename can point to either a real file or a virtual file. static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, - llvm::StringRef Filename) { + StringRef Filename, + bool CacheFailure) { if (Filename.empty()) return NULL; if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) return NULL; // If Filename is a directory. - llvm::StringRef DirName = llvm::sys::path::parent_path(Filename); + StringRef DirName = llvm::sys::path::parent_path(Filename); // Use the current directory if file has no path component. if (DirName.empty()) DirName = "."; - return FileMgr.getDirectory(DirName); + return FileMgr.getDirectory(DirName, CacheFailure); } /// Add all ancestors of the given path (pointing to either a file or /// a directory) as virtual directories. -void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) { - llvm::StringRef DirName = llvm::sys::path::parent_path(Path); +void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { + StringRef DirName = llvm::sys::path::parent_path(Path); if (DirName.empty()) return; @@ -263,7 +264,8 @@ void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) { /// (real or virtual). This returns NULL if the directory doesn't /// exist. /// -const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { +const DirectoryEntry *FileManager::getDirectory(StringRef DirName, + bool CacheFailure) { ++NumDirLookups; llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = SeenDirEntries.GetOrCreateValue(DirName); @@ -287,6 +289,8 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { struct stat StatBuf; if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) { // There's no real directory at the given path. + if (!CacheFailure) + SeenDirEntries.erase(DirName); return 0; } @@ -309,7 +313,8 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { /// getFile - Lookup, cache, and verify the specified file (real or /// virtual). This returns NULL if the file doesn't exist. /// -const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { +const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, + bool CacheFailure) { ++NumFileLookups; // See if there is already an entry in the map. @@ -335,10 +340,15 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { // subdirectory. This will let us avoid having to waste time on known-to-fail // searches when we go to find sys/bar.h, because all the search directories // without a 'sys' subdir will get a cached failure result. - const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); - if (DirInfo == 0) // Directory doesn't exist, file can't exist. + const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, + CacheFailure); + if (DirInfo == 0) { // Directory doesn't exist, file can't exist. + if (!CacheFailure) + SeenFileEntries.erase(Filename); + return 0; - + } + // FIXME: Use the directory info to prune this, before doing the stat syscall. // FIXME: This will reduce the # syscalls. @@ -347,6 +357,9 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { struct stat StatBuf; if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) { // There's no real file at the given path. + if (!CacheFailure) + SeenFileEntries.erase(Filename); + return 0; } @@ -381,7 +394,7 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { } const FileEntry * -FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, +FileManager::getVirtualFile(StringRef Filename, off_t Size, time_t ModificationTime) { ++NumFileLookups; @@ -404,7 +417,8 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, // Now that all ancestors of Filename are in the cache, the // following call is guaranteed to find the DirectoryEntry from the // cache. - const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); + const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, + /*CacheFailure=*/true); assert(DirInfo && "The directory of a virtual file should already be in the cache."); @@ -451,8 +465,8 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, return UFE; } -void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const { - llvm::StringRef pathRef(path.data(), path.size()); +void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { + StringRef pathRef(path.data(), path.size()); if (FileSystemOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(pathRef)) @@ -499,7 +513,7 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) { } llvm::MemoryBuffer *FileManager:: -getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) { +getBufferForFile(StringRef Filename, std::string *ErrorStr) { llvm::OwningPtr<llvm::MemoryBuffer> Result; llvm::error_code ec; if (FileSystemOpts.WorkingDir.empty()) { @@ -537,7 +551,7 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf, StatCache.get()); } -bool FileManager::getNoncachedStatValue(llvm::StringRef Path, +bool FileManager::getNoncachedStatValue(StringRef Path, struct stat &StatBuf) { llvm::SmallString<128> FilePath(Path); FixupRelativePath(FilePath); @@ -546,7 +560,7 @@ bool FileManager::getNoncachedStatValue(llvm::StringRef Path, } void FileManager::GetUniqueIDMapping( - llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const { + SmallVectorImpl<const FileEntry *> &UIDToFiles) const { UIDToFiles.clear(); UIDToFiles.resize(NextFileUID); @@ -558,7 +572,7 @@ void FileManager::GetUniqueIDMapping( UIDToFiles[FE->getValue()->getUID()] = FE->getValue(); // Map virtual file entries - for (llvm::SmallVector<FileEntry*, 4>::const_iterator + for (SmallVector<FileEntry*, 4>::const_iterator VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end(); VFE != VFEEnd; ++VFE) if (*VFE && *VFE != NON_EXISTENT_FILE) diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp index 188e2d4..38f09a0 100644 --- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -32,6 +32,7 @@ IdentifierInfo::IdentifierInfo() { ObjCOrBuiltinID = 0; HasMacro = false; IsExtension = false; + IsCXX11CompatKeyword = false; IsPoisoned = false; IsCPPOperatorKeyword = false; NeedsHandleIdentifier = false; @@ -55,7 +56,7 @@ namespace { class EmptyLookupIterator : public IdentifierIterator { public: - virtual llvm::StringRef Next() { return llvm::StringRef(); } + virtual StringRef Next() { return StringRef(); } }; } @@ -102,11 +103,11 @@ namespace { /// identifiers because they are language keywords. This causes the lexer to /// automatically map matching identifiers to specialized token codes. /// -/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be -/// enabled in the specified langauge, set to 1 if it is an extension -/// in the specified language, and set to 0 if disabled in the -/// specified language. -static void AddKeyword(llvm::StringRef Keyword, +/// The C90/C99/CPP/CPP0x flags are set to 3 if the token is a keyword in a +/// future language standard, set to 2 if the token should be enabled in the +/// specified langauge, set to 1 if it is an extension in the specified +/// language, and set to 0 if disabled in the specified language. +static void AddKeyword(StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, const LangOptions &LangOpts, IdentifierTable &Table) { unsigned AddResult = 0; @@ -115,7 +116,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; - else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; + else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; @@ -123,17 +124,20 @@ static void AddKeyword(llvm::StringRef Keyword, else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2; else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2; else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2; - + else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3; + // Don't add this keyword if disabled in this language. if (AddResult == 0) return; - IdentifierInfo &Info = Table.get(Keyword, TokenCode); + IdentifierInfo &Info = + Table.get(Keyword, AddResult == 3 ? tok::identifier : TokenCode); Info.setIsExtensionToken(AddResult == 1); + Info.setIsCXX11CompatKeyword(AddResult == 3); } /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative /// representations. -static void AddCXXOperatorKeyword(llvm::StringRef Keyword, +static void AddCXXOperatorKeyword(StringRef Keyword, tok::TokenKind TokenCode, IdentifierTable &Table) { IdentifierInfo &Info = Table.get(Keyword, TokenCode); @@ -142,7 +146,7 @@ static void AddCXXOperatorKeyword(llvm::StringRef Keyword, /// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or /// "property". -static void AddObjCKeyword(llvm::StringRef Name, +static void AddObjCKeyword(StringRef Name, tok::ObjCKeywordKind ObjCID, IdentifierTable &Table) { Table.get(Name).setObjCKeywordID(ObjCID); @@ -153,20 +157,20 @@ static void AddObjCKeyword(llvm::StringRef Name, void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { // Add keywords and tokens for the current language. #define KEYWORD(NAME, FLAGS) \ - AddKeyword(llvm::StringRef(#NAME), tok::kw_ ## NAME, \ + AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \ FLAGS, LangOpts, *this); #define ALIAS(NAME, TOK, FLAGS) \ - AddKeyword(llvm::StringRef(NAME), tok::kw_ ## TOK, \ + AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \ FLAGS, LangOpts, *this); #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ if (LangOpts.CXXOperatorNames) \ - AddCXXOperatorKeyword(llvm::StringRef(#NAME), tok::ALIAS, *this); + AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this); #define OBJC1_AT_KEYWORD(NAME) \ if (LangOpts.ObjC1) \ - AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); + AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); #define OBJC2_AT_KEYWORD(NAME) \ if (LangOpts.ObjC2) \ - AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); + AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); #define TESTING_KEYWORD(NAME, FLAGS) #include "clang/Basic/TokenKinds.def" @@ -217,6 +221,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { CASE(12, 'i', 'c', include_next); CASE(16, '_', 'i', __include_macros); + CASE(16, '_', 'e', __export_macro__); #undef CASE #undef HASH } @@ -336,9 +341,9 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { return SI->getIdentifierInfoForSlot(argIndex); } -llvm::StringRef Selector::getNameForSlot(unsigned int argIndex) const { +StringRef Selector::getNameForSlot(unsigned int argIndex) const { IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); - return II? II->getName() : llvm::StringRef(); + return II? II->getName() : StringRef(); } std::string MultiKeywordSelector::getName() const { @@ -377,7 +382,7 @@ std::string Selector::getAsString() const { /// Interpreting the given string using the normal CamelCase /// conventions, determine whether the given string starts with the /// given "word", which is assumed to end in a lowercase letter. -static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) { +static bool startsWithWord(StringRef name, StringRef word) { if (name.size() < word.size()) return false; return ((name.size() == word.size() || !islower(name[word.size()])) @@ -388,10 +393,11 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return OMF_None; - llvm::StringRef name = first->getName(); + StringRef name = first->getName(); if (sel.isUnarySelector()) { if (name == "autorelease") return OMF_autorelease; if (name == "dealloc") return OMF_dealloc; + if (name == "finalize") return OMF_finalize; if (name == "release") return OMF_release; if (name == "retain") return OMF_retain; if (name == "retainCount") return OMF_retainCount; @@ -491,4 +497,3 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { return 0; } - diff --git a/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp new file mode 100644 index 0000000..5f479db --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,30 @@ +//===--- LangOptions.cpp - C Language Family Language Options ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LangOptions class. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/LangOptions.h" + +using namespace clang; + +LangOptions::LangOptions() { +#define LANGOPT(Name, Bits, Default, Description) Name = Default; +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default); +#include "clang/Basic/LangOptions.def" +} + +void LangOptions::resetNonModularOptions() { +#define LANGOPT(Name, Bits, Default, Description) +#define BENIGN_LANGOPT(Name, Bits, Default, Description) Name = Default; +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Name = Default; +#include "clang/Basic/LangOptions.def" +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp index 5062d43..6e4f3e6 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp @@ -23,7 +23,7 @@ using namespace clang; // PrettyStackTraceLoc //===----------------------------------------------------------------------===// -void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const { +void PrettyStackTraceLoc::print(raw_ostream &OS) const { if (Loc.isValid()) { Loc.print(OS, SM); OS << ": "; @@ -35,7 +35,7 @@ void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const { // SourceLocation //===----------------------------------------------------------------------===// -void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ +void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{ if (!isValid()) { OS << "<invalid loc>"; return; @@ -48,13 +48,13 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ OS << "<invalid>"; return; } - // The instantiation and spelling pos is identical for file locs. + // The macro expansion and spelling pos is identical for file locs. OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); return; } - SM.getInstantiationLoc(*this).print(OS, SM); + SM.getExpansionLoc(*this).print(OS, SM); OS << " <Spelling="; SM.getSpellingLoc(*this).print(OS, SM); @@ -75,9 +75,9 @@ FileID FullSourceLoc::getFileID() const { } -FullSourceLoc FullSourceLoc::getInstantiationLoc() const { +FullSourceLoc FullSourceLoc::getExpansionLoc() const { assert(isValid()); - return FullSourceLoc(SrcMgr->getInstantiationLoc(*this), *SrcMgr); + return FullSourceLoc(SrcMgr->getExpansionLoc(*this), *SrcMgr); } FullSourceLoc FullSourceLoc::getSpellingLoc() const { @@ -85,14 +85,14 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const { return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr); } -unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const { +unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getInstantiationLineNumber(*this, Invalid); + return SrcMgr->getExpansionLineNumber(*this, Invalid); } -unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const { +unsigned FullSourceLoc::getExpansionColumnNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getInstantiationColumnNumber(*this, Invalid); + return SrcMgr->getExpansionColumnNumber(*this, Invalid); } unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const { @@ -125,7 +125,7 @@ const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const { return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid); } -llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const { +StringRef FullSourceLoc::getBufferData(bool *Invalid) const { return getBuffer(Invalid)->getBuffer(); } diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index 45922c1..364663e 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -17,10 +17,12 @@ #include "clang/Basic/FileManager.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Capacity.h" #include <algorithm> #include <string> #include <cstring> @@ -39,9 +41,8 @@ ContentCache::~ContentCache() { delete Buffer.getPointer(); } -/// getSizeBytesMapped - Returns the number of bytes actually mapped for -/// this ContentCache. This can be 0 if the MemBuffer was not actually -/// instantiated. +/// getSizeBytesMapped - Returns the number of bytes actually mapped for this +/// ContentCache. This can be 0 if the MemBuffer was not actually expanded. unsigned ContentCache::getSizeBytesMapped() const { return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0; } @@ -78,7 +79,7 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, Buffer.setInt(DoNotFree? DoNotFreeFlag : 0); } -const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, +const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, const SourceManager &SM, SourceLocation Loc, bool *Invalid) const { @@ -105,7 +106,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // that we are in an inconsistent situation and error out as quickly as // possible. if (!Buffer.getPointer()) { - const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); + const StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(), "<invalid>")); char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); @@ -143,7 +144,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // If the buffer is valid, check to see if it has a UTF Byte Order Mark // (BOM). We only support UTF-8 with and without a BOM right now. See // http://en.wikipedia.org/wiki/Byte_order_mark for more information. - llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); + StringRef BufStr = Buffer.getPointer()->getBuffer(); const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr) .StartsWith("\xFE\xFF", "UTF-16 (BE)") .StartsWith("\xFF\xFE", "UTF-16 (LE)") @@ -169,7 +170,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, return Buffer.getPointer(); } -unsigned LineTableInfo::getLineTableFilenameID(llvm::StringRef Name) { +unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { // Look up the filename in the string table, returning the pre-existing value // if it exists. llvm::StringMapEntry<unsigned> &Entry = @@ -186,7 +187,7 @@ unsigned LineTableInfo::getLineTableFilenameID(llvm::StringRef Name) { /// AddLineNote - Add a line note to the line table that indicates that there /// is a #line at the specified FID/Offset location which changes the presumed /// location to LineNo/FilenameID. -void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, +void LineTableInfo::AddLineNote(int FID, unsigned Offset, unsigned LineNo, int FilenameID) { std::vector<LineEntry> &Entries = LineEntries[FID]; @@ -217,7 +218,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, /// presumed #include stack. If it is 1, this is a file entry, if it is 2 then /// this is a file exit. FileKind specifies whether this is a system header or /// extern C system header. -void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, +void LineTableInfo::AddLineNote(int FID, unsigned Offset, unsigned LineNo, int FilenameID, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind) { @@ -251,7 +252,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, /// FindNearestLineEntry - Find the line entry nearest to FID that is before /// it. If there is no line entry before Offset in FID, return null. -const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, +const LineEntry *LineTableInfo::FindNearestLineEntry(int FID, unsigned Offset) { const std::vector<LineEntry> &Entries = LineEntries[FID]; assert(!Entries.empty() && "No #line entries for this FID after all!"); @@ -270,14 +271,14 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, /// \brief Add a new line entry that has already been encoded into /// the internal representation of the line table. -void LineTableInfo::AddEntry(unsigned FID, +void LineTableInfo::AddEntry(int FID, const std::vector<LineEntry> &Entries) { LineEntries[FID] = Entries; } /// getLineTableFilenameID - Return the uniqued ID for the specified filename. /// -unsigned SourceManager::getLineTableFilenameID(llvm::StringRef Name) { +unsigned SourceManager::getLineTableFilenameID(StringRef Name) { if (LineTable == 0) LineTable = new LineTableInfo(); return LineTable->getLineTableFilenameID(Name); @@ -289,7 +290,7 @@ unsigned SourceManager::getLineTableFilenameID(llvm::StringRef Name) { /// unspecified. void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID) { - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); @@ -319,7 +320,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, return AddLineNote(Loc, LineNo, FilenameID); } - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); @@ -362,7 +363,7 @@ LineTableInfo &SourceManager::getLineTable() { // Private 'Create' methods. //===----------------------------------------------------------------------===// -SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr) +SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr) : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), NumBinaryProbes(0), FakeBufferForRecovery(0) { @@ -387,11 +388,18 @@ SourceManager::~SourceManager() { } delete FakeBufferForRecovery; + + for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator + I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) { + delete I->second; + } } void SourceManager::clearIDTables() { MainFileID = FileID(); - SLocEntryTable.clear(); + LocalSLocEntryTable.clear(); + LoadedSLocEntryTable.clear(); + SLocEntryLoaded.clear(); LastLineNoFileIDQuery = FileID(); LastLineNoContentCache = 0; LastFileIDLookup = FileID(); @@ -399,9 +407,10 @@ void SourceManager::clearIDTables() { if (LineTable) LineTable->clear(); - // Use up FileID #0 as an invalid instantiation. - NextOffset = 0; - createInstantiationLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1); + // Use up FileID #0 as an invalid expansion. + NextLocalOffset = 0; + CurrentLoadedOffset = MaxLoadedOffset; + createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1); } /// getOrCreateContentCache - Create or return a cached ContentCache for the @@ -452,33 +461,16 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { return Entry; } -void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source, - unsigned NumSLocEntries, - unsigned NextOffset) { - ExternalSLocEntries = Source; - this->NextOffset = NextOffset; - unsigned CurPrealloc = SLocEntryLoaded.size(); - // If we've ever preallocated, we must not count the dummy entry. - if (CurPrealloc) --CurPrealloc; - SLocEntryLoaded.resize(NumSLocEntries + 1); - SLocEntryLoaded[0] = true; - SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries - CurPrealloc); -} - -void SourceManager::ClearPreallocatedSLocEntries() { - unsigned I = 0; - for (unsigned N = SLocEntryLoaded.size(); I != N; ++I) - if (!SLocEntryLoaded[I]) - break; - - // We've already loaded all preallocated source location entries. - if (I == SLocEntryLoaded.size()) - return; - - // Remove everything from location I onward. - SLocEntryTable.resize(I); - SLocEntryLoaded.clear(); - ExternalSLocEntries = 0; +std::pair<int, unsigned> +SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, + unsigned TotalSize) { + assert(ExternalSLocEntries && "Don't have an external sloc source"); + LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); + SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); + CurrentLoadedOffset -= TotalSize; + assert(CurrentLoadedOffset >= NextLocalOffset && "Out of source locations"); + int ID = LoadedSLocEntryTable.size(); + return std::make_pair(-ID - 1, CurrentLoadedOffset); } /// \brief As part of recovering from missing or changed content, produce a @@ -492,7 +484,7 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { } //===----------------------------------------------------------------------===// -// Methods to create new FileID's and instantiations. +// Methods to create new FileID's and macro expansions. //===----------------------------------------------------------------------===// /// createFileID - Create a new FileID for the specified ContentCache and @@ -501,77 +493,76 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { FileID SourceManager::createFileID(const ContentCache *File, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, - unsigned PreallocatedID, - unsigned Offset) { - if (PreallocatedID) { - // If we're filling in a preallocated ID, just load in the file - // entry and return. - assert(PreallocatedID < SLocEntryLoaded.size() && - "Preallocate ID out-of-range"); - assert(!SLocEntryLoaded[PreallocatedID] && - "Source location entry already loaded"); - assert(Offset && "Preallocate source location cannot have zero offset"); - SLocEntryTable[PreallocatedID] - = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); - SLocEntryLoaded[PreallocatedID] = true; - FileID FID = FileID::get(PreallocatedID); - return FID; + int LoadedID, unsigned LoadedOffset) { + if (LoadedID < 0) { + assert(LoadedID != -1 && "Loading sentinel FileID"); + unsigned Index = unsigned(-LoadedID) - 2; + assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); + assert(!SLocEntryLoaded[Index] && "FileID already loaded"); + LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, + FileInfo::get(IncludePos, File, FileCharacter)); + SLocEntryLoaded[Index] = true; + return FileID::get(LoadedID); } - - SLocEntryTable.push_back(SLocEntry::get(NextOffset, - FileInfo::get(IncludePos, File, - FileCharacter))); + LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, + FileInfo::get(IncludePos, File, + FileCharacter))); unsigned FileSize = File->getSize(); - assert(NextOffset+FileSize+1 > NextOffset && "Ran out of source locations!"); - NextOffset += FileSize+1; + assert(NextLocalOffset + FileSize + 1 > NextLocalOffset && + NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset && + "Ran out of source locations!"); + // We do a +1 here because we want a SourceLocation that means "the end of the + // file", e.g. for the "no newline at the end of the file" diagnostic. + NextLocalOffset += FileSize + 1; // Set LastFileIDLookup to the newly created file. The next getFileID call is // almost guaranteed to be from that file. - FileID FID = FileID::get(SLocEntryTable.size()-1); + FileID FID = FileID::get(LocalSLocEntryTable.size()-1); return LastFileIDLookup = FID; } SourceLocation -SourceManager::createMacroArgInstantiationLoc(SourceLocation SpellingLoc, - SourceLocation ILoc, - unsigned TokLength) { - InstantiationInfo II = - InstantiationInfo::createForMacroArg(SpellingLoc, ILoc); - return createInstantiationLocImpl(II, TokLength); -} - -SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, - SourceLocation ILocStart, - SourceLocation ILocEnd, - unsigned TokLength, - unsigned PreallocatedID, - unsigned Offset) { - InstantiationInfo II = - InstantiationInfo::create(SpellingLoc, ILocStart, ILocEnd); - return createInstantiationLocImpl(II, TokLength, PreallocatedID, Offset); +SourceManager::createMacroArgExpansionLoc(SourceLocation SpellingLoc, + SourceLocation ExpansionLoc, + unsigned TokLength) { + ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc, + ExpansionLoc); + return createExpansionLocImpl(Info, TokLength); } SourceLocation -SourceManager::createInstantiationLocImpl(const InstantiationInfo &II, - unsigned TokLength, - unsigned PreallocatedID, - unsigned Offset) { - if (PreallocatedID) { - // If we're filling in a preallocated ID, just load in the - // instantiation entry and return. - assert(PreallocatedID < SLocEntryLoaded.size() && - "Preallocate ID out-of-range"); - assert(!SLocEntryLoaded[PreallocatedID] && - "Source location entry already loaded"); - assert(Offset && "Preallocate source location cannot have zero offset"); - SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II); - SLocEntryLoaded[PreallocatedID] = true; - return SourceLocation::getMacroLoc(Offset); +SourceManager::createExpansionLoc(SourceLocation SpellingLoc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLength, + int LoadedID, + unsigned LoadedOffset) { + ExpansionInfo Info = ExpansionInfo::create(SpellingLoc, ExpansionLocStart, + ExpansionLocEnd); + return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset); +} + +SourceLocation +SourceManager::createExpansionLocImpl(const ExpansionInfo &Info, + unsigned TokLength, + int LoadedID, + unsigned LoadedOffset) { + if (LoadedID < 0) { + assert(LoadedID != -1 && "Loading sentinel FileID"); + unsigned Index = unsigned(-LoadedID) - 2; + assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); + assert(!SLocEntryLoaded[Index] && "FileID already loaded"); + LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info); + SLocEntryLoaded[Index] = true; + return SourceLocation::getMacroLoc(LoadedOffset); } - SLocEntryTable.push_back(SLocEntry::get(NextOffset, II)); - assert(NextOffset+TokLength+1 > NextOffset && "Ran out of source locations!"); - NextOffset += TokLength+1; - return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); + LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info)); + assert(NextLocalOffset + TokLength + 1 > NextLocalOffset && + NextLocalOffset + TokLength + 1 <= CurrentLoadedOffset && + "Ran out of source locations!"); + // See createFileID for that +1. + NextLocalOffset += TokLength + 1; + return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1)); } const llvm::MemoryBuffer * @@ -602,9 +593,9 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile, OverriddenFiles[SourceFile] = NewFile; } -llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { +StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { bool MyInvalid = false; - const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid); + const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid); if (!SLoc.isFile() || MyInvalid) { if (Invalid) *Invalid = true; @@ -627,18 +618,32 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { // SourceLocation manipulation methods. //===----------------------------------------------------------------------===// -/// getFileIDSlow - Return the FileID for a SourceLocation. This is a very hot -/// method that is used for all SourceManager queries that start with a -/// SourceLocation object. It is responsible for finding the entry in -/// SLocEntryTable which contains the specified location. +/// \brief Return the FileID for a SourceLocation. /// +/// This is the cache-miss path of getFileID. Not as hot as that function, but +/// still very important. It is responsible for finding the entry in the +/// SLocEntry tables that contains the specified location. FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { if (!SLocOffset) return FileID::get(0); + // Now it is time to search for the correct file. See where the SLocOffset + // sits in the global view and consult local or loaded buffers for it. + if (SLocOffset < NextLocalOffset) + return getFileIDLocal(SLocOffset); + return getFileIDLoaded(SLocOffset); +} + +/// \brief Return the FileID for a SourceLocation with a low offset. +/// +/// This function knows that the SourceLocation is in a local buffer, not a +/// loaded one. +FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const { + assert(SLocOffset < NextLocalOffset && "Bad function choice"); + // After the first and second level caches, I see two common sorts of - // behavior: 1) a lot of searched FileID's are "near" the cached file location - // or are "near" the cached instantiation location. 2) others are just + // behavior: 1) a lot of searched FileID's are "near" the cached file + // location or are "near" the cached expansion location. 2) others are just // completely random and may be a very long way away. // // To handle this, we do a linear search for up to 8 steps to catch #1 quickly @@ -649,12 +654,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { // most newly created FileID. std::vector<SrcMgr::SLocEntry>::const_iterator I; - if (SLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { + if (LastFileIDLookup.ID < 0 || + LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { // Neither loc prunes our search. - I = SLocEntryTable.end(); + I = LocalSLocEntryTable.end(); } else { // Perhaps it is near the file point. - I = SLocEntryTable.begin()+LastFileIDLookup.ID; + I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID; } // Find the FileID that contains this. "I" is an iterator that points to a @@ -662,25 +668,12 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { unsigned NumProbes = 0; while (1) { --I; - if (ExternalSLocEntries) { - bool Invalid = false; - getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid); - if (Invalid) - return FileID::get(0); - } - if (I->getOffset() <= SLocOffset) { -#if 0 - printf("lin %d -> %d [%s] %d %d\n", SLocOffset, - I-SLocEntryTable.begin(), - I->isInstantiation() ? "inst" : "file", - LastFileIDLookup.ID, int(SLocEntryTable.end()-I)); -#endif - FileID Res = FileID::get(I-SLocEntryTable.begin()); - - // If this isn't an instantiation, remember it. We have good locality - // across FileID lookups. - if (!I->isInstantiation()) + FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin())); + + // If this isn't an expansion, remember it. We have good locality across + // FileID lookups. + if (!I->isExpansion()) LastFileIDLookup = Res; NumLinearScans += NumProbes+1; return Res; @@ -691,7 +684,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { // Convert "I" back into an index. We know that it is an entry whose index is // larger than the offset we are looking for. - unsigned GreaterIndex = I-SLocEntryTable.begin(); + unsigned GreaterIndex = I - LocalSLocEntryTable.begin(); // LessIndex - This is the lower bound of the range that we're searching. // We know that the offset corresponding to the FileID is is less than // SLocOffset. @@ -700,8 +693,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { while (1) { bool Invalid = false; unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; - unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid) - .getOffset(); + unsigned MidOffset = getLocalSLocEntry(MiddleIndex, &Invalid).getOffset(); if (Invalid) return FileID::get(0); @@ -715,18 +707,14 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { } // If the middle index contains the value, succeed and return. + // FIXME: This could be made faster by using a function that's aware of + // being in the local area. if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) { -#if 0 - printf("bin %d -> %d [%s] %d %d\n", SLocOffset, - I-SLocEntryTable.begin(), - I->isInstantiation() ? "inst" : "file", - LastFileIDLookup.ID, int(SLocEntryTable.end()-I)); -#endif FileID Res = FileID::get(MiddleIndex); - // If this isn't an instantiation, remember it. We have good locality + // If this isn't a macro expansion, remember it. We have good locality // across FileID lookups. - if (!I->isInstantiation()) + if (!LocalSLocEntryTable[MiddleIndex].isExpansion()) LastFileIDLookup = Res; NumBinaryProbes += NumProbes; return Res; @@ -737,17 +725,82 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { } } +/// \brief Return the FileID for a SourceLocation with a high offset. +/// +/// This function knows that the SourceLocation is in a loaded buffer, not a +/// local one. +FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const { + assert(SLocOffset >= CurrentLoadedOffset && "Bad function choice"); + + // Sanity checking, otherwise a bug may lead to hanging in release build. + if (SLocOffset < CurrentLoadedOffset) + return FileID(); + + // Essentially the same as the local case, but the loaded array is sorted + // in the other direction. + + // First do a linear scan from the last lookup position, if possible. + unsigned I; + int LastID = LastFileIDLookup.ID; + if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset) + I = 0; + else + I = (-LastID - 2) + 1; + + unsigned NumProbes; + for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) { + // Make sure the entry is loaded! + const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I); + if (E.getOffset() <= SLocOffset) { + FileID Res = FileID::get(-int(I) - 2); + + if (!E.isExpansion()) + LastFileIDLookup = Res; + NumLinearScans += NumProbes + 1; + return Res; + } + } + + // Linear scan failed. Do the binary search. Note the reverse sorting of the + // table: GreaterIndex is the one where the offset is greater, which is + // actually a lower index! + unsigned GreaterIndex = I; + unsigned LessIndex = LoadedSLocEntryTable.size(); + NumProbes = 0; + while (1) { + ++NumProbes; + unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex; + const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex); + + ++NumProbes; + + if (E.getOffset() > SLocOffset) { + GreaterIndex = MiddleIndex; + continue; + } + + if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) { + FileID Res = FileID::get(-int(MiddleIndex) - 2); + if (!E.isExpansion()) + LastFileIDLookup = Res; + NumBinaryProbes += NumProbes; + return Res; + } + + LessIndex = MiddleIndex; + } +} + SourceLocation SourceManager:: -getInstantiationLocSlowCase(SourceLocation Loc) const { +getExpansionLocSlowCase(SourceLocation Loc) const { do { // Note: If Loc indicates an offset into a token that came from a macro // expansion (e.g. the 5th character of the token) we do not want to add - // this offset when going to the instantiation location. The instatiation + // this offset when going to the expansion location. The expansion // location is the macro invocation, which the offset has nothing to do // with. This is unlike when we get the spelling loc, because the offset // directly correspond to the token whose spelling we're inspecting. - Loc = getSLocEntry(getFileID(Loc)).getInstantiation() - .getInstantiationLocStart(); + Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart(); } while (!Loc.isFileID()); return Loc; @@ -756,23 +809,32 @@ getInstantiationLocSlowCase(SourceLocation Loc) const { SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const { do { std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); - Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc(); - Loc = Loc.getFileLocWithOffset(LocInfo.second); + Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); + Loc = Loc.getLocWithOffset(LocInfo.second); + } while (!Loc.isFileID()); + return Loc; +} + +SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const { + do { + if (isMacroArgExpansion(Loc)) + Loc = getImmediateSpellingLoc(Loc); + else + Loc = getImmediateExpansionRange(Loc).first; } while (!Loc.isFileID()); return Loc; } std::pair<FileID, unsigned> -SourceManager::getDecomposedInstantiationLocSlowCase( +SourceManager::getDecomposedExpansionLocSlowCase( const SrcMgr::SLocEntry *E) const { - // If this is an instantiation record, walk through all the instantiation - // points. + // If this is an expansion record, walk through all the expansion points. FileID FID; SourceLocation Loc; unsigned Offset; do { - Loc = E->getInstantiation().getInstantiationLocStart(); + Loc = E->getExpansion().getExpansionLocStart(); FID = getFileID(Loc); E = &getSLocEntry(FID); @@ -785,16 +847,16 @@ SourceManager::getDecomposedInstantiationLocSlowCase( std::pair<FileID, unsigned> SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, unsigned Offset) const { - // If this is an instantiation record, walk through all the instantiation - // points. + // If this is an expansion record, walk through all the expansion points. FileID FID; SourceLocation Loc; do { - Loc = E->getInstantiation().getSpellingLoc(); + Loc = E->getExpansion().getSpellingLoc(); + Loc = Loc.getLocWithOffset(Offset); FID = getFileID(Loc); E = &getSLocEntry(FID); - Offset += Loc.getOffset()-E->getOffset(); + Offset = Loc.getOffset()-E->getOffset(); } while (!Loc.isFileID()); return std::make_pair(FID, Offset); @@ -807,45 +869,45 @@ SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{ if (Loc.isFileID()) return Loc; std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); - Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc(); - return Loc.getFileLocWithOffset(LocInfo.second); + Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); + return Loc.getLocWithOffset(LocInfo.second); } -/// getImmediateInstantiationRange - Loc is required to be an instantiation -/// location. Return the start/end of the instantiation information. +/// getImmediateExpansionRange - Loc is required to be an expansion location. +/// Return the start/end of the expansion information. std::pair<SourceLocation,SourceLocation> -SourceManager::getImmediateInstantiationRange(SourceLocation Loc) const { - assert(Loc.isMacroID() && "Not an instantiation loc!"); - const InstantiationInfo &II = getSLocEntry(getFileID(Loc)).getInstantiation(); - return II.getInstantiationLocRange(); +SourceManager::getImmediateExpansionRange(SourceLocation Loc) const { + assert(Loc.isMacroID() && "Not a macro expansion loc!"); + const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion(); + return Expansion.getExpansionLocRange(); } -/// getInstantiationRange - Given a SourceLocation object, return the -/// range of tokens covered by the instantiation in the ultimate file. +/// getExpansionRange - Given a SourceLocation object, return the range of +/// tokens covered by the expansion in the ultimate file. std::pair<SourceLocation,SourceLocation> -SourceManager::getInstantiationRange(SourceLocation Loc) const { +SourceManager::getExpansionRange(SourceLocation Loc) const { if (Loc.isFileID()) return std::make_pair(Loc, Loc); std::pair<SourceLocation,SourceLocation> Res = - getImmediateInstantiationRange(Loc); + getImmediateExpansionRange(Loc); - // Fully resolve the start and end locations to their ultimate instantiation + // Fully resolve the start and end locations to their ultimate expansion // points. while (!Res.first.isFileID()) - Res.first = getImmediateInstantiationRange(Res.first).first; + Res.first = getImmediateExpansionRange(Res.first).first; while (!Res.second.isFileID()) - Res.second = getImmediateInstantiationRange(Res.second).second; + Res.second = getImmediateExpansionRange(Res.second).second; return Res; } -bool SourceManager::isMacroArgInstantiation(SourceLocation Loc) const { +bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const { if (!Loc.isMacroID()) return false; FileID FID = getFileID(Loc); const SrcMgr::SLocEntry *E = &getSLocEntry(FID); - const SrcMgr::InstantiationInfo &II = E->getInstantiation(); - return II.isMacroArgInstantiation(); + const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); + return Expansion.isMacroArgExpansion(); } @@ -913,10 +975,10 @@ unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } -unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, - bool *Invalid) const { +unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc, + bool *Invalid) const { if (isInvalid(Loc, Invalid)) return 0; - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } @@ -927,10 +989,10 @@ unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc, } static LLVM_ATTRIBUTE_NOINLINE void -ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, +ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, llvm::BumpPtrAllocator &Alloc, const SourceManager &SM, bool &Invalid); -static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, +static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, llvm::BumpPtrAllocator &Alloc, const SourceManager &SM, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. @@ -941,7 +1003,7 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, // Find the file offsets of all of the *physical* source lines. This does // not look at trigraphs, escaped newlines, or anything else tricky. - llvm::SmallVector<unsigned, 256> LineOffsets; + SmallVector<unsigned, 256> LineOffsets; // Line #1 starts at char 0. LineOffsets.push_back(0); @@ -1108,10 +1170,10 @@ unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc, std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); return getLineNumber(LocInfo.first, LocInfo.second); } -unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc, - bool *Invalid) const { +unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc, + bool *Invalid) const { if (isInvalid(Loc, Invalid)) return 0; - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); return getLineNumber(LocInfo.first, LocInfo.second); } unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc, @@ -1131,7 +1193,7 @@ unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc, SrcMgr::CharacteristicKind SourceManager::getFileCharacteristic(SourceLocation Loc) const { assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!"); - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid); if (Invalid || !SEntry.isFile()) @@ -1172,13 +1234,13 @@ const char *SourceManager::getBufferName(SourceLocation Loc, /// or GNU line marker directives. This provides a view on the data that a /// user should see in diagnostics, for example. /// -/// Note that a presumed location is always given as the instantiation point -/// of an instantiation location, not at the spelling location. +/// Note that a presumed location is always given as the expansion point of an +/// expansion location, not at the spelling location. PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { if (Loc.isInvalid()) return PresumedLoc(); - // Presumed locations are always for instantiation points. - std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + // Presumed locations are always for expansion points. + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); @@ -1229,7 +1291,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // Handle virtual #include manipulation. if (Entry->IncludeOffset) { IncludeLoc = getLocForStartOfFile(LocInfo.first); - IncludeLoc = IncludeLoc.getFileLocWithOffset(Entry->IncludeOffset); + IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset); } } } @@ -1237,6 +1299,25 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc); } +/// \brief The size of the SLocEnty that \arg FID represents. +unsigned SourceManager::getFileIDSize(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid) + return 0; + + int ID = FID.ID; + unsigned NextOffset; + if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size())) + NextOffset = getNextLocalOffset(); + else if (ID+1 == -1) + NextOffset = MaxLoadedOffset; + else + NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset(); + + return NextOffset - Entry.getOffset() - 1; +} + //===----------------------------------------------------------------------===// // Other miscellaneous methods. //===----------------------------------------------------------------------===// @@ -1259,24 +1340,36 @@ static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) { /// \brief Get the source location for the given file:line:col triplet. /// /// If the source file is included multiple times, the source location will -/// be based upon the first inclusion. -SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, - unsigned Line, unsigned Col) { +/// be based upon an arbitrary inclusion. +SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile, + unsigned Line, + unsigned Col) const { assert(SourceFile && "Null source file!"); assert(Line && Col && "Line and column should start from 1!"); + FileID FirstFID = translateFile(SourceFile); + return translateLineCol(FirstFID, Line, Col); +} + +/// \brief Get the FileID for the given file. +/// +/// If the source file is included multiple times, the FileID will be the +/// first inclusion. +FileID SourceManager::translateFile(const FileEntry *SourceFile) const { + assert(SourceFile && "Null source file!"); + // Find the first file ID that corresponds to the given file. FileID FirstFID; // First, check the main file ID, since it is common to look for a // location in the main file. llvm::Optional<ino_t> SourceFileInode; - llvm::Optional<llvm::StringRef> SourceFileName; + llvm::Optional<StringRef> SourceFileName; if (!MainFileID.isInvalid()) { bool Invalid = false; const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); if (Invalid) - return SourceLocation(); + return FileID(); if (MainSLoc.isFile()) { const ContentCache *MainContentCache @@ -1308,12 +1401,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (FirstFID.isInvalid()) { // The location we're looking for isn't in the main file; look - // through all of the source locations. - for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { + // through all of the local source locations. + for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { bool Invalid = false; - const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid); if (Invalid) - return SourceLocation(); + return FileID(); if (SLoc.isFile() && SLoc.getFile().getContentCache() && @@ -1322,6 +1415,18 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, break; } } + // If that still didn't help, try the modules. + if (FirstFID.isInvalid()) { + for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getLoadedSLocEntry(I); + if (SLoc.isFile() && + SLoc.getFile().getContentCache() && + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { + FirstFID = FileID::get(-int(I) - 2); + break; + } + } + } } // If we haven't found what we want yet, try again, but this time stat() @@ -1333,10 +1438,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, (SourceFileInode || (SourceFileInode = getActualFileInode(SourceFile)))) { bool Invalid = false; - for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { + FileID IFileID; + IFileID.ID = I; + const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid); if (Invalid) - return SourceLocation(); + return FileID(); if (SLoc.isFile()) { const ContentCache *FileContentCache @@ -1355,20 +1462,38 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, } } } - - if (FirstFID.isInvalid()) + + return FirstFID; +} + +/// \brief Get the source location in \arg FID for the given line:col. +/// Returns null location if \arg FID is not a file SLocEntry. +SourceLocation SourceManager::translateLineCol(FileID FID, + unsigned Line, + unsigned Col) const { + if (FID.isInvalid()) + return SourceLocation(); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid) + return SourceLocation(); + + if (!Entry.isFile()) return SourceLocation(); + SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset()); + if (Line == 1 && Col == 1) - return getLocForStartOfFile(FirstFID); + return FileLoc; ContentCache *Content - = const_cast<ContentCache *>(getOrCreateContentCache(SourceFile)); + = const_cast<ContentCache *>(Entry.getFile().getContentCache()); if (!Content) return SourceLocation(); // If this is the first use of line information for this buffer, compute the - /// SourceLineCache for it on demand. + // SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); @@ -1380,33 +1505,150 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); if (Size > 0) --Size; - return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); + return FileLoc.getLocWithOffset(Size); } unsigned FilePos = Content->SourceLineCache[Line - 1]; const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos; unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf; + if (BufLength == 0) + return FileLoc.getLocWithOffset(FilePos); + unsigned i = 0; // Check that the given column is valid. while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r') ++i; if (i < Col-1) - return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + i); + return FileLoc.getLocWithOffset(FilePos + i); - return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1); + return FileLoc.getLocWithOffset(FilePos + Col - 1); } -/// Given a decomposed source location, move it up the include/instantiation -/// stack to the parent source location. If this is possible, return the -/// decomposed version of the parent in Loc and return false. If Loc is the -/// top-level entry, return true and don't modify it. +/// \brief Compute a map of macro argument chunks to their expanded source +/// location. Chunks that are not part of a macro argument will map to an +/// invalid source location. e.g. if a file contains one macro argument at +/// offset 100 with length 10, this is how the map will be formed: +/// 0 -> SourceLocation() +/// 100 -> Expanded macro arg location +/// 110 -> SourceLocation() +void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr, + FileID FID) const { + assert(!FID.isInvalid()); + assert(!CachePtr); + + CachePtr = new MacroArgsMap(); + MacroArgsMap &MacroArgsCache = *CachePtr; + // Initially no macro argument chunk is present. + MacroArgsCache.insert(std::make_pair(0, SourceLocation())); + + int ID = FID.ID; + while (1) { + ++ID; + // Stop if there are no more FileIDs to check. + if (ID > 0) { + if (unsigned(ID) >= local_sloc_entry_size()) + return; + } else if (ID == -1) { + return; + } + + const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID); + if (Entry.isFile()) { + SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc(); + if (IncludeLoc.isInvalid()) + continue; + if (!isInFileID(IncludeLoc, FID)) + return; // No more files/macros that may be "contained" in this file. + + // Skip the files/macros of the #include'd file, we only care about macros + // that lexed macro arguments from our file. + if (Entry.getFile().NumCreatedFIDs) + ID += Entry.getFile().NumCreatedFIDs - 1/*because of next ++ID*/; + continue; + } + + if (!Entry.getExpansion().isMacroArgExpansion()) + continue; + + SourceLocation SpellLoc = + getSpellingLoc(Entry.getExpansion().getSpellingLoc()); + unsigned BeginOffs; + if (!isInFileID(SpellLoc, FID, &BeginOffs)) + return; // No more files/macros that may be "contained" in this file. + unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID)); + + // Add a new chunk for this macro argument. A previous macro argument chunk + // may have been lexed again, so e.g. if the map is + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 110 -> SourceLocation() + // and we found a new macro FileID that lexed from offet 105 with length 3, + // the new map will be: + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 105 -> Expanded loc #2 + // 108 -> Expanded loc #1 + // 110 -> SourceLocation() + // + // Since re-lexed macro chunks will always be the same size or less of + // previous chunks, we only need to find where the ending of the new macro + // chunk is mapped to and update the map with new begin/end mappings. + + MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs); + --I; + SourceLocation EndOffsMappedLoc = I->second; + MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset()); + MacroArgsCache[EndOffs] = EndOffsMappedLoc; + } +} + +/// \brief If \arg Loc points inside a function macro argument, the returned +/// location will be the macro location in which the argument was expanded. +/// If a macro argument is used multiple times, the expanded location will +/// be at the first expansion of the argument. +/// e.g. +/// MY_MACRO(foo); +/// ^ +/// Passing a file location pointing at 'foo', will yield a macro location +/// where 'foo' was expanded into. +SourceLocation +SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { + if (Loc.isInvalid() || !Loc.isFileID()) + return Loc; + + FileID FID; + unsigned Offset; + llvm::tie(FID, Offset) = getDecomposedLoc(Loc); + if (FID.isInvalid()) + return Loc; + + MacroArgsMap *&MacroArgsCache = MacroArgsCacheMap[FID]; + if (!MacroArgsCache) + computeMacroArgsCache(MacroArgsCache, FID); + + assert(!MacroArgsCache->empty()); + MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset); + --I; + + unsigned MacroArgBeginOffs = I->first; + SourceLocation MacroArgExpandedLoc = I->second; + if (MacroArgExpandedLoc.isValid()) + return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs); + + return Loc; +} + +/// Given a decomposed source location, move it up the include/expansion stack +/// to the parent source location. If this is possible, return the decomposed +/// version of the parent in Loc and return false. If Loc is the top-level +/// entry, return true and don't modify it. static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, const SourceManager &SM) { SourceLocation UpperLoc; const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first); - if (Entry.isInstantiation()) - UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); + if (Entry.isExpansion()) + UpperLoc = Entry.getExpansion().getExpansionLocEnd(); else UpperLoc = Entry.getFile().getIncludeLoc(); @@ -1427,11 +1669,6 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, if (LHS == RHS) return false; - // If both locations are macro instantiations, the order of their offsets - // reflect the order that the tokens, pointed to by these locations, were - // instantiated (during parsing each token that is instantiated by a macro, - // expands the SLocEntries). - std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS); std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS); @@ -1445,41 +1682,28 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); // Okay, we missed in the cache, start updating the cache for this query. - IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first); - - // "Traverse" the include/instantiation stacks of both locations and try to - // find a common "ancestor". FileIDs build a tree-like structure that - // reflects the #include hierarchy, and this algorithm needs to find the - // nearest common ancestor between the two locations. For example, if you - // have a.c that includes b.h and c.h, and are comparing a location in b.h to - // a location in c.h, we need to find that their nearest common ancestor is - // a.c, and compare the locations of the two #includes to find their relative - // ordering. - // - // SourceManager assigns FileIDs in order of parsing. This means that an - // includee always has a larger FileID than an includer. While you might - // think that we could just compare the FileID's here, that doesn't work to - // compare a point at the end of a.c with a point within c.h. Though c.h has - // a larger FileID, we have to compare the include point of c.h to the - // location in a.c. - // - // Despite not being able to directly compare FileID's, we can tell that a - // larger FileID is necessarily more deeply nested than a lower one and use - // this information to walk up the tree to the nearest common ancestor. + IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first, + /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID); + + // We need to find the common ancestor. The only way of doing this is to + // build the complete include chain for one and then walking up the chain + // of the other looking for a match. + // We use a map from FileID to Offset to store the chain. Easier than writing + // a custom set hash info that only depends on the first part of a pair. + typedef llvm::DenseMap<FileID, unsigned> LocSet; + LocSet LChain; do { - // If LOffs is larger than ROffs, then LOffs must be more deeply nested than - // ROffs, walk up the #include chain. - if (LOffs.first.ID > ROffs.first.ID) { - if (MoveUpIncludeHierarchy(LOffs, *this)) - break; // We reached the top. - - } else { - // Otherwise, ROffs is larger than LOffs, so ROffs must be more deeply - // nested than LOffs, walk up the #include chain. - if (MoveUpIncludeHierarchy(ROffs, *this)) - break; // We reached the top. - } - } while (LOffs.first != ROffs.first); + LChain.insert(LOffs); + // We catch the case where LOffs is in a file included by ROffs and + // quit early. The other way round unfortunately remains suboptimal. + } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this)); + LocSet::iterator I; + while((I = LChain.find(ROffs.first)) == LChain.end()) { + if (MoveUpIncludeHierarchy(ROffs, *this)) + break; // Met at topmost file. + } + if (I != LChain.end()) + LOffs = *I; // If we exited because we found a nearest common ancestor, compare the // locations within the common file and cache them. @@ -1488,26 +1712,21 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); } - // There is no common ancestor, most probably because one location is in the - // predefines buffer or an AST file. - // FIXME: We should rearrange the external interface so this simply never - // happens; it can't conceptually happen. Also see PR5662. - IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching. - - // Zip both entries up to the top level record. - while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/; - while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/; - - // If exactly one location is a memory buffer, assume it precedes the other. - - // Strip off macro instantation locations, going up to the top-level File - // SLocEntry. - bool LIsMB = getFileEntryForID(LOffs.first) == 0; - bool RIsMB = getFileEntryForID(ROffs.first) == 0; - if (LIsMB != RIsMB) - return LIsMB; - - // Otherwise, just assume FileIDs were created in order. + // This can happen if a location is in a built-ins buffer. + // But see PR5662. + // Clear the lookup cache, it depends on a common location. + IsBeforeInTUCache.clear(); + bool LIsBuiltins = strcmp("<built-in>", + getBuffer(LOffs.first)->getBufferIdentifier()) == 0; + bool RIsBuiltins = strcmp("<built-in>", + getBuffer(ROffs.first)->getBufferIdentifier()) == 0; + // built-in is before non-built-in + if (LIsBuiltins != RIsBuiltins) + return LIsBuiltins; + assert(LIsBuiltins && RIsBuiltins && + "Non-built-in locations must be rooted in the main file"); + // Both are in built-in buffers, but from different files. We just claim that + // lower IDs come first. return LOffs.first < ROffs.first; } @@ -1517,20 +1736,26 @@ void SourceManager::PrintStats() const { llvm::errs() << "\n*** Source Manager Stats:\n"; llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size() << " mem buffers mapped.\n"; - llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated (" - << SLocEntryTable.capacity()*sizeof(SrcMgr::SLocEntry) + llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated (" + << llvm::capacity_in_bytes(LocalSLocEntryTable) << " bytes of capacity), " - << NextOffset << "B of Sloc address space used.\n"; - + << NextLocalOffset << "B of Sloc address space used.\n"; + llvm::errs() << LoadedSLocEntryTable.size() + << " loaded SLocEntries allocated, " + << MaxLoadedOffset - CurrentLoadedOffset + << "B of Sloc address space used.\n"; + unsigned NumLineNumsComputed = 0; unsigned NumFileBytesMapped = 0; for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){ NumLineNumsComputed += I->second->SourceLineCache != 0; NumFileBytesMapped += I->second->getSizeBytesMapped(); } + unsigned NumMacroArgsComputed = MacroArgsCacheMap.size(); llvm::errs() << NumFileBytesMapped << " bytes of files mapped, " - << NumLineNumsComputed << " files with line #'s computed.\n"; + << NumLineNumsComputed << " files with line #'s computed, " + << NumMacroArgsComputed << " files with macro args computed.\n"; llvm::errs() << "FileID scans: " << NumLinearScans << " linear, " << NumBinaryProbes << " binary.\n"; } @@ -1557,3 +1782,11 @@ SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const { return MemoryBufferSizes(malloc_bytes, mmap_bytes); } +size_t SourceManager::getDataStructureSizes() const { + return llvm::capacity_in_bytes(MemBufferInfos) + + llvm::capacity_in_bytes(LocalSLocEntryTable) + + llvm::capacity_in_bytes(LoadedSLocEntryTable) + + llvm::capacity_in_bytes(SLocEntryLoaded) + + llvm::capacity_in_bytes(FileInfos) + + llvm::capacity_in_bytes(OverriddenFiles); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp index 30a9bdb..593db2b 100644 --- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" #include <cctype> #include <cstdlib> using namespace clang; @@ -33,6 +34,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; + HalfWidth = 16; + HalfAlign = 16; FloatWidth = 32; FloatAlign = 32; DoubleWidth = 64; @@ -41,6 +44,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { LongDoubleAlign = 64; LargeArrayMinWidth = 0; LargeArrayAlign = 0; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; SizeType = UnsignedLong; PtrDiffType = SignedLong; IntMaxType = SignedLongLong; @@ -53,6 +57,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Int64Type = SignedLongLong; SigAtomicType = SignedInt; UseBitFieldTypeAlignment = true; + UseZeroLengthBitfieldAlignment = false; + ZeroLengthBitfieldBoundary = 0; + HalfFormat = &llvm::APFloat::IEEEhalf; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; @@ -60,6 +67,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { "i64:64:64-f32:32:32-f64:64:64-n32"; UserLabelPrefix = "_"; MCountName = "mcount"; + RegParmMax = 0; + SSERegParmMax = 0; HasAlignMac68kSupport = false; // Default to no types using fpret. @@ -83,7 +92,7 @@ TargetInfo::~TargetInfo() {} /// For example, SignedShort -> "short". const char *TargetInfo::getTypeName(IntType T) { switch (T) { - default: assert(0 && "not an integer!"); + default: llvm_unreachable("not an integer!"); case SignedShort: return "short"; case UnsignedShort: return "unsigned short"; case SignedInt: return "int"; @@ -99,7 +108,7 @@ const char *TargetInfo::getTypeName(IntType T) { /// integer type enum. For example, SignedLong -> "L". const char *TargetInfo::getTypeConstantSuffix(IntType T) { switch (T) { - default: assert(0 && "not an integer!"); + default: llvm_unreachable("not an integer!"); case SignedShort: case SignedInt: return ""; case SignedLong: return "L"; @@ -115,7 +124,7 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) { /// enum. For example, SignedInt -> getIntWidth(). unsigned TargetInfo::getTypeWidth(IntType T) const { switch (T) { - default: assert(0 && "not an integer!"); + default: llvm_unreachable("not an integer!"); case SignedShort: case UnsignedShort: return getShortWidth(); case SignedInt: @@ -131,7 +140,7 @@ unsigned TargetInfo::getTypeWidth(IntType T) const { /// enum. For example, SignedInt -> getIntAlign(). unsigned TargetInfo::getTypeAlign(IntType T) const { switch (T) { - default: assert(0 && "not an integer!"); + default: llvm_unreachable("not an integer!"); case SignedShort: case UnsignedShort: return getShortAlign(); case SignedInt: @@ -147,7 +156,7 @@ unsigned TargetInfo::getTypeAlign(IntType T) const { /// the type is signed; false otherwise. bool TargetInfo::isTypeSigned(IntType T) { switch (T) { - default: assert(0 && "not an integer!"); + default: llvm_unreachable("not an integer!"); case SignedShort: case SignedInt: case SignedLong: @@ -174,7 +183,7 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) { //===----------------------------------------------------------------------===// -static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) { +static StringRef removeGCCRegisterPrefix(StringRef Name) { if (Name[0] == '%' || Name[0] == '#') Name = Name.substr(1); @@ -184,7 +193,7 @@ static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) { /// isValidClobber - Returns whether the passed in string is /// a valid clobber in an inline asm statement. This is used by /// Sema. -bool TargetInfo::isValidClobber(llvm::StringRef Name) const { +bool TargetInfo::isValidClobber(StringRef Name) const { return (isValidGCCRegisterName(Name) || Name == "memory" || Name == "cc"); } @@ -192,7 +201,7 @@ bool TargetInfo::isValidClobber(llvm::StringRef Name) const { /// isValidGCCRegisterName - Returns whether the passed in string /// is a valid register name according to GCC. This is used by Sema for /// inline asm statements. -bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const { +bool TargetInfo::isValidGCCRegisterName(StringRef Name) const { if (Name.empty()) return false; @@ -248,8 +257,8 @@ bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const { return false; } -llvm::StringRef -TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const { +StringRef +TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const { assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); // Get rid of any register prefix. diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index 4c1eeed..6d0d7bb 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Type.h" #include <algorithm> using namespace clang; @@ -37,7 +38,7 @@ using namespace clang; /// DefineStd - Define a macro name and standard variants. For example if /// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" /// when in GNU mode. -static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName, +static void DefineStd(MacroBuilder &Builder, StringRef MacroName, const LangOptions &Opts) { assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); @@ -77,7 +78,7 @@ public: static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, const llvm::Triple &Triple, - llvm::StringRef &PlatformName, + StringRef &PlatformName, VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "5621"); Builder.defineMacro("__APPLE__"); @@ -89,7 +90,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); // Darwin defines __strong even in C mode (just to nothing). - if (Opts.getGCMode() != LangOptions::NonGC) + if (Opts.getGC() != LangOptions::NonGC) Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); else Builder.defineMacro("__strong", ""); @@ -146,6 +147,14 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, } } + // If -ccc-host-triple arch-pc-win32-macho option specified, we're + // generating code for Win32 ABI. No need to emit + // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. + if (PlatformName == "win32") { + PlatformMinVersion = VersionTuple(Maj, Min, Rev); + return; + } + // Set the appropriate OS version define. if (PlatformName == "ios") { assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); @@ -194,9 +203,9 @@ public: this->MCountName = "\01mcount"; } - virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const { + virtual std::string isValidSectionSpecifier(StringRef SR) const { // Let MCSectionMachO validate this. - llvm::StringRef Segment, Section; + StringRef Segment, Section; unsigned TAA, StubSize; bool HasTAA; return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, @@ -242,9 +251,8 @@ protected: if (Release == 0U) Release = 8U; - Builder.defineMacro("__FreeBSD__", llvm::Twine(Release)); - Builder.defineMacro("__FreeBSD_cc_version", - llvm::Twine(Release * 100000U + 1U)); + Builder.defineMacro("__FreeBSD__", Twine(Release)); + Builder.defineMacro("__FreeBSD_cc_version", Twine(Release * 100000U + 1U)); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); @@ -497,9 +505,9 @@ protected: Builder.defineMacro("_MT"); if (Opts.MSCVersion != 0) - Builder.defineMacro("_MSC_VER", llvm::Twine(Opts.MSCVersion)); + Builder.defineMacro("_MSC_VER", Twine(Opts.MSCVersion)); - if (Opts.Microsoft) { + if (Opts.MicrosoftExt) { Builder.defineMacro("_MSC_EXTENSIONS"); if (Opts.CPlusPlus0x) { @@ -871,13 +879,41 @@ public: } // end anonymous namespace. namespace { + static const unsigned PTXAddrSpaceMap[] = { + 0, // opencl_global + 4, // opencl_local + 1 // opencl_constant + }; class PTXTargetInfo : public TargetInfo { static const char * const GCCRegNames[]; static const Builtin::Info BuiltinInfo[]; + std::vector<llvm::StringRef> AvailableFeatures; public: PTXTargetInfo(const std::string& triple) : TargetInfo(triple) { TLSSupported = false; LongWidth = LongAlign = 64; + AddrSpaceMap = &PTXAddrSpaceMap; + // Define available target features + // These must be defined in sorted order! + AvailableFeatures.push_back("compute10"); + AvailableFeatures.push_back("compute11"); + AvailableFeatures.push_back("compute12"); + AvailableFeatures.push_back("compute13"); + AvailableFeatures.push_back("compute20"); + AvailableFeatures.push_back("double"); + AvailableFeatures.push_back("no-fma"); + AvailableFeatures.push_back("ptx20"); + AvailableFeatures.push_back("ptx21"); + AvailableFeatures.push_back("ptx22"); + AvailableFeatures.push_back("ptx23"); + AvailableFeatures.push_back("sm10"); + AvailableFeatures.push_back("sm11"); + AvailableFeatures.push_back("sm12"); + AvailableFeatures.push_back("sm13"); + AvailableFeatures.push_back("sm20"); + AvailableFeatures.push_back("sm21"); + AvailableFeatures.push_back("sm22"); + AvailableFeatures.push_back("sm23"); } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -910,6 +946,10 @@ namespace { // FIXME: implement return "typedef char* __builtin_va_list;"; } + + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const; }; const Builtin::Info PTXTargetInfo::BuiltinInfo[] = { @@ -929,6 +969,17 @@ namespace { NumNames = llvm::array_lengthof(GCCRegNames); } + bool PTXTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const { + if(std::binary_search(AvailableFeatures.begin(), AvailableFeatures.end(), + Name)) { + Features[Name] = Enabled; + return true; + } else { + return false; + } + } class PTX32TargetInfo : public PTXTargetInfo { public: @@ -1121,10 +1172,134 @@ class X86TargetInfo : public TargetInfo { bool HasAES; bool HasAVX; + /// \brief Enumeration of all of the X86 CPUs supported by Clang. + /// + /// Each enumeration represents a particular CPU supported by Clang. These + /// loosely correspond to the options passed to '-march' or '-mtune' flags. + enum CPUKind { + CK_Generic, + + /// \name i386 + /// i386-generation processors. + //@{ + CK_i386, + //@} + + /// \name i486 + /// i486-generation processors. + //@{ + CK_i486, + CK_WinChipC6, + CK_WinChip2, + CK_C3, + //@} + + /// \name i586 + /// i586-generation processors, P5 microarchitecture based. + //@{ + CK_i586, + CK_Pentium, + CK_PentiumMMX, + //@} + + /// \name i686 + /// i686-generation processors, P6 / Pentium M microarchitecture based. + //@{ + CK_i686, + CK_PentiumPro, + CK_Pentium2, + CK_Pentium3, + CK_Pentium3M, + CK_PentiumM, + CK_C3_2, + + /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. + /// Clang however has some logic to suport this. + // FIXME: Warn, deprecate, and potentially remove this. + CK_Yonah, + //@} + + /// \name Netburst + /// Netburst microarchitecture based processors. + //@{ + CK_Pentium4, + CK_Pentium4M, + CK_Prescott, + CK_Nocona, + //@} + + /// \name Core + /// Core microarchitecture based processors. + //@{ + CK_Core2, + + /// This enumerator, like \see CK_Yonah, is a bit odd. It is another + /// codename which GCC no longer accepts as an option to -march, but Clang + /// has some logic for recognizing it. + // FIXME: Warn, deprecate, and potentially remove this. + CK_Penryn, + //@} + + /// \name Atom + /// Atom processors + //@{ + CK_Atom, + //@} + + /// \name Nehalem + /// Nehalem microarchitecture based processors. + //@{ + CK_Corei7, + CK_Corei7AVX, + CK_CoreAVXi, + //@} + + /// \name K6 + /// K6 architecture processors. + //@{ + CK_K6, + CK_K6_2, + CK_K6_3, + //@} + + /// \name K7 + /// K7 architecture processors. + //@{ + CK_Athlon, + CK_AthlonThunderbird, + CK_Athlon4, + CK_AthlonXP, + CK_AthlonMP, + //@} + + /// \name K8 + /// K8 architecture processors. + //@{ + CK_Athlon64, + CK_Athlon64SSE3, + CK_AthlonFX, + CK_K8, + CK_K8SSE3, + CK_Opteron, + CK_OpteronSSE3, + + /// This specification is deprecated and will be removed in the future. + /// Users should prefer \see CK_K8. + // FIXME: Warn on this when the CPU is set to it. + CK_x86_64, + //@} + + /// \name Geode + /// Geode processors. + //@{ + CK_Geode + //@} + } CPU; + public: X86TargetInfo(const std::string& triple) : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), - HasAES(false), HasAVX(false) { + HasAES(false), HasAVX(false), CPU(CK_Generic) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -1158,16 +1333,122 @@ public: virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, const std::string &Name, bool Enabled) const; - virtual void getDefaultFeatures(const std::string &CPU, - llvm::StringMap<bool> &Features) const; + virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const; virtual void HandleTargetFeatures(std::vector<std::string> &Features); virtual const char* getABI() const { return MMX3DNowLevel == NoMMX3DNow ? "no-mmx" : ""; } + virtual bool setCPU(const std::string &Name) { + CPU = llvm::StringSwitch<CPUKind>(Name) + .Case("i386", CK_i386) + .Case("i486", CK_i486) + .Case("winchip-c6", CK_WinChipC6) + .Case("winchip2", CK_WinChip2) + .Case("c3", CK_C3) + .Case("i586", CK_i586) + .Case("pentium", CK_Pentium) + .Case("pentium-mmx", CK_PentiumMMX) + .Case("i686", CK_i686) + .Case("pentiumpro", CK_PentiumPro) + .Case("pentium2", CK_Pentium2) + .Case("pentium3", CK_Pentium3) + .Case("pentium3m", CK_Pentium3M) + .Case("pentium-m", CK_PentiumM) + .Case("c3-2", CK_C3_2) + .Case("yonah", CK_Yonah) + .Case("pentium4", CK_Pentium4) + .Case("pentium4m", CK_Pentium4M) + .Case("prescott", CK_Prescott) + .Case("nocona", CK_Nocona) + .Case("core2", CK_Core2) + .Case("penryn", CK_Penryn) + .Case("atom", CK_Atom) + .Case("corei7", CK_Corei7) + .Case("corei7-avx", CK_Corei7AVX) + .Case("core-avx-i", CK_CoreAVXi) + .Case("k6", CK_K6) + .Case("k6-2", CK_K6_2) + .Case("k6-3", CK_K6_3) + .Case("athlon", CK_Athlon) + .Case("athlon-tbird", CK_AthlonThunderbird) + .Case("athlon-4", CK_Athlon4) + .Case("athlon-xp", CK_AthlonXP) + .Case("athlon-mp", CK_AthlonMP) + .Case("athlon64", CK_Athlon64) + .Case("athlon64-sse3", CK_Athlon64SSE3) + .Case("athlon-fx", CK_AthlonFX) + .Case("k8", CK_K8) + .Case("k8-sse3", CK_K8SSE3) + .Case("opteron", CK_Opteron) + .Case("opteron-sse3", CK_OpteronSSE3) + .Case("x86-64", CK_x86_64) + .Case("geode", CK_Geode) + .Default(CK_Generic); + + // Perform any per-CPU checks necessary to determine if this CPU is + // acceptable. + // FIXME: This results in terrible diagnostics. Clang just says the CPU is + // invalid without explaining *why*. + switch (CPU) { + case CK_Generic: + // No processor selected! + return false; + + case CK_i386: + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + case CK_i586: + case CK_Pentium: + case CK_PentiumMMX: + case CK_i686: + case CK_PentiumPro: + case CK_Pentium2: + case CK_Pentium3: + case CK_Pentium3M: + case CK_PentiumM: + case CK_Yonah: + case CK_C3_2: + case CK_Pentium4: + case CK_Pentium4M: + case CK_Prescott: + case CK_K6: + case CK_K6_2: + case CK_K6_3: + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: + case CK_Geode: + // Only accept certain architectures when compiling in 32-bit mode. + if (PointerWidth != 32) + return false; + + // Fallthrough + case CK_Nocona: + case CK_Core2: + case CK_Penryn: + case CK_Atom: + case CK_Corei7: + case CK_Corei7AVX: + case CK_CoreAVXi: + case CK_Athlon64: + case CK_Athlon64SSE3: + case CK_AthlonFX: + case CK_K8: + case CK_K8SSE3: + case CK_Opteron: + case CK_OpteronSSE3: + case CK_x86_64: + return true; + } + llvm_unreachable("Unhandled CPU kind"); + } }; -void X86TargetInfo::getDefaultFeatures(const std::string &CPU, - llvm::StringMap<bool> &Features) const { +void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { // FIXME: This should not be here. Features["3dnow"] = false; Features["3dnowa"] = false; @@ -1190,57 +1471,100 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, if (PointerWidth == 64) Features["sse2"] = Features["sse"] = Features["mmx"] = true; - if (CPU == "generic" || CPU == "i386" || CPU == "i486" || CPU == "i586" || - CPU == "pentium" || CPU == "i686" || CPU == "pentiumpro") - ; - else if (CPU == "pentium-mmx" || CPU == "pentium2") + switch (CPU) { + case CK_Generic: + case CK_i386: + case CK_i486: + case CK_i586: + case CK_Pentium: + case CK_i686: + case CK_PentiumPro: + break; + case CK_PentiumMMX: + case CK_Pentium2: setFeatureEnabled(Features, "mmx", true); - else if (CPU == "pentium3") { + break; + case CK_Pentium3: + case CK_Pentium3M: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse", true); - } else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64") { + break; + case CK_PentiumM: + case CK_Pentium4: + case CK_Pentium4M: + case CK_x86_64: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse2", true); - } else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona") { + break; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse3", true); - } else if (CPU == "core2") { + break; + case CK_Core2: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "ssse3", true); - } else if (CPU == "penryn") { + break; + case CK_Penryn: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse4", true); Features["sse42"] = false; - } else if (CPU == "atom") { + break; + case CK_Atom: setFeatureEnabled(Features, "mmx", true); - setFeatureEnabled(Features, "sse3", true); - } else if (CPU == "corei7") { + setFeatureEnabled(Features, "ssse3", true); + break; + case CK_Corei7: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); - } else if (CPU == "corei7-avx") { + break; + case CK_Corei7AVX: + case CK_CoreAVXi: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); //setFeatureEnabled(Features, "avx", true); - } else if (CPU == "k6" || CPU == "winchip-c6") + break; + case CK_K6: + case CK_WinChipC6: setFeatureEnabled(Features, "mmx", true); - else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || - CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") { + break; + case CK_K6_2: + case CK_K6_3: + case CK_WinChip2: + case CK_C3: setFeatureEnabled(Features, "3dnow", true); - } else if (CPU == "athlon-4" || CPU == "athlon-xp" || CPU == "athlon-mp") { + break; + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Geode: + setFeatureEnabled(Features, "3dnowa", true); + break; + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: setFeatureEnabled(Features, "sse", true); setFeatureEnabled(Features, "3dnowa", true); - } else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" || - CPU == "athlon-fx") { + break; + case CK_K8: + case CK_Opteron: + case CK_Athlon64: + case CK_AthlonFX: setFeatureEnabled(Features, "sse2", true); setFeatureEnabled(Features, "3dnowa", true); - } else if (CPU == "k8-sse3") { + break; + case CK_K8SSE3: + case CK_OpteronSSE3: + case CK_Athlon64SSE3: setFeatureEnabled(Features, "sse3", true); setFeatureEnabled(Features, "3dnowa", true); - } else if (CPU == "c3-2") { + break; + case CK_C3_2: setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "sse", true); + break; } } @@ -1278,7 +1602,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, else if (Name == "aes") Features["aes"] = true; else if (Name == "avx") - Features["avx"] = true; + Features["avx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = Features["sse42"] = true; } else { if (Name == "mmx") Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false; @@ -1360,8 +1685,8 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { Features.erase(it); } -/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines -/// that are not tied to a specific subtarget. +/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro +/// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. @@ -1376,19 +1701,140 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, DefineStd(Builder, "i386", Opts); } - if (HasAES) - Builder.defineMacro("__AES__"); - - if (HasAVX) - Builder.defineMacro("__AVX__"); + // Subtarget options. + // FIXME: We are hard-coding the tune parameters based on the CPU, but they + // truly should be based on -mtune options. + switch (CPU) { + case CK_Generic: + break; + case CK_i386: + // The rest are coming from the i386 define above. + Builder.defineMacro("__tune_i386__"); + break; + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + Builder.defineMacro("__i486"); + Builder.defineMacro("__i486__"); + Builder.defineMacro("__tune_i486__"); + break; + case CK_PentiumMMX: + Builder.defineMacro("__pentium_mmx__"); + Builder.defineMacro("__tune_pentium_mmx__"); + // Fallthrough + case CK_i586: + case CK_Pentium: + Builder.defineMacro("__i586"); + Builder.defineMacro("__i586__"); + Builder.defineMacro("__tune_i586__"); + Builder.defineMacro("__pentium"); + Builder.defineMacro("__pentium__"); + Builder.defineMacro("__tune_pentium__"); + break; + case CK_Pentium3: + case CK_Pentium3M: + case CK_PentiumM: + Builder.defineMacro("__tune_pentium3__"); + // Fallthrough + case CK_Pentium2: + case CK_C3_2: + Builder.defineMacro("__tune_pentium2__"); + // Fallthrough + case CK_PentiumPro: + Builder.defineMacro("__tune_i686__"); + Builder.defineMacro("__tune_pentiumpro__"); + // Fallthrough + case CK_i686: + Builder.defineMacro("__i686"); + Builder.defineMacro("__i686__"); + // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686. + Builder.defineMacro("__pentiumpro"); + Builder.defineMacro("__pentiumpro__"); + break; + case CK_Pentium4: + case CK_Pentium4M: + Builder.defineMacro("__pentium4"); + Builder.defineMacro("__pentium4__"); + Builder.defineMacro("__tune_pentium4__"); + break; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: + Builder.defineMacro("__nocona"); + Builder.defineMacro("__nocona__"); + Builder.defineMacro("__tune_nocona__"); + break; + case CK_Core2: + case CK_Penryn: + Builder.defineMacro("__core2"); + Builder.defineMacro("__core2__"); + Builder.defineMacro("__tune_core2__"); + break; + case CK_Atom: + Builder.defineMacro("__atom"); + Builder.defineMacro("__atom__"); + Builder.defineMacro("__tune_atom__"); + break; + case CK_Corei7: + case CK_Corei7AVX: + case CK_CoreAVXi: + Builder.defineMacro("__corei7"); + Builder.defineMacro("__corei7__"); + Builder.defineMacro("__tune_corei7__"); + break; + case CK_K6_2: + Builder.defineMacro("__k6_2__"); + Builder.defineMacro("__tune_k6_2__"); + // Fallthrough + case CK_K6_3: + if (CPU != CK_K6_2) { // In case of fallthrough + // FIXME: GCC may be enabling these in cases where some other k6 + // architecture is specified but -m3dnow is explicitly provided. The + // exact semantics need to be determined and emulated here. + Builder.defineMacro("__k6_3__"); + Builder.defineMacro("__tune_k6_3__"); + } + // Fallthrough + case CK_K6: + Builder.defineMacro("__k6"); + Builder.defineMacro("__k6__"); + Builder.defineMacro("__tune_k6__"); + break; + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: + Builder.defineMacro("__athlon"); + Builder.defineMacro("__athlon__"); + Builder.defineMacro("__tune_athlon__"); + if (SSELevel != NoSSE) { + Builder.defineMacro("__athlon_sse__"); + Builder.defineMacro("__tune_athlon_sse__"); + } + break; + case CK_K8: + case CK_K8SSE3: + case CK_x86_64: + case CK_Opteron: + case CK_OpteronSSE3: + case CK_Athlon64: + case CK_Athlon64SSE3: + case CK_AthlonFX: + Builder.defineMacro("__k8"); + Builder.defineMacro("__k8__"); + Builder.defineMacro("__tune_k8__"); + break; + case CK_Geode: + Builder.defineMacro("__geode"); + Builder.defineMacro("__geode__"); + Builder.defineMacro("__tune_geode__"); + break; + } // Target properties. Builder.defineMacro("__LITTLE_ENDIAN__"); - - // Subtarget options. - Builder.defineMacro("__nocona"); - Builder.defineMacro("__nocona__"); - Builder.defineMacro("__tune_nocona__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline @@ -1396,6 +1842,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, // backend can't deal with (PR879). Builder.defineMacro("__NO_MATH_INLINES"); + if (HasAES) + Builder.defineMacro("__AES__"); + + if (HasAVX) + Builder.defineMacro("__AVX__"); + // Each case falls through to the previous one here. switch (SSELevel) { case SSE42: @@ -1416,20 +1868,20 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, break; } - if (Opts.Microsoft && PointerWidth == 32) { + if (Opts.MicrosoftExt && PointerWidth == 32) { switch (SSELevel) { case SSE42: case SSE41: case SSSE3: case SSE3: case SSE2: - Builder.defineMacro("_M_IX86_FP", llvm::Twine(2)); + Builder.defineMacro("_M_IX86_FP", Twine(2)); break; case SSE1: - Builder.defineMacro("_M_IX86_FP", llvm::Twine(1)); + Builder.defineMacro("_M_IX86_FP", Twine(1)); break; default: - Builder.defineMacro("_M_IX86_FP", llvm::Twine(0)); + Builder.defineMacro("_M_IX86_FP", Twine(0)); } } @@ -1523,7 +1975,7 @@ public: LongDoubleAlign = 32; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32-n8:16:32"; + "a0:0:64-f80:32:32-n8:16:32-S128"; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; @@ -1533,6 +1985,11 @@ public: RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | (1 << TargetInfo::LongDouble)); + + // x86-32 has atomics up to 8 bytes + // FIXME: Check that we actually have cmpxchg8b before setting + // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } virtual const char *getVAListDeclaration() const { return "typedef char* __builtin_va_list;"; @@ -1569,7 +2026,7 @@ public: IntPtrType = SignedLong; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:128:128-n8:16:32"; + "a0:0:64-f80:128:128-n8:16:32-S128"; HasAlignMac68kSupport = true; } @@ -1587,7 +2044,7 @@ public: DoubleAlign = LongLongAlign = 64; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-" - "v128:128:128-a0:0:64-f80:32:32-n8:16:32"; + "v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32"; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -1636,7 +2093,7 @@ public: // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. - if (Opts.Microsoft) + if (Opts.MicrosoftExt) // Provide "as-is" __declspec. Builder.defineMacro("__declspec", "__declspec"); else @@ -1657,7 +2114,7 @@ public: DoubleAlign = LongLongAlign = 64; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32-n8:16:32"; + "a0:0:64-f80:32:32-n8:16:32-S32"; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -1699,9 +2156,6 @@ protected: MacroBuilder &Builder) const { // RTEMS defines; list based off of gcc output - // FIXME: Move version number handling to llvm::Triple. - llvm::StringRef Release = Triple.getOSName().substr(strlen("rtems"), 1); - Builder.defineMacro("__rtems__"); Builder.defineMacro("__ELF__"); } @@ -1767,10 +2221,16 @@ public: DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"; + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); + + // x86-64 has atomics up to 16 bytes. + // FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128 + // on CPUs with cmpxchg16b + MaxAtomicPromoteWidth = 128; + MaxAtomicInlineWidth = 64; } virtual const char *getVAListDeclaration() const { return "typedef struct __va_list_tag {" @@ -1855,7 +2315,7 @@ public: // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. - if (Opts.Microsoft) + if (Opts.MicrosoftExt) // Provide "as-is" __declspec. Builder.defineMacro("__declspec", "__declspec"); else @@ -1934,15 +2394,19 @@ public: // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:64:128-a0:0:32-n32"); + "v64:64:64-v128:64:128-a0:0:32-n32-S64"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:64:128-a0:0:64-n32"); + "v64:64:64-v128:64:128-a0:0:64-n32-S64"); } // ARM targets default to using the ARM C++ ABI. CXXABI = CXXABI_ARM; + + // ARM has atomics up to 8 bytes + // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e + MaxAtomicPromoteWidth = 64; } virtual const char *getABI() const { return ABI.c_str(); } virtual bool setABI(const std::string &Name) { @@ -1960,16 +2424,27 @@ public: // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. UseBitFieldTypeAlignment = false; + /// Do force alignment of members that follow zero length bitfields. If + /// the alignment of the zero-length bitfield is greater than the member + /// that follows it, `bar', `bar' will be aligned as the type of the + /// zero length bitfield. + UseZeroLengthBitfieldAlignment = true; + + /// gcc forces the alignment to 4 bytes, regardless of the type of the + /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in + /// gcc. + ZeroLengthBitfieldBoundary = 32; + if (IsThumb) { // Thumb1 add sp, #imm requires the immediate value be multiple of 4, // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-" - "v64:32:64-v128:32:128-a0:0:32-n32"); + "v64:32:64-v128:32:128-a0:0:32-n32-S32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-" - "v64:32:64-v128:32:128-a0:0:32-n32"); + "v64:32:64-v128:32:128-a0:0:32-n32-S32"); } // FIXME: Override "preferred align" for double and long long. @@ -1983,8 +2458,7 @@ public: return true; } - void getDefaultFeatures(const std::string &CPU, - llvm::StringMap<bool> &Features) const { + void getDefaultFeatures(llvm::StringMap<bool> &Features) const { if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") Features["vfp2"] = true; else if (CPU == "cortex-a8" || CPU == "cortex-a9") @@ -2029,7 +2503,7 @@ public: Features.erase(it); } - static const char *getCPUDefineSuffix(llvm::StringRef Name) { + static const char *getCPUDefineSuffix(StringRef Name) { return llvm::StringSwitch<const char*>(Name) .Cases("arm8", "arm810", "4") .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4") @@ -2068,7 +2542,7 @@ public: Builder.defineMacro("__LITTLE_ENDIAN__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); - llvm::StringRef CPUArch = getCPUDefineSuffix(CPU); + StringRef CPUArch = getCPUDefineSuffix(CPU); Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); // Subtarget options. @@ -2131,6 +2605,9 @@ public: case 'P': // VFP Floating point register double precision Info.setAllowsRegister(); return true; + case 'Q': // A memory address that is a single base register. + Info.setAllowsMemory(); + return true; case 'U': // a memory reference... switch (Name[1]) { case 'q': // ...ARMV4 ldrsb @@ -2247,6 +2724,9 @@ public: DarwinARMTargetInfo(const std::string& triple) : DarwinTargetInfo<ARMTargetInfo>(triple) { HasAlignMac68kSupport = true; + // iOS always has 64-bit atomic instructions. + // FIXME: This should be based off of the target features in ARMTargetInfo. + MaxAtomicInlineWidth = 64; } }; } // end anonymous namespace. @@ -2592,6 +3072,12 @@ namespace { // target processor and program binary. TCE co-design environment is // publicly available in http://tce.cs.tut.fi + static const unsigned TCEOpenCLAddrSpaceMap[] = { + 3, // opencl_global + 4, // opencl_local + 5 // opencl_constant + }; + class TCETargetInfo : public TargetInfo{ public: TCETargetInfo(const std::string& triple) : TargetInfo(triple) { @@ -2620,6 +3106,7 @@ namespace { "i16:16:32-i32:32:32-i64:32:32-" "f32:32:32-f64:32:32-v64:32:32-" "v128:32:32-a0:0:32-n32"; + AddrSpaceMap = &TCEOpenCLAddrSpaceMap; } virtual void getTargetDefines(const LangOptions &Opts, @@ -2648,51 +3135,30 @@ namespace { } namespace { -class MipsTargetInfo : public TargetInfo { - std::string ABI, CPU; - static const TargetInfo::GCCRegAlias GCCRegAliases[]; - static const char * const GCCRegNames[]; +class MipsTargetInfoBase : public TargetInfo { + std::string CPU; +protected: + std::string ABI; public: - MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") { - DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + MipsTargetInfoBase(const std::string& triple, const std::string& ABIStr) + : TargetInfo(triple), ABI(ABIStr) { SizeType = UnsignedInt; PtrDiffType = SignedInt; } virtual const char *getABI() const { return ABI.c_str(); } - virtual bool setABI(const std::string &Name) { - - if ((Name == "o32") || (Name == "eabi")) { - ABI = Name; - return true; - } else - return false; - } + virtual bool setABI(const std::string &Name) = 0; virtual bool setCPU(const std::string &Name) { CPU = Name; return true; } - void getDefaultFeatures(const std::string &CPU, - llvm::StringMap<bool> &Features) const { + void getDefaultFeatures(llvm::StringMap<bool> &Features) const { Features[ABI] = true; Features[CPU] = true; } virtual void getArchDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - if (ABI == "o32") - Builder.defineMacro("__mips_o32"); - else if (ABI == "eabi") - Builder.defineMacro("__mips_eabi"); - } + MacroBuilder &Builder) const = 0; virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); - DefineStd(Builder, "MIPSEB", Opts); - Builder.defineMacro("_MIPSEB"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); - } + MacroBuilder &Builder) const = 0; virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { // FIXME: Implement! @@ -2701,9 +3167,24 @@ public: return "typedef void* __builtin_va_list;"; } virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const; + unsigned &NumNames) const { + static const char * const GCCRegNames[] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", + "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", + "$fcc5","$fcc6","$fcc7" + }; + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const; + unsigned &NumAliases) const = 0; virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { @@ -2724,89 +3205,296 @@ public: } }; -const char * const MipsTargetInfo::GCCRegNames[] = { - "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", - "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", - "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", - "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", - "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", - "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", - "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", - "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", - "$fcc5","$fcc6","$fcc7" +class Mips32TargetInfoBase : public MipsTargetInfoBase { +public: + Mips32TargetInfoBase(const std::string& triple) : + MipsTargetInfoBase(triple, "o32") {} + virtual bool setABI(const std::string &Name) { + if ((Name == "o32") || (Name == "eabi")) { + ABI = Name; + return true; + } else + return false; + } + virtual void getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (ABI == "o32") { + Builder.defineMacro("__mips_o32"); + Builder.defineMacro("_ABIO32", "1"); + Builder.defineMacro("_MIPS_SIM", "_ABIO32"); + } + else if (ABI == "eabi") + Builder.defineMacro("__mips_eabi"); + else + llvm_unreachable("Invalid ABI for Mips32."); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "at" }, "$1" }, + { { "v0" }, "$2" }, + { { "v1" }, "$3" }, + { { "a0" }, "$4" }, + { { "a1" }, "$5" }, + { { "a2" }, "$6" }, + { { "a3" }, "$7" }, + { { "t0" }, "$8" }, + { { "t1" }, "$9" }, + { { "t2" }, "$10" }, + { { "t3" }, "$11" }, + { { "t4" }, "$12" }, + { { "t5" }, "$13" }, + { { "t6" }, "$14" }, + { { "t7" }, "$15" }, + { { "s0" }, "$16" }, + { { "s1" }, "$17" }, + { { "s2" }, "$18" }, + { { "s3" }, "$19" }, + { { "s4" }, "$20" }, + { { "s5" }, "$21" }, + { { "s6" }, "$22" }, + { { "s7" }, "$23" }, + { { "t8" }, "$24" }, + { { "t9" }, "$25" }, + { { "k0" }, "$26" }, + { { "k1" }, "$27" }, + { { "gp" }, "$28" }, + { { "sp" }, "$29" }, + { { "fp" }, "$30" }, + { { "ra" }, "$31" } + }; + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } }; -void MipsTargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); -} +class Mips32EBTargetInfo : public Mips32TargetInfoBase { +public: + Mips32EBTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) { + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); + } +}; -const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = { - { { "at" }, "$1" }, - { { "v0" }, "$2" }, - { { "v1" }, "$3" }, - { { "a0" }, "$4" }, - { { "a1" }, "$5" }, - { { "a2" }, "$6" }, - { { "a3" }, "$7" }, - { { "t0" }, "$8" }, - { { "t1" }, "$9" }, - { { "t2" }, "$10" }, - { { "t3" }, "$11" }, - { { "t4" }, "$12" }, - { { "t5" }, "$13" }, - { { "t6" }, "$14" }, - { { "t7" }, "$15" }, - { { "s0" }, "$16" }, - { { "s1" }, "$17" }, - { { "s2" }, "$18" }, - { { "s3" }, "$19" }, - { { "s4" }, "$20" }, - { { "s5" }, "$21" }, - { { "s6" }, "$22" }, - { { "s7" }, "$23" }, - { { "t8" }, "$24" }, - { { "t9" }, "$25" }, - { { "k0" }, "$26" }, - { { "k1" }, "$27" }, - { { "gp" }, "$28" }, - { { "sp" }, "$29" }, - { { "fp" }, "$30" }, - { { "ra" }, "$31" } +class Mips32ELTargetInfo : public Mips32TargetInfoBase { +public: + Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) { + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); + } }; -void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); -} +class Mips64TargetInfoBase : public MipsTargetInfoBase { + virtual void SetDescriptionString(const std::string &Name) = 0; +public: + Mips64TargetInfoBase(const std::string& triple) : + MipsTargetInfoBase(triple, "n64") {} + virtual bool setABI(const std::string &Name) { + SetDescriptionString(Name); + if ((Name == "n32") || (Name == "n64")) { + ABI = Name; + return true; + } else + return false; + } + virtual void getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (ABI == "n32") { + Builder.defineMacro("__mips_n32"); + Builder.defineMacro("_ABIN32", "2"); + Builder.defineMacro("_MIPS_SIM", "_ABIN32"); + } + else if (ABI == "n64") { + Builder.defineMacro("__mips_n64"); + Builder.defineMacro("_ABI64", "3"); + Builder.defineMacro("_MIPS_SIM", "_ABI64"); + } + else + llvm_unreachable("Invalid ABI for Mips64."); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "at" }, "$1" }, + { { "v0" }, "$2" }, + { { "v1" }, "$3" }, + { { "a0" }, "$4" }, + { { "a1" }, "$5" }, + { { "a2" }, "$6" }, + { { "a3" }, "$7" }, + { { "a4" }, "$8" }, + { { "a5" }, "$9" }, + { { "a6" }, "$10" }, + { { "a7" }, "$11" }, + { { "t0" }, "$12" }, + { { "t1" }, "$13" }, + { { "t2" }, "$14" }, + { { "t3" }, "$15" }, + { { "s0" }, "$16" }, + { { "s1" }, "$17" }, + { { "s2" }, "$18" }, + { { "s3" }, "$19" }, + { { "s4" }, "$20" }, + { { "s5" }, "$21" }, + { { "s6" }, "$22" }, + { { "s7" }, "$23" }, + { { "t8" }, "$24" }, + { { "t9" }, "$25" }, + { { "k0" }, "$26" }, + { { "k1" }, "$27" }, + { { "gp" }, "$28" }, + { { "sp" }, "$29" }, + { { "fp" }, "$30" }, + { { "ra" }, "$31" } + }; + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } +}; + +class Mips64EBTargetInfo : public Mips64TargetInfoBase { + virtual void SetDescriptionString(const std::string &Name) { + // Change DescriptionString only if ABI is n32. + if (Name == "n32") + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } +public: + Mips64EBTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) { + // Default ABI is n64. + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); + } +}; + +class Mips64ELTargetInfo : public Mips64TargetInfoBase { + virtual void SetDescriptionString(const std::string &Name) { + // Change DescriptionString only if ABI is n32. + if (Name == "n32") + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } +public: + Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) { + // Default ABI is n64. + DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); + } +}; } // end anonymous namespace. namespace { -class MipselTargetInfo : public MipsTargetInfo { +class PNaClTargetInfo : public TargetInfo { public: - MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) { - DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + PNaClTargetInfo(const std::string& triple) : TargetInfo(triple) { + this->UserLabelPrefix = ""; + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->UIntMaxType = TargetInfo::UnsignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + this->RegParmMax = 2; + DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" + "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; } + void getDefaultFeatures(llvm::StringMap<bool> &Features) const { + } + virtual void getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__le32__"); + Builder.defineMacro("__pnacl__"); + } virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const; + MacroBuilder &Builder) const { + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + + Builder.defineMacro("__native_client__"); + getArchDefines(Opts, Builder); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + } + virtual const char *getVAListDeclaration() const { + return "typedef int __builtin_va_list[4];"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + return false; + } + + virtual const char *getClobbers() const { + return ""; + } }; -void MipselTargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); - DefineStd(Builder, "MIPSEL", Opts); - Builder.defineMacro("_MIPSEL"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); +void PNaClTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = NULL; + NumNames = 0; +} + +void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = NULL; + NumAliases = 0; } } // end anonymous namespace. + //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// @@ -2847,40 +3535,74 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::mips: switch (os) { - case llvm::Triple::Psp: - return new PSPTargetInfo<MipsTargetInfo>(T); case llvm::Triple::Linux: - return new LinuxTargetInfo<MipsTargetInfo>(T); + return new LinuxTargetInfo<Mips32EBTargetInfo>(T); case llvm::Triple::RTEMS: - return new RTEMSTargetInfo<MipsTargetInfo>(T); + return new RTEMSTargetInfo<Mips32EBTargetInfo>(T); case llvm::Triple::FreeBSD: - return new FreeBSDTargetInfo<MipsTargetInfo>(T); + return new FreeBSDTargetInfo<Mips32EBTargetInfo>(T); case llvm::Triple::NetBSD: - return new NetBSDTargetInfo<MipsTargetInfo>(T); + return new NetBSDTargetInfo<Mips32EBTargetInfo>(T); default: - return new MipsTargetInfo(T); + return new Mips32EBTargetInfo(T); } case llvm::Triple::mipsel: switch (os) { - case llvm::Triple::Psp: - return new PSPTargetInfo<MipselTargetInfo>(T); case llvm::Triple::Linux: - return new LinuxTargetInfo<MipselTargetInfo>(T); + return new LinuxTargetInfo<Mips32ELTargetInfo>(T); case llvm::Triple::RTEMS: - return new RTEMSTargetInfo<MipselTargetInfo>(T); + return new RTEMSTargetInfo<Mips32ELTargetInfo>(T); case llvm::Triple::FreeBSD: - return new FreeBSDTargetInfo<MipselTargetInfo>(T); + return new FreeBSDTargetInfo<Mips32ELTargetInfo>(T); case llvm::Triple::NetBSD: - return new NetBSDTargetInfo<MipselTargetInfo>(T); + return new NetBSDTargetInfo<Mips32ELTargetInfo>(T); default: - return new MipsTargetInfo(T); + return new Mips32ELTargetInfo(T); + } + + case llvm::Triple::mips64: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips64EBTargetInfo>(T); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips64EBTargetInfo>(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips64EBTargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips64EBTargetInfo>(T); + default: + return new Mips64EBTargetInfo(T); + } + + case llvm::Triple::mips64el: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips64ELTargetInfo>(T); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips64ELTargetInfo>(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips64ELTargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips64ELTargetInfo>(T); + default: + return new Mips64ELTargetInfo(T); + } + + case llvm::Triple::le32: + switch (os) { + case llvm::Triple::NativeClient: + return new PNaClTargetInfo(T); + default: + return NULL; } case llvm::Triple::ppc: if (Triple.isOSDarwin()) return new DarwinPPC32TargetInfo(T); switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC32TargetInfo>(T); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<PPC32TargetInfo>(T); case llvm::Triple::NetBSD: @@ -2895,6 +3617,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { if (Triple.isOSDarwin()) return new DarwinPPC64TargetInfo(T); switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC64TargetInfo>(T); case llvm::Triple::Lv2: return new PS3PPUTargetInfo<PPC64TargetInfo>(T); case llvm::Triple::FreeBSD: @@ -2915,6 +3639,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::sparc: switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV8TargetInfo>(T); case llvm::Triple::AuroraUX: return new AuroraUXSparcV8TargetInfo(T); case llvm::Triple::Solaris: @@ -3003,7 +3729,7 @@ static TargetInfo *AllocateTarget(const std::string &T) { /// CreateTargetInfo - Return the target info object for the specified target /// triple. -TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, +TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts) { llvm::Triple Triple(Opts.Triple); @@ -3035,7 +3761,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, // Compute the default target features, we need the target to handle this // because features may have dependencies on one another. llvm::StringMap<bool> Features; - Target->getDefaultFeatures(Opts.CPU, Features); + Target->getDefaultFeatures(Features); // Apply the user specified deltas. for (std::vector<std::string>::const_iterator it = Opts.Features.begin(), diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp index 89076ca..390a685 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Version.h" +#include "clang/Basic/LLVM.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Config/config.h" #include <cstring> @@ -24,14 +25,14 @@ std::string getClangRepositoryPath() { return CLANG_REPOSITORY_STRING; #else #ifdef SVN_REPOSITORY - llvm::StringRef URL(SVN_REPOSITORY); + StringRef URL(SVN_REPOSITORY); #else - llvm::StringRef URL(""); + StringRef URL(""); #endif // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static llvm::StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_30/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); @@ -42,7 +43,7 @@ std::string getClangRepositoryPath() { // Trim path prefix off, assuming path came from standard cfe path. size_t Start = URL.find("cfe/"); - if (Start != llvm::StringRef::npos) + if (Start != StringRef::npos) URL = URL.substr(Start + 4); return URL; diff --git a/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp b/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp index d5cf126..77aad39 100644 --- a/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp @@ -25,7 +25,7 @@ std::string VersionTuple::getAsString() const { return Result; } -llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out, +raw_ostream& clang::operator<<(raw_ostream &Out, const VersionTuple &V) { Out << V.getMajor(); if (llvm::Optional<unsigned> Minor = V.getMinor()) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp index 85f42db..b9e3ed9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp @@ -15,6 +15,7 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" #include "llvm/PassManager.h" +#include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/RegAllocRegistry.h" @@ -23,21 +24,24 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/PassManagerBuilder.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegistry.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar.h" using namespace clang; using namespace llvm; namespace { class EmitAssemblyHelper { - Diagnostic &Diags; + DiagnosticsEngine &Diags; const CodeGenOptions &CodeGenOpts; const TargetOptions &TargetOpts; const LangOptions &LangOpts; @@ -82,7 +86,7 @@ private: bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS); public: - EmitAssemblyHelper(Diagnostic &_Diags, + EmitAssemblyHelper(DiagnosticsEngine &_Diags, const CodeGenOptions &CGOpts, const TargetOptions &TOpts, const LangOptions &LOpts, Module *M) @@ -237,27 +241,18 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, TargetMachine::setDataSections (CodeGenOpts.DataSections); // FIXME: Parse this earlier. - if (CodeGenOpts.RelocationModel == "static") { - TargetMachine::setRelocationModel(llvm::Reloc::Static); - } else if (CodeGenOpts.RelocationModel == "pic") { - TargetMachine::setRelocationModel(llvm::Reloc::PIC_); - } else { - assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && - "Invalid PIC model!"); - TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); - } - // FIXME: Parse this earlier. + llvm::CodeModel::Model CM; if (CodeGenOpts.CodeModel == "small") { - TargetMachine::setCodeModel(llvm::CodeModel::Small); + CM = llvm::CodeModel::Small; } else if (CodeGenOpts.CodeModel == "kernel") { - TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + CM = llvm::CodeModel::Kernel; } else if (CodeGenOpts.CodeModel == "medium") { - TargetMachine::setCodeModel(llvm::CodeModel::Medium); + CM = llvm::CodeModel::Medium; } else if (CodeGenOpts.CodeModel == "large") { - TargetMachine::setCodeModel(llvm::CodeModel::Large); + CM = llvm::CodeModel::Large; } else { assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); - TargetMachine::setCodeModel(llvm::CodeModel::Default); + CM = llvm::CodeModel::Default; } std::vector<const char *> BackendArgs; @@ -274,6 +269,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, BackendArgs.push_back("-time-passes"); for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); + if (CodeGenOpts.NoGlobalMerge) + BackendArgs.push_back("-global-merge=false"); BackendArgs.push_back(0); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, const_cast<char **>(&BackendArgs[0])); @@ -287,8 +284,20 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, Features.AddFeature(*it); FeaturesStr = Features.getString(); } + + llvm::Reloc::Model RM = llvm::Reloc::Default; + if (CodeGenOpts.RelocationModel == "static") { + RM = llvm::Reloc::Static; + } else if (CodeGenOpts.RelocationModel == "pic") { + RM = llvm::Reloc::PIC_; + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + RM = llvm::Reloc::DynamicNoPIC; + } + TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU, - FeaturesStr); + FeaturesStr, RM, CM); if (CodeGenOpts.RelaxAll) TM->setMCRelaxAll(true); @@ -386,7 +395,8 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { } } -void clang::EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts, +void clang::EmitBackendOutput(DiagnosticsEngine &Diags, + const CodeGenOptions &CGOpts, const TargetOptions &TOpts, const LangOptions &LOpts, Module *M, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 9815d1d..9694953 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp @@ -59,10 +59,10 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { ASTContext &C = CGM.getContext(); - const llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy); - const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); + llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy); + llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); - llvm::SmallVector<llvm::Constant*, 6> elements; + SmallVector<llvm::Constant*, 6> elements; // reserved elements.push_back(llvm::ConstantInt::get(ulong, 0)); @@ -243,7 +243,7 @@ static CharUnits getLowBit(CharUnits v) { } static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, - llvm::SmallVectorImpl<llvm::Type*> &elementTypes) { + SmallVectorImpl<llvm::Type*> &elementTypes) { ASTContext &C = CGM.getContext(); // The header is basically a 'struct { void *; int; int; void *; void *; }'. @@ -280,7 +280,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { ASTContext &C = CGM.getContext(); const BlockDecl *block = info.getBlockDecl(); - llvm::SmallVector<llvm::Type*, 8> elementTypes; + SmallVector<llvm::Type*, 8> elementTypes; initializeForBlockHeader(CGM, info, elementTypes); if (!block->hasCaptures()) { @@ -291,7 +291,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { } // Collect the layout chunks. - llvm::SmallVector<BlockLayoutChunk, 16> layout; + SmallVector<BlockLayoutChunk, 16> layout; layout.reserve(block->capturesCXXThis() + (block->capture_end() - block->capture_begin())); @@ -422,7 +422,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { // which has 7 bytes of padding, as opposed to the naive solution // which might have less (?). if (endAlign < maxFieldAlign) { - llvm::SmallVectorImpl<BlockLayoutChunk>::iterator + SmallVectorImpl<BlockLayoutChunk>::iterator li = layout.begin() + 1, le = layout.end(); // Look for something that the header end is already @@ -433,7 +433,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { // If we found something that's naturally aligned for the end of // the header, keep adding things... if (li != le) { - llvm::SmallVectorImpl<BlockLayoutChunk>::iterator first = li; + SmallVectorImpl<BlockLayoutChunk>::iterator first = li; for (; li != le; ++li) { assert(endAlign >= li->Alignment); @@ -468,7 +468,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { // Slam everything else on now. This works because they have // strictly decreasing alignment and we expect that size is always a // multiple of alignment. - for (llvm::SmallVectorImpl<BlockLayoutChunk>::iterator + for (SmallVectorImpl<BlockLayoutChunk>::iterator li = layout.begin(), le = layout.end(); li != le; ++li) { assert(endAlign >= li->Alignment); li->setIndex(info, elementTypes.size()); @@ -507,7 +507,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { // Build the block descriptor. llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo); - const llvm::Type *intTy = ConvertType(getContext().IntTy); + llvm::Type *intTy = ConvertType(getContext().IntTy); llvm::AllocaInst *blockAddr = CreateTempAlloca(blockInfo.StructureType, "block"); @@ -617,10 +617,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, declRef, VK_RValue); EmitExprAsInit(&l2r, &blockFieldPseudoVar, - LValue::MakeAddr(blockField, type, - getContext().getDeclAlign(variable) - .getQuantity(), - getContext()), + MakeAddrLValue(blockField, type, + getContext().getDeclAlign(variable) + .getQuantity()), /*captured by init*/ false); } @@ -681,8 +680,8 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() { // const char *layout; // reserved // }; BlockDescriptorType = - llvm::StructType::createNamed("struct.__block_descriptor", - UnsignedLongTy, UnsignedLongTy, NULL); + llvm::StructType::create("struct.__block_descriptor", + UnsignedLongTy, UnsignedLongTy, NULL); // Now form a pointer to that. BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType); @@ -703,13 +702,9 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() { // struct __block_descriptor *__descriptor; // }; GenericBlockLiteralType = - llvm::StructType::createNamed("struct.__block_literal_generic", - VoidPtrTy, - IntTy, - IntTy, - VoidPtrTy, - BlockDescPtrTy, - NULL); + llvm::StructType::create("struct.__block_literal_generic", + VoidPtrTy, IntTy, IntTy, VoidPtrTy, + BlockDescPtrTy, NULL); return GenericBlockLiteralType; } @@ -723,7 +718,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, llvm::Value *Callee = EmitScalarExpr(E->getCallee()); // Get a pointer to the generic block literal. - const llvm::Type *BlockLiteralTy = + llvm::Type *BlockLiteralTy = llvm::PointerType::getUnqual(CGM.getGenericBlockLiteralType()); // Bitcast the callee to a block literal. @@ -731,9 +726,9 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal"); // Get the function pointer from the literal. - llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp"); + llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3); - BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy, "tmp"); + BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy); // Add the block literal. CallArgList Args; @@ -746,20 +741,16 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, E->arg_begin(), E->arg_end()); // Load the function. - llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); + llvm::Value *Func = Builder.CreateLoad(FuncPtr); const FunctionType *FuncTy = FnType->castAs<FunctionType>(); - QualType ResultType = FuncTy->getResultType(); - - const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, Args, - FuncTy->getExtInfo()); + const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FuncTy); // Cast the function pointer to the right type. - const llvm::Type *BlockFTy = + llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo, false); - const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); + llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); Func = Builder.CreateBitCast(Func, BlockFTyPtr); // And call the block. @@ -783,7 +774,7 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable, // to byref*. addr = Builder.CreateLoad(addr); - const llvm::PointerType *byrefPointerType + llvm::PointerType *byrefPointerType = llvm::PointerType::get(BuildByRefType(variable), 0); addr = Builder.CreateBitCast(addr, byrefPointerType, "byref.addr"); @@ -863,7 +854,7 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, literal->setAlignment(blockInfo.BlockAlign.getQuantity()); // Return a constant of the appropriately-casted type. - const llvm::Type *requiredType = + llvm::Type *requiredType = CGM.getTypes().ConvertType(blockInfo.getBlockExpr()->getType()); return llvm::ConstantExpr::getBitCast(literal, requiredType); } @@ -918,7 +909,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, if (CGM.ReturnTypeUsesSRet(fnInfo)) blockInfo.UsesStret = true; - const llvm::FunctionType *fnLLVMType = + llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic()); MangleBuffer name; @@ -1005,7 +996,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), ce = blockDecl->capture_end(); ci != ce; ++ci) { const VarDecl *variable = ci->getVariable(); - DI->setLocation(variable->getLocation()); + DI->EmitLocation(Builder, variable->getLocation()); const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { @@ -1065,7 +1056,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // FIXME: it would be nice if these were mergeable with things with // identical semantics. - const llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false); + llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, @@ -1088,7 +1079,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { true); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); - const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); + llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); llvm::Value *src = GetAddrOfLocalVar(&srcDecl); src = Builder.CreateLoad(src); @@ -1180,7 +1171,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { // FIXME: We'd like to put these into a mergable by content, with // internal linkage. - const llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false); + llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, @@ -1201,7 +1192,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { false, true); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); - const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); + llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); llvm::Value *src = GetAddrOfLocalVar(&srcDecl); src = Builder.CreateLoad(src); @@ -1399,7 +1390,7 @@ public: static llvm::Constant * generateByrefCopyHelper(CodeGenFunction &CGF, - const llvm::StructType &byrefType, + llvm::StructType &byrefType, CodeGenModule::ByrefHelpers &byrefInfo) { ASTContext &Context = CGF.getContext(); @@ -1416,7 +1407,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo()); CodeGenTypes &Types = CGF.CGM.getTypes(); - const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); + llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -1438,7 +1429,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); if (byrefInfo.needsCopy()) { - const llvm::Type *byrefPtrType = byrefType.getPointerTo(0); + llvm::Type *byrefPtrType = byrefType.getPointerTo(0); // dst->x llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst); @@ -1462,7 +1453,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, /// Build the copy helper for a __block variable. static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM, - const llvm::StructType &byrefType, + llvm::StructType &byrefType, CodeGenModule::ByrefHelpers &info) { CodeGenFunction CGF(CGM); return generateByrefCopyHelper(CGF, byrefType, info); @@ -1471,7 +1462,7 @@ static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM, /// Generate code for a __block variable's dispose helper. static llvm::Constant * generateByrefDisposeHelper(CodeGenFunction &CGF, - const llvm::StructType &byrefType, + llvm::StructType &byrefType, CodeGenModule::ByrefHelpers &byrefInfo) { ASTContext &Context = CGF.getContext(); QualType R = Context.VoidTy; @@ -1484,7 +1475,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo()); CodeGenTypes &Types = CGF.CGM.getTypes(); - const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); + llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -1521,7 +1512,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, /// Build the dispose helper for a __block variable. static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM, - const llvm::StructType &byrefType, + llvm::StructType &byrefType, CodeGenModule::ByrefHelpers &info) { CodeGenFunction CGF(CGM); return generateByrefDisposeHelper(CGF, byrefType, info); @@ -1529,7 +1520,7 @@ static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM, /// template <class T> static T *buildByrefHelpers(CodeGenModule &CGM, - const llvm::StructType &byrefTy, + llvm::StructType &byrefTy, T &byrefInfo) { // Increase the field's alignment to be at least pointer alignment, // since the layout of the byref struct will guarantee at least that. @@ -1553,7 +1544,7 @@ template <class T> static T *buildByrefHelpers(CodeGenModule &CGM, } CodeGenModule::ByrefHelpers * -CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType, +CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, const AutoVarEmission &emission) { const VarDecl &var = *emission.Variable; QualType type = var.getType(); @@ -1658,18 +1649,18 @@ llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, /// T x; /// } x /// -const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { - std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D]; +llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { + std::pair<llvm::Type *, unsigned> &Info = ByRefValueInfo[D]; if (Info.first) return Info.first; QualType Ty = D->getType(); - llvm::SmallVector<llvm::Type *, 8> types; + SmallVector<llvm::Type *, 8> types; llvm::StructType *ByRefType = - llvm::StructType::createNamed(getLLVMContext(), - "struct.__block_byref_" + D->getNameAsString()); + llvm::StructType::create(getLLVMContext(), + "struct.__block_byref_" + D->getNameAsString()); // void *__isa; types.push_back(Int8PtrTy); @@ -1742,7 +1733,7 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { llvm::Value *addr = emission.Address; // That's an alloca of the byref structure type. - const llvm::StructType *byrefType = cast<llvm::StructType>( + llvm::StructType *byrefType = cast<llvm::StructType>( cast<llvm::PointerType>(addr->getType())->getElementType()); // Build the byref helpers if necessary. This is null if we don't need any. @@ -1812,8 +1803,63 @@ namespace { /// to be done externally. void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) { // We don't enter this cleanup if we're in pure-GC mode. - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) + if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) return; EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address); } + +/// Adjust the declaration of something from the blocks API. +static void configureBlocksRuntimeObject(CodeGenModule &CGM, + llvm::Constant *C) { + if (!CGM.getLangOptions().BlocksRuntimeOptional) return; + + llvm::GlobalValue *GV = cast<llvm::GlobalValue>(C->stripPointerCasts()); + if (GV->isDeclaration() && + GV->getLinkage() == llvm::GlobalValue::ExternalLinkage) + GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); +} + +llvm::Constant *CodeGenModule::getBlockObjectDispose() { + if (BlockObjectDispose) + return BlockObjectDispose; + + llvm::Type *args[] = { Int8PtrTy, Int32Ty }; + llvm::FunctionType *fty + = llvm::FunctionType::get(VoidTy, args, false); + BlockObjectDispose = CreateRuntimeFunction(fty, "_Block_object_dispose"); + configureBlocksRuntimeObject(*this, BlockObjectDispose); + return BlockObjectDispose; +} + +llvm::Constant *CodeGenModule::getBlockObjectAssign() { + if (BlockObjectAssign) + return BlockObjectAssign; + + llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty }; + llvm::FunctionType *fty + = llvm::FunctionType::get(VoidTy, args, false); + BlockObjectAssign = CreateRuntimeFunction(fty, "_Block_object_assign"); + configureBlocksRuntimeObject(*this, BlockObjectAssign); + return BlockObjectAssign; +} + +llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { + if (NSConcreteGlobalBlock) + return NSConcreteGlobalBlock; + + NSConcreteGlobalBlock = GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock", + Int8PtrTy->getPointerTo(), 0); + configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock); + return NSConcreteGlobalBlock; +} + +llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { + if (NSConcreteStackBlock) + return NSConcreteStackBlock; + + NSConcreteStackBlock = GetOrCreateLLVMGlobal("_NSConcreteStackBlock", + Int8PtrTy->getPointerTo(), 0); + configureBlocksRuntimeObject(*this, NSConcreteStackBlock); + return NSConcreteStackBlock; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h index 4d8dead..6e71c1f 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h @@ -176,7 +176,7 @@ public: /// because it gets set later in the block-creation process. mutable bool UsesStret : 1; - const llvm::StructType *StructureType; + llvm::StructType *StructureType; const BlockExpr *Block; CharUnits BlockSize; CharUnits BlockAlign; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp index 1566bd9..ec0ca42 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -27,24 +27,34 @@ using namespace clang; using namespace CodeGen; using namespace llvm; -static void EmitMemoryBarrier(CodeGenFunction &CGF, - bool LoadLoad, bool LoadStore, - bool StoreLoad, bool StoreStore, - bool Device) { - Value *True = CGF.Builder.getTrue(); - Value *False = CGF.Builder.getFalse(); - Value *C[5] = { LoadLoad ? True : False, - LoadStore ? True : False, - StoreLoad ? True : False, - StoreStore ? True : False, - Device ? True : False }; - CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier), C); +/// getBuiltinLibFunction - Given a builtin id for a function like +/// "__builtin_fabsf", return a Function* for "fabsf". +llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, + unsigned BuiltinID) { + assert(Context.BuiltinInfo.isLibFunction(BuiltinID)); + + // Get the name, skip over the __builtin_ prefix (if necessary). + StringRef Name; + GlobalDecl D(FD); + + // If the builtin has been declared explicitly with an assembler label, + // use the mangled name. This differs from the plain label on platforms + // that prefix labels. + if (FD->hasAttr<AsmLabelAttr>()) + Name = getMangledName(D); + else + Name = Context.BuiltinInfo.GetName(BuiltinID) + 10; + + llvm::FunctionType *Ty = + cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); + + return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false); } /// Emit the conversions required to turn the given value into an /// integer of the given size. static Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V, - QualType T, const llvm::IntegerType *IntType) { + QualType T, llvm::IntegerType *IntType) { V = CGF.EmitToMemory(V, T); if (V->getType()->isPointerTy()) @@ -55,7 +65,7 @@ static Value *EmitToInt(CodeGenFunction &CGF, llvm::Value *V, } static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V, - QualType T, const llvm::Type *ResultType) { + QualType T, llvm::Type *ResultType) { V = CGF.EmitFromMemory(V, T); if (ResultType->isPointerTy()) @@ -65,25 +75,11 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V, return V; } -// The atomic builtins are also full memory barriers. This is a utility for -// wrapping a call to the builtins with memory barriers. -static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn, - ArrayRef<Value *> Args) { - // FIXME: We need a target hook for whether this applies to device memory or - // not. - bool Device = true; - - // Create barriers both before and after the call. - EmitMemoryBarrier(CGF, true, true, true, true, Device); - Value *Result = CGF.Builder.CreateCall(Fn, Args); - EmitMemoryBarrier(CGF, true, true, true, true, Device); - return Result; -} - /// Utility to insert an atomic instruction based on Instrinsic::ID /// and the expression node. static RValue EmitBinaryAtomic(CodeGenFunction &CGF, - Intrinsic::ID Id, const CallExpr *E) { + llvm::AtomicRMWInst::BinOp Kind, + const CallExpr *E) { QualType T = E->getType(); assert(E->getArg(0)->getType()->isPointerType()); assert(CGF.getContext().hasSameUnqualifiedType(T, @@ -99,16 +95,15 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, CGF.getContext().getTypeSize(T)); llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace); - llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType }; - llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes); - llvm::Value *Args[2]; Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType); Args[1] = CGF.EmitScalarExpr(E->getArg(1)); - const llvm::Type *ValueType = Args[1]->getType(); + llvm::Type *ValueType = Args[1]->getType(); Args[1] = EmitToInt(CGF, Args[1], T, IntType); - llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args); + llvm::Value *Result = + CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1], + llvm::SequentiallyConsistent); Result = EmitFromInt(CGF, Result, T, ValueType); return RValue::get(Result); } @@ -117,7 +112,8 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, /// the expression node, where the return value is the result of the /// operation. static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, - Intrinsic::ID Id, const CallExpr *E, + llvm::AtomicRMWInst::BinOp Kind, + const CallExpr *E, Instruction::BinaryOps Op) { QualType T = E->getType(); assert(E->getArg(0)->getType()->isPointerType()); @@ -134,16 +130,15 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, CGF.getContext().getTypeSize(T)); llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace); - llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType }; - llvm::Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes); - llvm::Value *Args[2]; Args[1] = CGF.EmitScalarExpr(E->getArg(1)); - const llvm::Type *ValueType = Args[1]->getType(); + llvm::Type *ValueType = Args[1]->getType(); Args[1] = EmitToInt(CGF, Args[1], T, IntType); Args[0] = CGF.Builder.CreateBitCast(DestPtr, IntPtrType); - llvm::Value *Result = EmitCallWithBarrier(CGF, AtomF, Args); + llvm::Value *Result = + CGF.Builder.CreateAtomicRMW(Kind, Args[0], Args[1], + llvm::SequentiallyConsistent); Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]); Result = EmitFromInt(CGF, Result, T, ValueType); return RValue::get(Result); @@ -157,21 +152,26 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) { StringRef FnName; switch (ValTyP->getKind()) { - default: assert(0 && "Isn't a scalar fp type!"); + default: llvm_unreachable("Isn't a scalar fp type!"); case BuiltinType::Float: FnName = "fabsf"; break; case BuiltinType::Double: FnName = "fabs"; break; case BuiltinType::LongDouble: FnName = "fabsl"; break; } // The prototype is something that takes and returns whatever V's type is. - llvm::Type *ArgTys[] = { V->getType() }; - llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), ArgTys, + llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(), false); llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName); return CGF.Builder.CreateCall(Fn, V, "abs"); } +static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn, + const CallExpr *E, llvm::Value *calleeValue) { + return CGF.EmitCall(E->getCallee()->getType(), calleeValue, + ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn); +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. @@ -195,7 +195,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_va_start: case Builtin::BI__builtin_va_end: { Value *ArgValue = EmitVAListRef(E->getArg(0)); - const llvm::Type *DestType = Int8PtrTy; + llvm::Type *DestType = Int8PtrTy; if (ArgValue->getType() != DestType) ArgValue = Builder.CreateBitCast(ArgValue, DestType, ArgValue->getName().data()); @@ -208,7 +208,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *DstPtr = EmitVAListRef(E->getArg(0)); Value *SrcPtr = EmitVAListRef(E->getArg(1)); - const llvm::Type *Type = Int8PtrTy; + llvm::Type *Type = Int8PtrTy; DstPtr = Builder.CreateBitCast(DstPtr, Type); SrcPtr = Builder.CreateBitCast(SrcPtr, Type); @@ -236,8 +236,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); + llvm::Type *ResultType = ConvertType(E->getType()); + Value *Result = Builder.CreateCall(F, ArgValue); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -251,8 +251,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); + llvm::Type *ResultType = ConvertType(E->getType()); + Value *Result = Builder.CreateCall(F, ArgValue); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -267,9 +267,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"), - llvm::ConstantInt::get(ArgType, 1), "tmp"); + llvm::Type *ResultType = ConvertType(E->getType()); + Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue), + llvm::ConstantInt::get(ArgType, 1)); Value *Zero = llvm::Constant::getNullValue(ArgType); Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero"); Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs"); @@ -287,10 +287,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType); - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp"); - Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1), - "tmp"); + llvm::Type *ResultType = ConvertType(E->getType()); + Value *Tmp = Builder.CreateCall(F, ArgValue); + Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1)); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -304,8 +303,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType); - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); + llvm::Type *ResultType = ConvertType(E->getType()); + Value *Result = Builder.CreateCall(F, ArgValue); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -327,7 +326,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *ArgValue = EmitScalarExpr(E->getArg(0)); llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::bswap, ArgType); - return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); + return RValue::get(Builder.CreateCall(F, ArgValue)); } case Builtin::BI__builtin_object_size: { // We pass this builtin onto the optimizer so that it can @@ -381,7 +380,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Exponent = EmitScalarExpr(E->getArg(1)); llvm::Type *ArgType = Base->getType(); Value *F = CGM.getIntrinsic(Intrinsic::powi, ArgType); - return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp")); + return RValue::get(Builder.CreateCall2(F, Base, Exponent)); } case Builtin::BI__builtin_isgreater: @@ -396,7 +395,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *RHS = EmitScalarExpr(E->getArg(1)); switch (BuiltinID) { - default: assert(0 && "Unknown ordered comparison"); + default: llvm_unreachable("Unknown ordered comparison"); case Builtin::BI__builtin_isgreater: LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp"); break; @@ -417,13 +416,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, break; } // ZExt bool to int type. - return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()), - "tmp")); + return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()))); } case Builtin::BI__builtin_isnan: { Value *V = EmitScalarExpr(E->getArg(0)); V = Builder.CreateFCmpUNO(V, V, "cmp"); - return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp")); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } case Builtin::BI__builtin_isinf: { @@ -432,7 +430,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, V = EmitFAbs(*this, V, E->getArg(0)->getType()); V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf"); - return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp")); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } // TODO: BI__builtin_isinf_sign @@ -457,7 +455,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_isfinite: { - // isfinite(x) --> x == x && fabs(x) != infinity; } + // isfinite(x) --> x == x && fabs(x) != infinity; Value *V = EmitScalarExpr(E->getArg(0)); Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq"); @@ -471,7 +469,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_fpclassify: { Value *V = EmitScalarExpr(E->getArg(5)); - const llvm::Type *Ty = ConvertType(E->getArg(5)->getType()); + llvm::Type *Ty = ConvertType(E->getArg(5)->getType()); // Create Result BasicBlock *Begin = Builder.GetInsertBlock(); @@ -530,7 +528,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BIalloca: case Builtin::BI__builtin_alloca: { Value *Size = EmitScalarExpr(E->getArg(0)); - return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size, "tmp")); + return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size)); } case Builtin::BIbzero: case Builtin::BI__builtin_bzero: { @@ -550,11 +548,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin___memcpy_chk: { // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. - if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || - !E->getArg(3)->isEvaluatable(CGM.getContext())) + llvm::APSInt Size, DstSize; + if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) || + !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext())) break; - llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); - llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); if (Size.ugt(DstSize)) break; Value *Dest = EmitScalarExpr(E->getArg(0)); @@ -575,11 +572,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin___memmove_chk: { // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. - if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || - !E->getArg(3)->isEvaluatable(CGM.getContext())) + llvm::APSInt Size, DstSize; + if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) || + !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext())) break; - llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); - llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); if (Size.ugt(DstSize)) break; Value *Dest = EmitScalarExpr(E->getArg(0)); @@ -608,11 +604,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin___memset_chk: { // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. - if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || - !E->getArg(3)->isEvaluatable(CGM.getContext())) + llvm::APSInt Size, DstSize; + if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) || + !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext())) break; - llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); - llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); if (Size.ugt(DstSize)) break; Value *Address = EmitScalarExpr(E->getArg(0)); @@ -640,13 +635,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_return_address: { Value *Depth = EmitScalarExpr(E->getArg(0)); - Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp"); + Depth = Builder.CreateIntCast(Depth, Int32Ty, false); Value *F = CGM.getIntrinsic(Intrinsic::returnaddress); return RValue::get(Builder.CreateCall(F, Depth)); } case Builtin::BI__builtin_frame_address: { Value *Depth = EmitScalarExpr(E->getArg(0)); - Depth = Builder.CreateIntCast(Depth, Int32Ty, false, "tmp"); + Depth = Builder.CreateIntCast(Depth, Int32Ty, false); Value *F = CGM.getIntrinsic(Intrinsic::frameaddress); return RValue::get(Builder.CreateCall(F, Depth)); } @@ -661,7 +656,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } case Builtin::BI__builtin_dwarf_sp_column: { - const llvm::IntegerType *Ty + llvm::IntegerType *Ty = cast<llvm::IntegerType>(ConvertType(E->getType())); int Column = getTargetHooks().getDwarfEHStackPointer(CGM); if (Column == -1) { @@ -680,7 +675,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Int = EmitScalarExpr(E->getArg(0)); Value *Ptr = EmitScalarExpr(E->getArg(1)); - const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType()); + llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType()); assert((IntTy->getBitWidth() == 32 || IntTy->getBitWidth() == 64) && "LLVM's __builtin_eh_return only supports 32- and 64-bit variants"); Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32 @@ -775,82 +770,82 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_release: case Builtin::BI__sync_swap: - assert(0 && "Shouldn't make it through sema"); + llvm_unreachable("Shouldn't make it through sema"); case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: case Builtin::BI__sync_fetch_and_add_4: case Builtin::BI__sync_fetch_and_add_8: case Builtin::BI__sync_fetch_and_add_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_add, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Add, E); case Builtin::BI__sync_fetch_and_sub_1: case Builtin::BI__sync_fetch_and_sub_2: case Builtin::BI__sync_fetch_and_sub_4: case Builtin::BI__sync_fetch_and_sub_8: case Builtin::BI__sync_fetch_and_sub_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_sub, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Sub, E); case Builtin::BI__sync_fetch_and_or_1: case Builtin::BI__sync_fetch_and_or_2: case Builtin::BI__sync_fetch_and_or_4: case Builtin::BI__sync_fetch_and_or_8: case Builtin::BI__sync_fetch_and_or_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_or, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Or, E); case Builtin::BI__sync_fetch_and_and_1: case Builtin::BI__sync_fetch_and_and_2: case Builtin::BI__sync_fetch_and_and_4: case Builtin::BI__sync_fetch_and_and_8: case Builtin::BI__sync_fetch_and_and_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_and, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::And, E); case Builtin::BI__sync_fetch_and_xor_1: case Builtin::BI__sync_fetch_and_xor_2: case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xor, E); // Clang extensions: not overloaded yet. case Builtin::BI__sync_fetch_and_min: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Min, E); case Builtin::BI__sync_fetch_and_max: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_max, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Max, E); case Builtin::BI__sync_fetch_and_umin: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umin, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMin, E); case Builtin::BI__sync_fetch_and_umax: - return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umax, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::UMax, E); case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E, + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Add, E, llvm::Instruction::Add); case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_sub, E, + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Sub, E, llvm::Instruction::Sub); case Builtin::BI__sync_and_and_fetch_1: case Builtin::BI__sync_and_and_fetch_2: case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_and, E, + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::And, E, llvm::Instruction::And); case Builtin::BI__sync_or_and_fetch_1: case Builtin::BI__sync_or_and_fetch_2: case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_or, E, + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Or, E, llvm::Instruction::Or); case Builtin::BI__sync_xor_and_fetch_1: case Builtin::BI__sync_xor_and_fetch_2: case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E, + return EmitBinaryAtomicPost(*this, llvm::AtomicRMWInst::Xor, E, llvm::Instruction::Xor); case Builtin::BI__sync_val_compare_and_swap_1: @@ -867,18 +862,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::IntegerType::get(getLLVMContext(), getContext().getTypeSize(T)); llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace); - llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType }; - Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, - IntrinsicTypes); Value *Args[3]; Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType); Args[1] = EmitScalarExpr(E->getArg(1)); - const llvm::Type *ValueType = Args[1]->getType(); + llvm::Type *ValueType = Args[1]->getType(); Args[1] = EmitToInt(*this, Args[1], T, IntType); Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType); - Value *Result = EmitCallWithBarrier(*this, AtomF, Args); + Value *Result = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2], + llvm::SequentiallyConsistent); Result = EmitFromInt(*this, Result, T, ValueType); return RValue::get(Result); } @@ -897,9 +890,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::IntegerType::get(getLLVMContext(), getContext().getTypeSize(T)); llvm::Type *IntPtrType = IntType->getPointerTo(AddrSpace); - llvm::Type *IntrinsicTypes[2] = { IntType, IntPtrType }; - Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, - IntrinsicTypes); Value *Args[3]; Args[0] = Builder.CreateBitCast(DestPtr, IntPtrType); @@ -907,7 +897,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType); Value *OldVal = Args[1]; - Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args); + Value *PrevVal = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2], + llvm::SequentiallyConsistent); Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal); // zext bool to int. Result = Builder.CreateZExt(Result, ConvertType(E->getType())); @@ -919,14 +910,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E); case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: - return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); + return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E); case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: @@ -934,32 +925,95 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_lock_release_8: case Builtin::BI__sync_lock_release_16: { Value *Ptr = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ElTy = + llvm::Type *ElLLVMTy = cast<llvm::PointerType>(Ptr->getType())->getElementType(); llvm::StoreInst *Store = - Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr); - Store->setVolatile(true); + Builder.CreateStore(llvm::Constant::getNullValue(ElLLVMTy), Ptr); + QualType ElTy = E->getArg(0)->getType()->getPointeeType(); + CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy); + Store->setAlignment(StoreSize.getQuantity()); + Store->setAtomic(llvm::Release); return RValue::get(0); } case Builtin::BI__sync_synchronize: { - // We assume like gcc appears to, that this only applies to cached memory. - EmitMemoryBarrier(*this, true, true, true, true, false); + // We assume this is supposed to correspond to a C++0x-style + // sequentially-consistent fence (i.e. this is only usable for + // synchonization, not device I/O or anything like that). This intrinsic + // is really badly designed in the sense that in theory, there isn't + // any way to safely use it... but in practice, it mostly works + // to use it with non-atomic loads and stores to get acquire/release + // semantics. + Builder.CreateFence(llvm::SequentiallyConsistent); return RValue::get(0); } - case Builtin::BI__builtin_llvm_memory_barrier: { - Value *C[5] = { - EmitScalarExpr(E->getArg(0)), - EmitScalarExpr(E->getArg(1)), - EmitScalarExpr(E->getArg(2)), - EmitScalarExpr(E->getArg(3)), - EmitScalarExpr(E->getArg(4)) - }; - Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C); + case Builtin::BI__atomic_thread_fence: + case Builtin::BI__atomic_signal_fence: { + llvm::SynchronizationScope Scope; + if (BuiltinID == Builtin::BI__atomic_signal_fence) + Scope = llvm::SingleThread; + else + Scope = llvm::CrossThread; + Value *Order = EmitScalarExpr(E->getArg(0)); + if (isa<llvm::ConstantInt>(Order)) { + int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + switch (ord) { + case 0: // memory_order_relaxed + default: // invalid order + break; + case 1: // memory_order_consume + case 2: // memory_order_acquire + Builder.CreateFence(llvm::Acquire, Scope); + break; + case 3: // memory_order_release + Builder.CreateFence(llvm::Release, Scope); + break; + case 4: // memory_order_acq_rel + Builder.CreateFence(llvm::AcquireRelease, Scope); + break; + case 5: // memory_order_seq_cst + Builder.CreateFence(llvm::SequentiallyConsistent, Scope); + break; + } + return RValue::get(0); + } + + llvm::BasicBlock *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB; + AcquireBB = createBasicBlock("acquire", CurFn); + ReleaseBB = createBasicBlock("release", CurFn); + AcqRelBB = createBasicBlock("acqrel", CurFn); + SeqCstBB = createBasicBlock("seqcst", CurFn); + llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn); + + Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); + llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB); + + Builder.SetInsertPoint(AcquireBB); + Builder.CreateFence(llvm::Acquire, Scope); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(1), AcquireBB); + SI->addCase(Builder.getInt32(2), AcquireBB); + + Builder.SetInsertPoint(ReleaseBB); + Builder.CreateFence(llvm::Release, Scope); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(3), ReleaseBB); + + Builder.SetInsertPoint(AcqRelBB); + Builder.CreateFence(llvm::AcquireRelease, Scope); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(4), AcqRelBB); + + Builder.SetInsertPoint(SeqCstBB); + Builder.CreateFence(llvm::SequentiallyConsistent, Scope); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(5), SeqCstBB); + + Builder.SetInsertPoint(ContBB); return RValue::get(0); } - + // Library functions with special handling. case Builtin::BIsqrt: case Builtin::BIsqrtf: @@ -982,7 +1036,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Exponent = EmitScalarExpr(E->getArg(1)); llvm::Type *ArgType = Base->getType(); Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType); - return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp")); + return RValue::get(Builder.CreateCall2(F, Base, Exponent)); } case Builtin::BIfma: @@ -997,8 +1051,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::fma, ArgType); return RValue::get(Builder.CreateCall3(F, FirstArg, EmitScalarExpr(E->getArg(1)), - EmitScalarExpr(E->getArg(2)), - "tmp")); + EmitScalarExpr(E->getArg(2)))); } case Builtin::BI__builtin_signbit: @@ -1007,25 +1060,40 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, LLVMContext &C = CGM.getLLVMContext(); Value *Arg = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ArgTy = Arg->getType(); + llvm::Type *ArgTy = Arg->getType(); if (ArgTy->isPPC_FP128Ty()) break; // FIXME: I'm not sure what the right implementation is here. int ArgWidth = ArgTy->getPrimitiveSizeInBits(); - const llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth); + llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth); Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy); Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy); Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp); return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType()))); } + case Builtin::BI__builtin_annotation: { + llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0)); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::annotation, + AnnVal->getType()); + + // Get the annotation string, go through casts. Sema requires this to be a + // non-wide string literal, potentially casted, so the cast<> is safe. + const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts(); + llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString(); + return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc())); + } } - // If this is an alias for a libm function (e.g. __builtin_sin) turn it into - // that function. - if (getContext().BuiltinInfo.isLibFunction(BuiltinID) || - getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return EmitCall(E->getCallee()->getType(), - CGM.getBuiltinLibFunction(FD, BuiltinID), - ReturnValueSlot(), E->arg_begin(), E->arg_end(), FD); + // If this is an alias for a lib function (e.g. __builtin_sin), emit + // the call using the normal call path, but using the unmangled + // version of the function name. + if (getContext().BuiltinInfo.isLibFunction(BuiltinID)) + return emitLibraryCall(*this, FD, E, + CGM.getBuiltinLibFunction(FD, BuiltinID)); + + // If this is a predefined lib function (e.g. malloc), emit the call + // using exactly the normal call path. + if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + return emitLibraryCall(*this, FD, E, EmitScalarExpr(E->getCallee())); // See if we have a target specific intrinsic. const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); @@ -1045,7 +1113,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, assert(Error == ASTContext::GE_None && "Should not codegen an error"); Function *F = CGM.getIntrinsic(IntrinsicID); - const llvm::FunctionType *FTy = F->getFunctionType(); + llvm::FunctionType *FTy = F->getFunctionType(); for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { Value *ArgValue; @@ -1064,7 +1132,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // If the intrinsic arg type is different from the builtin arg type // we need to do a bit cast. - const llvm::Type *PTy = FTy->getParamType(i); + llvm::Type *PTy = FTy->getParamType(i); if (PTy != ArgValue->getType()) { assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) && "Must be able to losslessly bit cast to param"); @@ -1077,7 +1145,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *V = Builder.CreateCall(F, Args); QualType BuiltinRetType = E->getType(); - const llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext()); + llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext()); if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType); if (RetTy != V->getType()) { @@ -1154,12 +1222,12 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops, return Builder.CreateCall(F, Ops, name); } -Value *CodeGenFunction::EmitNeonShiftVector(Value *V, const llvm::Type *Ty, +Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty, bool neg) { ConstantInt *CI = cast<ConstantInt>(V); int SV = CI->getSExtValue(); - const llvm::VectorType *VTy = cast<llvm::VectorType>(Ty); + llvm::VectorType *VTy = cast<llvm::VectorType>(Ty); llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV); SmallVector<llvm::Constant*, 16> CV(VTy->getNumElements(), C); return llvm::ConstantVector::get(CV); @@ -1193,12 +1261,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const FunctionDecl *FD = E->getDirectCallee(); // Oddly people write this call without args on occasion and gcc accepts // it - it's also marked as varargs in the description file. - llvm::SmallVector<Value*, 2> Ops; + SmallVector<Value*, 2> Ops; for (unsigned i = 0; i < E->getNumArgs(); i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); - const llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); - const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); - llvm::StringRef Name = FD->getName(); + llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); + llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); + StringRef Name = FD->getName(); return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), Ops); } @@ -1223,7 +1291,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL); Value *One = llvm::ConstantInt::get(Int32Ty, 1); - Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp"); + Value *Tmp = Builder.CreateAlloca(Int64Ty, One); Value *Val = EmitScalarExpr(E->getArg(0)); Builder.CreateStore(Val, Tmp); @@ -1236,10 +1304,41 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd"); } - llvm::SmallVector<Value*, 4> Ops; + SmallVector<Value*, 4> Ops; for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); + // vget_lane and vset_lane are not overloaded and do not have an extra + // argument that specifies the vector type. + switch (BuiltinID) { + default: break; + case ARM::BI__builtin_neon_vget_lane_i8: + case ARM::BI__builtin_neon_vget_lane_i16: + case ARM::BI__builtin_neon_vget_lane_i32: + case ARM::BI__builtin_neon_vget_lane_i64: + case ARM::BI__builtin_neon_vget_lane_f32: + case ARM::BI__builtin_neon_vgetq_lane_i8: + case ARM::BI__builtin_neon_vgetq_lane_i16: + case ARM::BI__builtin_neon_vgetq_lane_i32: + case ARM::BI__builtin_neon_vgetq_lane_i64: + case ARM::BI__builtin_neon_vgetq_lane_f32: + return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)), + "vget_lane"); + case ARM::BI__builtin_neon_vset_lane_i8: + case ARM::BI__builtin_neon_vset_lane_i16: + case ARM::BI__builtin_neon_vset_lane_i32: + case ARM::BI__builtin_neon_vset_lane_i64: + case ARM::BI__builtin_neon_vset_lane_f32: + case ARM::BI__builtin_neon_vsetq_lane_i8: + case ARM::BI__builtin_neon_vsetq_lane_i16: + case ARM::BI__builtin_neon_vsetq_lane_i32: + case ARM::BI__builtin_neon_vsetq_lane_i64: + case ARM::BI__builtin_neon_vsetq_lane_f32: + Ops.push_back(EmitScalarExpr(E->getArg(2))); + return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane"); + } + + // Get the last argument, which specifies the vector type. llvm::APSInt Result; const Expr *Arg = E->getArg(E->getNumArgs()-1); if (!Arg->isIntegerConstantExpr(Result, getContext())) @@ -1382,18 +1481,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Value *SV = llvm::ConstantVector::get(Indices); return Builder.CreateShuffleVector(Ops[0], Ops[1], SV, "vext"); } - case ARM::BI__builtin_neon_vget_lane_i8: - case ARM::BI__builtin_neon_vget_lane_i16: - case ARM::BI__builtin_neon_vget_lane_i32: - case ARM::BI__builtin_neon_vget_lane_i64: - case ARM::BI__builtin_neon_vget_lane_f32: - case ARM::BI__builtin_neon_vgetq_lane_i8: - case ARM::BI__builtin_neon_vgetq_lane_i16: - case ARM::BI__builtin_neon_vgetq_lane_i32: - case ARM::BI__builtin_neon_vgetq_lane_i64: - case ARM::BI__builtin_neon_vgetq_lane_f32: - return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)), - "vget_lane"); case ARM::BI__builtin_neon_vhadd_v: case ARM::BI__builtin_neon_vhaddq_v: Int = usgn ? Intrinsic::arm_neon_vhaddu : Intrinsic::arm_neon_vhadds; @@ -1457,9 +1544,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); - Ops[1] = Builder.CreateCall(F, - ArrayRef<Value *>(Ops.begin() + 1, Ops.end()), - "vld2_lane"); + Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1471,9 +1556,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops[4] = Builder.CreateBitCast(Ops[4], Ty); Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); - Ops[1] = Builder.CreateCall(F, - ArrayRef<Value *>(Ops.begin() + 1, Ops.end()), - "vld3_lane"); + Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1486,9 +1569,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[4] = Builder.CreateBitCast(Ops[4], Ty); Ops[5] = Builder.CreateBitCast(Ops[5], Ty); Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); - Ops[1] = Builder.CreateCall(F, - ArrayRef<Value *>(Ops.begin() + 1, Ops.end()), - "vld3_lane"); + Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1508,7 +1589,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld4_dup_v: Int = Intrinsic::arm_neon_vld2; break; - default: assert(0 && "unknown vld_dup intrinsic?"); + default: llvm_unreachable("unknown vld_dup intrinsic?"); } Function *F = CGM.getIntrinsic(Int, Ty); Value *Align = GetPointeeAlignment(*this, E->getArg(1)); @@ -1527,10 +1608,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld4_dup_v: Int = Intrinsic::arm_neon_vld2lane; break; - default: assert(0 && "unknown vld_dup intrinsic?"); + default: llvm_unreachable("unknown vld_dup intrinsic?"); } Function *F = CGM.getIntrinsic(Int, Ty); - const llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType()); + llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType()); SmallVector<Value*, 6> Args; Args.push_back(Ops[1]); @@ -1562,14 +1643,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Int = usgn ? Intrinsic::arm_neon_vminu : Intrinsic::arm_neon_vmins; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmin"); case ARM::BI__builtin_neon_vmovl_v: { - const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); Ops[0] = Builder.CreateBitCast(Ops[0], DTy); if (usgn) return Builder.CreateZExt(Ops[0], Ty, "vmovl"); return Builder.CreateSExt(Ops[0], Ty, "vmovl"); } case ARM::BI__builtin_neon_vmovn_v: { - const llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy); + llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy); Ops[0] = Builder.CreateBitCast(Ops[0], QTy); return Builder.CreateTrunc(Ops[0], Ty, "vmovn"); } @@ -1587,7 +1668,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals; // The source operand type has twice as many elements of half the size. unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); - const llvm::Type *EltTy = + llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2); llvm::Type *NarrowTy = llvm::VectorType::get(EltTy, VTy->getNumElements() * 2); @@ -1602,7 +1683,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Int = usgn ? Intrinsic::arm_neon_vpaddlu : Intrinsic::arm_neon_vpaddls; // The source operand type has twice as many elements of half the size. unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); - const llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2); + llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2); llvm::Type *NarrowTy = llvm::VectorType::get(EltTy, VTy->getNumElements() * 2); llvm::Type *Tys[2] = { Ty, NarrowTy }; @@ -1729,18 +1810,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vrsubhn_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty), Ops, "vrsubhn"); - case ARM::BI__builtin_neon_vset_lane_i8: - case ARM::BI__builtin_neon_vset_lane_i16: - case ARM::BI__builtin_neon_vset_lane_i32: - case ARM::BI__builtin_neon_vset_lane_i64: - case ARM::BI__builtin_neon_vset_lane_f32: - case ARM::BI__builtin_neon_vsetq_lane_i8: - case ARM::BI__builtin_neon_vsetq_lane_i16: - case ARM::BI__builtin_neon_vsetq_lane_i32: - case ARM::BI__builtin_neon_vsetq_lane_i64: - case ARM::BI__builtin_neon_vsetq_lane_f32: - Ops.push_back(EmitScalarExpr(E->getArg(2))); - return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane"); case ARM::BI__builtin_neon_vshl_v: case ARM::BI__builtin_neon_vshlq_v: Int = usgn ? Intrinsic::arm_neon_vshiftu : Intrinsic::arm_neon_vshifts; @@ -1921,7 +1990,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, } llvm::Value *CodeGenFunction:: -BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops) { +BuildVector(const SmallVectorImpl<llvm::Value*> &Ops) { assert((Ops.size() & (Ops.size() - 1)) == 0 && "Not a power-of-two sized vector!"); bool AllConstants = true; @@ -1949,7 +2018,7 @@ BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops) { Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - llvm::SmallVector<Value*, 4> Ops; + SmallVector<Value*, 4> Ops; // Find out if any arguments are required to be integer constant expressions. unsigned ICEArguments = 0; @@ -1983,7 +2052,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_psrlqi128: case X86::BI__builtin_ia32_psrlwi128: { Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext"); - const llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2); + llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2); llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0); Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty), Ops[1], Zero, "insert"); @@ -1992,7 +2061,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Intrinsic::ID ID = Intrinsic::not_intrinsic; switch (BuiltinID) { - default: assert(0 && "Unsupported shift intrinsic!"); + default: llvm_unreachable("Unsupported shift intrinsic!"); case X86::BI__builtin_ia32_pslldi128: name = "pslldi"; ID = Intrinsic::x86_sse2_psll_d; @@ -2046,13 +2115,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_psrlqi: case X86::BI__builtin_ia32_psrlwi: { Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext"); - const llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 1); + llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 1); Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast"); const char *name = 0; Intrinsic::ID ID = Intrinsic::not_intrinsic; switch (BuiltinID) { - default: assert(0 && "Unsupported shift intrinsic!"); + default: llvm_unreachable("Unsupported shift intrinsic!"); case X86::BI__builtin_ia32_pslldi: name = "pslldi"; ID = Intrinsic::x86_mmx_psll_d; @@ -2098,19 +2167,19 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, Ops, "cmpss"); } case X86::BI__builtin_ia32_ldmxcsr: { - const llvm::Type *PtrTy = Int8PtrTy; + llvm::Type *PtrTy = Int8PtrTy; Value *One = llvm::ConstantInt::get(Int32Ty, 1); - Value *Tmp = Builder.CreateAlloca(Int32Ty, One, "tmp"); + Value *Tmp = Builder.CreateAlloca(Int32Ty, One); Builder.CreateStore(Ops[0], Tmp); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr), Builder.CreateBitCast(Tmp, PtrTy)); } case X86::BI__builtin_ia32_stmxcsr: { - const llvm::Type *PtrTy = Int8PtrTy; + llvm::Type *PtrTy = Int8PtrTy; Value *One = llvm::ConstantInt::get(Int32Ty, 1); - Value *Tmp = Builder.CreateAlloca(Int32Ty, One, "tmp"); - One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr), - Builder.CreateBitCast(Tmp, PtrTy)); + Value *Tmp = Builder.CreateAlloca(Int32Ty, One); + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr), + Builder.CreateBitCast(Tmp, PtrTy)); return Builder.CreateLoad(Tmp, "stmxcsr"); } case X86::BI__builtin_ia32_cmppd: { @@ -2144,7 +2213,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // If palignr is shifting the pair of input vectors less than 9 bytes, // emit a shuffle instruction. if (shiftVal <= 8) { - llvm::SmallVector<llvm::Constant*, 8> Indices; + SmallVector<llvm::Constant*, 8> Indices; for (unsigned i = 0; i != 8; ++i) Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i)); @@ -2156,17 +2225,17 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // than 16 bytes, emit a logical right shift of the destination. if (shiftVal < 16) { // MMX has these as 1 x i64 vectors for some odd optimization reasons. - const llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1); + llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1); Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8); // create i32 constant llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q); - return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr"); + return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr"); } - // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + // If palignr is shifting the pair of vectors more than 16 bytes, emit zero. return llvm::Constant::getNullValue(ConvertType(E->getType())); } case X86::BI__builtin_ia32_palignr128: { @@ -2175,7 +2244,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // If palignr is shifting the pair of input vectors less than 17 bytes, // emit a shuffle instruction. if (shiftVal <= 16) { - llvm::SmallVector<llvm::Constant*, 16> Indices; + SmallVector<llvm::Constant*, 16> Indices; for (unsigned i = 0; i != 16; ++i) Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i)); @@ -2186,14 +2255,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // If palignr is shifting the pair of input vectors more than 16 but less // than 32 bytes, emit a logical right shift of the destination. if (shiftVal < 32) { - const llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2); + llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2); Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8); // create i32 constant llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq); - return Builder.CreateCall(F, ArrayRef<Value *>(&Ops[0], 2), "palignr"); + return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr"); } // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. @@ -2352,7 +2421,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - llvm::SmallVector<Value*, 4> Ops; + SmallVector<Value*, 4> Ops; for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); @@ -2373,11 +2442,11 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, { Ops[1] = Builder.CreateBitCast(Ops[1], Int8PtrTy); - Ops[0] = Builder.CreateGEP(Ops[1], Ops[0], "tmp"); + Ops[0] = Builder.CreateGEP(Ops[1], Ops[0]); Ops.pop_back(); switch (BuiltinID) { - default: assert(0 && "Unsupported ld/lvsl/lvsr intrinsic!"); + default: llvm_unreachable("Unsupported ld/lvsl/lvsr intrinsic!"); case PPC::BI__builtin_altivec_lvx: ID = Intrinsic::ppc_altivec_lvx; break; @@ -2412,11 +2481,11 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, case PPC::BI__builtin_altivec_stvewx: { Ops[2] = Builder.CreateBitCast(Ops[2], Int8PtrTy); - Ops[1] = Builder.CreateGEP(Ops[2], Ops[1], "tmp"); + Ops[1] = Builder.CreateGEP(Ops[2], Ops[1]); Ops.pop_back(); switch (BuiltinID) { - default: assert(0 && "Unsupported st intrinsic!"); + default: llvm_unreachable("Unsupported st intrinsic!"); case PPC::BI__builtin_altivec_stvx: ID = Intrinsic::ppc_altivec_stvx; break; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp new file mode 100644 index 0000000..88a0bdc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp @@ -0,0 +1,126 @@ +//===----- CGCUDANV.cpp - Interface to NVIDIA CUDA Runtime ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides a class for CUDA code generation targeting the NVIDIA CUDA +// runtime library. +// +//===----------------------------------------------------------------------===// + +#include "CGCUDARuntime.h" +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/Decl.h" +#include "llvm/BasicBlock.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Support/CallSite.h" + +#include <vector> + +using namespace clang; +using namespace CodeGen; + +namespace { + +class CGNVCUDARuntime : public CGCUDARuntime { + +private: + llvm::Type *IntTy, *SizeTy; + llvm::PointerType *CharPtrTy, *VoidPtrTy; + + llvm::Constant *getSetupArgumentFn() const; + llvm::Constant *getLaunchFn() const; + +public: + CGNVCUDARuntime(CodeGenModule &CGM); + + void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args); +}; + +} + +CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) : CGCUDARuntime(CGM) { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); + + IntTy = Types.ConvertType(Ctx.IntTy); + SizeTy = Types.ConvertType(Ctx.getSizeType()); + + CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy)); + VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy)); +} + +llvm::Constant *CGNVCUDARuntime::getSetupArgumentFn() const { + // cudaError_t cudaSetupArgument(void *, size_t, size_t) + std::vector<llvm::Type*> Params; + Params.push_back(VoidPtrTy); + Params.push_back(SizeTy); + Params.push_back(SizeTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, + Params, false), + "cudaSetupArgument"); +} + +llvm::Constant *CGNVCUDARuntime::getLaunchFn() const { + // cudaError_t cudaLaunch(char *) + std::vector<llvm::Type*> Params; + Params.push_back(CharPtrTy); + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(IntTy, + Params, false), + "cudaLaunch"); +} + +void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF, + FunctionArgList &Args) { + // Build the argument value list and the argument stack struct type. + llvm::SmallVector<llvm::Value *, 16> ArgValues; + std::vector<llvm::Type *> ArgTypes; + for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { + llvm::Value *V = CGF.GetAddrOfLocalVar(*I); + ArgValues.push_back(V); + assert(isa<llvm::PointerType>(V->getType()) && "Arg type not PointerType"); + ArgTypes.push_back(cast<llvm::PointerType>(V->getType())->getElementType()); + } + llvm::StructType *ArgStackTy = llvm::StructType::get( + CGF.getLLVMContext(), ArgTypes); + + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end"); + + // Emit the calls to cudaSetupArgument + llvm::Constant *cudaSetupArgFn = getSetupArgumentFn(); + for (unsigned I = 0, E = Args.size(); I != E; ++I) { + llvm::Value *Args[3]; + llvm::BasicBlock *NextBlock = CGF.createBasicBlock("setup.next"); + Args[0] = CGF.Builder.CreatePointerCast(ArgValues[I], VoidPtrTy); + Args[1] = CGF.Builder.CreateIntCast( + llvm::ConstantExpr::getSizeOf(ArgTypes[I]), + SizeTy, false); + Args[2] = CGF.Builder.CreateIntCast( + llvm::ConstantExpr::getOffsetOf(ArgStackTy, I), + SizeTy, false); + llvm::CallSite CS = CGF.EmitCallOrInvoke(cudaSetupArgFn, Args); + llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0); + llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero); + CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock); + CGF.EmitBlock(NextBlock); + } + + // Emit the call to cudaLaunch + llvm::Constant *cudaLaunchFn = getLaunchFn(); + llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy); + CGF.EmitCallOrInvoke(cudaLaunchFn, Arg); + CGF.EmitBranch(EndBlock); + + CGF.EmitBlock(EndBlock); +} + +CGCUDARuntime *CodeGen::CreateNVCUDARuntime(CodeGenModule &CGM) { + return new CGNVCUDARuntime(CGM); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp new file mode 100644 index 0000000..77dc248 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.cpp @@ -0,0 +1,55 @@ +//===----- CGCUDARuntime.cpp - Interface to CUDA Runtimes -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for CUDA code generation. Concrete +// subclasses of this implement code generation for specific CUDA +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#include "CGCUDARuntime.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "CGCall.h" +#include "CodeGenFunction.h" + +using namespace clang; +using namespace CodeGen; + +CGCUDARuntime::~CGCUDARuntime() {} + +RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF, + const CUDAKernelCallExpr *E, + ReturnValueSlot ReturnValue) { + llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end"); + + CodeGenFunction::ConditionalEvaluation eval(CGF); + CGF.EmitBranchOnBoolExpr(E->getConfig(), ContBlock, ConfigOKBlock); + + eval.begin(CGF); + CGF.EmitBlock(ConfigOKBlock); + + const Decl *TargetDecl = 0; + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) { + TargetDecl = DRE->getDecl(); + } + } + + llvm::Value *Callee = CGF.EmitScalarExpr(E->getCallee()); + CGF.EmitCall(E->getCallee()->getType(), Callee, ReturnValue, + E->arg_begin(), E->arg_end(), TargetDecl); + CGF.EmitBranch(ContBlock); + + CGF.EmitBlock(ContBlock); + eval.end(CGF); + + return RValue::get(0); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h new file mode 100644 index 0000000..a99a67a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDARuntime.h @@ -0,0 +1,54 @@ +//===----- CGCUDARuntime.h - Interface to CUDA Runtimes ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for CUDA code generation. Concrete +// subclasses of this implement code generation for specific CUDA +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CUDARUNTIME_H +#define CLANG_CODEGEN_CUDARUNTIME_H + +namespace clang { + +class CUDAKernelCallExpr; + +namespace CodeGen { + +class CodeGenFunction; +class CodeGenModule; +class FunctionArgList; +class ReturnValueSlot; +class RValue; + +class CGCUDARuntime { +protected: + CodeGenModule &CGM; + +public: + CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {} + virtual ~CGCUDARuntime(); + + virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF, + const CUDAKernelCallExpr *E, + ReturnValueSlot ReturnValue); + + virtual void EmitDeviceStubBody(CodeGenFunction &CGF, + FunctionArgList &Args) = 0; + +}; + +/// Creates an instance of a CUDA runtime class. +CGCUDARuntime *CreateNVCUDARuntime(CodeGenModule &CGM); + +} +} + +#endif diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp index f6fc202..b5e6e0d 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp @@ -138,7 +138,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, return true; // Derive the type for the alias. - const llvm::PointerType *AliasType + llvm::PointerType *AliasType = getTypes().GetFunctionType(AliasDecl)->getPointerTo(); // Find the referrent. Some aliases might require a bitcast, in @@ -154,7 +154,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); // Switch any previous uses to the alias. - llvm::StringRef MangledName = getMangledName(AliasDecl); + StringRef MangledName = getMangledName(AliasDecl); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { assert(Entry->isDeclaration() && "definition already exists for alias"); @@ -214,14 +214,14 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, const CGFunctionInfo *fnInfo) { GlobalDecl GD(ctor, ctorType); - llvm::StringRef name = getMangledName(GD); + StringRef name = getMangledName(GD); if (llvm::GlobalValue *existing = GetGlobalValue(name)) return existing; if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType); const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>(); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo, proto->isVariadic()); return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, /*ForVTable=*/false)); @@ -236,11 +236,7 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { // The destructor used for destructing this as a most-derived class; // call the base destructor and then destructs any virtual bases. - if (!D->getParent()->isAbstract() || D->isVirtual()) { - // We don't need to emit the complete ctor if the class is abstract, - // unless the destructor is virtual and needs to be in the vtable. - EmitGlobal(GlobalDecl(D, Dtor_Complete)); - } + EmitGlobal(GlobalDecl(D, Dtor_Complete)); // The destructor used for destructing this as a base class; ignores // virtual bases. @@ -282,13 +278,13 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, const CGFunctionInfo *fnInfo) { GlobalDecl GD(dtor, dtorType); - llvm::StringRef name = getMangledName(GD); + StringRef name = getMangledName(GD); if (llvm::GlobalValue *existing = GetGlobalValue(name)) return existing; if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo, false); return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, @@ -296,7 +292,7 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, } static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, - llvm::Value *This, const llvm::Type *Ty) { + llvm::Value *This, llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo(); llvm::Value *VTable = CGF.GetVTablePtr(This, Ty); @@ -307,9 +303,9 @@ static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, - const llvm::Type *Ty) { + llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); + uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } @@ -320,7 +316,7 @@ CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, llvm::Value * CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier *Qual, - const llvm::Type *Ty) { + llvm::Type *Ty) { llvm::Value *VTable = 0; assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) && "BuildAppleKextVirtualCall - bad Qual kind"); @@ -339,9 +335,10 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, VTable = Builder.CreateBitCast(VTable, Ty); assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); MD = MD->getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); + uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(MD); uint64_t AddressPoint = - CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD); + CGM.getVTableContext().getVTableLayout(RD) + .getAddressPoint(BaseSubobject(RD, CharUnits::Zero())); VTableIndex += AddressPoint; llvm::Value *VFuncPtr = Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); @@ -366,7 +363,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall( &CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD), Dtor_Complete); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty + llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic()); llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD); @@ -374,9 +371,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall( VTable = Builder.CreateBitCast(VTable, Ty); DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); uint64_t VTableIndex = - CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); + CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type)); uint64_t AddressPoint = - CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD); + CGM.getVTableContext().getVTableLayout(RD) + .getAddressPoint(BaseSubobject(RD, CharUnits::Zero())); VTableIndex += AddressPoint; llvm::Value *VFuncPtr = Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); @@ -387,10 +385,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall( llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, - llvm::Value *This, const llvm::Type *Ty) { + llvm::Value *This, llvm::Type *Ty) { DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); uint64_t VTableIndex = - CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); + CGM.getVTableContext().getMethodVTableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp index dcc28b4..248448c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp @@ -20,9 +20,9 @@ using namespace CodeGen; CGCXXABI::~CGCXXABI() { } static void ErrorUnsupportedABI(CodeGenFunction &CGF, - llvm::StringRef S) { - Diagnostic &Diags = CGF.CGM.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + StringRef S) { + DiagnosticsEngine &Diags = CGF.CGM.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet compile %1 in this ABI"); Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()), DiagID) @@ -49,7 +49,7 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, MPT->getPointeeType()->getAs<FunctionProtoType>(); const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), FPT->isVariadic()); return llvm::Constant::getNullValue(FTy->getPointerTo()); @@ -60,7 +60,7 @@ llvm::Value *CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, llvm::Value *MemPtr, const MemberPointerType *MPT) { ErrorUnsupportedABI(CGF, "loads of member pointers"); - const llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo(); + llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo(); return llvm::Constant::getNullValue(Ty); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h index 29f299a..c2abf35 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h @@ -15,14 +15,14 @@ #ifndef CLANG_CODEGEN_CXXABI_H #define CLANG_CODEGEN_CXXABI_H +#include "clang/Basic/LLVM.h" + #include "CodeGenFunction.h" namespace llvm { class Constant; class Type; class Value; - - template <class T> class SmallVectorImpl; } namespace clang { @@ -151,7 +151,7 @@ public: virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) = 0; + SmallVectorImpl<CanQualType> &ArgTys) = 0; /// Build the signature of the given destructor variant by adding /// any required parameters. For convenience, ResTy has been @@ -160,7 +160,7 @@ public: virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) = 0; + SmallVectorImpl<CanQualType> &ArgTys) = 0; /// Build the ABI-specific portion of the parameter list for a /// function. This generally involves a 'this' parameter and diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index f8783ad..6ae2d0c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -69,14 +69,14 @@ static CanQualType GetReturnType(QualType RetTy) { const CGFunctionInfo & CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) { return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(), - llvm::SmallVector<CanQualType, 16>(), + SmallVector<CanQualType, 16>(), FTNP->getExtInfo()); } /// \param Args - contains any initial parameters besides those /// in the formal type static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, - llvm::SmallVectorImpl<CanQualType> &ArgTys, + SmallVectorImpl<CanQualType> &ArgTys, CanQual<FunctionProtoType> FTP) { // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) @@ -87,7 +87,7 @@ static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, const CGFunctionInfo & CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) { - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; return ::getFunctionInfo(*this, ArgTys, FTP); } @@ -113,7 +113,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP) { - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; // Add the 'this' pointer. ArgTys.push_back(GetThisType(Context, RD)); @@ -123,7 +123,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; assert(!isa<CXXConstructorDecl>(MD) && "wrong method for contructors!"); assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!"); @@ -137,7 +137,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, CXXCtorType Type) { - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; ArgTys.push_back(GetThisType(Context, D->getParent())); CanQualType ResTy = Context.VoidTy; @@ -154,7 +154,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::SmallVector<CanQualType, 2> ArgTys; + SmallVector<CanQualType, 2> ArgTys; ArgTys.push_back(GetThisType(Context, D->getParent())); CanQualType ResTy = Context.VoidTy; @@ -180,11 +180,11 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType())); ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType())); // FIXME: Kill copy? - for (ObjCMethodDecl::param_iterator i = MD->param_begin(), + for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(), e = MD->param_end(); i != e; ++i) { ArgTys.push_back(Context.getCanonicalParamType((*i)->getType())); } @@ -216,7 +216,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CallArgList &Args, const FunctionType::ExtInfo &Info) { // FIXME: Kill copy. - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(Context.getCanonicalParamType(i->Ty)); @@ -227,7 +227,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const FunctionArgList &Args, const FunctionType::ExtInfo &Info) { // FIXME: Kill copy. - llvm::SmallVector<CanQualType, 16> ArgTys; + SmallVector<CanQualType, 16> ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(Context.getCanonicalParamType((*i)->getType())); @@ -235,15 +235,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, } const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() { - llvm::SmallVector<CanQualType, 1> args; + SmallVector<CanQualType, 1> args; return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, - const llvm::SmallVectorImpl<CanQualType> &ArgTys, + const SmallVectorImpl<CanQualType> &ArgTys, const FunctionType::ExtInfo &Info) { #ifndef NDEBUG - for (llvm::SmallVectorImpl<CanQualType>::const_iterator + for (SmallVectorImpl<CanQualType>::const_iterator I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I) assert(I->isCanonicalAsParam()); #endif @@ -312,50 +312,65 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, /***/ void CodeGenTypes::GetExpandedTypes(QualType type, - llvm::SmallVectorImpl<llvm::Type*> &expandedTypes) { - const RecordType *RT = type->getAsStructureType(); - assert(RT && "Can only expand structure types."); - const RecordDecl *RD = RT->getDecl(); - assert(!RD->hasFlexibleArrayMember() && - "Cannot expand structure with flexible array."); - - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + SmallVectorImpl<llvm::Type*> &expandedTypes) { + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(type)) { + uint64_t NumElts = AT->getSize().getZExtValue(); + for (uint64_t Elt = 0; Elt < NumElts; ++Elt) + GetExpandedTypes(AT->getElementType(), expandedTypes); + } else if (const RecordType *RT = type->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl(); + assert(!RD->hasFlexibleArrayMember() && + "Cannot expand structure with flexible array."); + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { - const FieldDecl *FD = *i; - assert(!FD->isBitField() && - "Cannot expand structure with bit-field members."); - - QualType fieldType = FD->getType(); - if (fieldType->isRecordType()) - GetExpandedTypes(fieldType, expandedTypes); - else - expandedTypes.push_back(ConvertType(fieldType)); - } + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + GetExpandedTypes(FD->getType(), expandedTypes); + } + } else if (const ComplexType *CT = type->getAs<ComplexType>()) { + llvm::Type *EltTy = ConvertType(CT->getElementType()); + expandedTypes.push_back(EltTy); + expandedTypes.push_back(EltTy); + } else + expandedTypes.push_back(ConvertType(type)); } llvm::Function::arg_iterator CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, llvm::Function::arg_iterator AI) { - const RecordType *RT = Ty->getAsStructureType(); - assert(RT && "Can only expand structure types."); - - RecordDecl *RD = RT->getDecl(); assert(LV.isSimple() && "Unexpected non-simple lvalue during struct expansion."); llvm::Value *Addr = LV.getAddress(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + + if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { + unsigned NumElts = AT->getSize().getZExtValue(); + QualType EltTy = AT->getElementType(); + for (unsigned Elt = 0; Elt < NumElts; ++Elt) { + llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt); + LValue LV = MakeAddrLValue(EltAddr, EltTy); + AI = ExpandTypeFromArgs(EltTy, LV, AI); + } + } else if (const RecordType *RT = Ty->getAsStructureType()) { + RecordDecl *RD = RT->getDecl(); + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); + FieldDecl *FD = *i; + QualType FT = FD->getType(); - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - if (CodeGenFunction::hasAggregateLLVMType(FT)) { + // FIXME: What are the right qualifiers here? + LValue LV = EmitLValueForField(Addr, FD, 0); AI = ExpandTypeFromArgs(FT, LV, AI); - } else { - EmitStoreThroughLValue(RValue::get(AI), LV); - ++AI; } + } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) { + QualType EltTy = CT->getElementType(); + llvm::Value *RealAddr = Builder.CreateStructGEP(Addr, 0, "real"); + EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy)); + llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 0, "imag"); + EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy)); + } else { + EmitStoreThroughLValue(RValue::get(AI), LV); + ++AI; } return AI; @@ -367,12 +382,12 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, /// with an in-memory size smaller than DstSize. static llvm::Value * EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr, - const llvm::StructType *SrcSTy, + llvm::StructType *SrcSTy, uint64_t DstSize, CodeGenFunction &CGF) { // We can't dive into a zero-element struct. if (SrcSTy->getNumElements() == 0) return SrcPtr; - const llvm::Type *FirstElt = SrcSTy->getElementType(0); + llvm::Type *FirstElt = SrcSTy->getElementType(0); // If the first elt is at least as large as what we're looking for, or if the // first element is the same size as the whole struct, we can enter it. @@ -386,9 +401,9 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr, SrcPtr = CGF.Builder.CreateConstGEP2_32(SrcPtr, 0, 0, "coerce.dive"); // If the first element is a struct, recurse. - const llvm::Type *SrcTy = + llvm::Type *SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); - if (const llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) + if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) return EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF); return SrcPtr; @@ -398,7 +413,7 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr, /// are either integers or pointers. This does a truncation of the value if it /// is too large or a zero extension if it is too small. static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, - const llvm::Type *Ty, + llvm::Type *Ty, CodeGenFunction &CGF) { if (Val->getType() == Ty) return Val; @@ -412,7 +427,7 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, Val = CGF.Builder.CreatePtrToInt(Val, CGF.IntPtrTy, "coerce.val.pi"); } - const llvm::Type *DestIntTy = Ty; + llvm::Type *DestIntTy = Ty; if (isa<llvm::PointerType>(DestIntTy)) DestIntTy = CGF.IntPtrTy; @@ -433,9 +448,9 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, /// destination type; in this situation the values of bits which not /// present in the src are undefined. static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, - const llvm::Type *Ty, + llvm::Type *Ty, CodeGenFunction &CGF) { - const llvm::Type *SrcTy = + llvm::Type *SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); // If SrcTy and Ty are the same, just do a load. @@ -444,7 +459,7 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty); - if (const llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) { + if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) { SrcPtr = EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF); SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); } @@ -495,7 +510,7 @@ static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, llvm::Value *DestPtr, bool DestIsVolatile, bool LowAlignment) { // Prefer scalar stores to first-class aggregate stores. - if (const llvm::StructType *STy = + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(Val->getType())) { for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i); @@ -519,8 +534,8 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::Value *DstPtr, bool DstIsVolatile, CodeGenFunction &CGF) { - const llvm::Type *SrcTy = Src->getType(); - const llvm::Type *DstTy = + llvm::Type *SrcTy = Src->getType(); + llvm::Type *DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType(); if (SrcTy == DstTy) { CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile); @@ -529,7 +544,7 @@ static void CreateCoercedStore(llvm::Value *Src, uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); - if (const llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) { + if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) { DstPtr = EnterStructPointerForCoercedAccess(DstPtr, DstSTy, SrcSize, CGF); DstTy = cast<llvm::PointerType>(DstPtr->getType())->getElementType(); } @@ -584,11 +599,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) { default: return false; case BuiltinType::Float: - return getContext().Target.useObjCFPRetForRealType(TargetInfo::Float); + return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Float); case BuiltinType::Double: - return getContext().Target.useObjCFPRetForRealType(TargetInfo::Double); + return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Double); case BuiltinType::LongDouble: - return getContext().Target.useObjCFPRetForRealType( + return getContext().getTargetInfo().useObjCFPRetForRealType( TargetInfo::LongDouble); } } @@ -614,8 +629,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted; assert(Inserted && "Recursively being processed?"); - llvm::SmallVector<llvm::Type*, 8> argTypes; - const llvm::Type *resultType = 0; + SmallVector<llvm::Type*, 8> argTypes; + llvm::Type *resultType = 0; const ABIArgInfo &retAI = FI.getReturnInfo(); switch (retAI.getKind()) { @@ -632,7 +647,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { resultType = llvm::Type::getVoidTy(getLLVMContext()); QualType ret = FI.getReturnType(); - const llvm::Type *ty = ConvertType(ret); + llvm::Type *ty = ConvertType(ret); unsigned addressSpace = Context.getTargetAddressSpace(ret); argTypes.push_back(llvm::PointerType::get(ty, addressSpace)); break; @@ -653,7 +668,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { case ABIArgInfo::Indirect: { // indirect arguments are always on the stack, which is addr space #0. - const llvm::Type *LTy = ConvertTypeForMem(it->type); + llvm::Type *LTy = ConvertTypeForMem(it->type); argTypes.push_back(LTy->getPointerTo()); break; } @@ -664,7 +679,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { // way is semantically identical, but fast-isel and the optimizer // generally likes scalar values better than FCAs. llvm::Type *argType = argAI.getCoerceToType(); - if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) { + if (llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) { for (unsigned i = 0, e = st->getNumElements(); i != e; ++i) argTypes.push_back(st->getElementType(i)); } else { @@ -685,7 +700,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) { return llvm::FunctionType::get(resultType, argTypes, isVariadic); } -const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { +llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); @@ -714,6 +729,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // FIXME: handle sseregparm someday... if (TargetDecl) { + if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) + FuncAttrs |= llvm::Attribute::ReturnsTwice; if (TargetDecl->hasAttr<NoThrowAttr>()) FuncAttrs |= llvm::Attribute::NoUnwind; else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { @@ -724,10 +741,18 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, if (TargetDecl->hasAttr<NoReturnAttr>()) FuncAttrs |= llvm::Attribute::NoReturn; - if (TargetDecl->hasAttr<ConstAttr>()) + + if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) + FuncAttrs |= llvm::Attribute::ReturnsTwice; + + // 'const' and 'pure' attribute functions are also nounwind. + if (TargetDecl->hasAttr<ConstAttr>()) { FuncAttrs |= llvm::Attribute::ReadNone; - else if (TargetDecl->hasAttr<PureAttr>()) + FuncAttrs |= llvm::Attribute::NoUnwind; + } else if (TargetDecl->hasAttr<PureAttr>()) { FuncAttrs |= llvm::Attribute::ReadOnly; + FuncAttrs |= llvm::Attribute::NoUnwind; + } if (TargetDecl->hasAttr<MallocAttr>()) RetAttrs |= llvm::Attribute::NoAlias; } @@ -763,7 +788,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, break; case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + llvm_unreachable("Invalid ABI kind for return argument"); } if (RetAttrs) @@ -776,7 +801,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, else RegParm = CodeGenOpts.NumRegisterParameters; - unsigned PointerWidth = getContext().Target.getPointerWidth(0); + unsigned PointerWidth = getContext().getTargetInfo().getPointerWidth(0); for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { QualType ParamType = it->type; @@ -803,7 +828,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, } // FIXME: handle sseregparm someday... - if (const llvm::StructType *STy = + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType())) Index += STy->getNumElements()-1; // 1 will be added below. break; @@ -824,7 +849,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, continue; case ABIArgInfo::Expand: { - llvm::SmallVector<llvm::Type*, 8> types; + SmallVector<llvm::Type*, 8> types; // FIXME: This is rather inefficient. Do we ever actually need to do // anything here? The result should be just reconstructed on the other // side, so extension should be a non-issue. @@ -847,7 +872,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF, const VarDecl *var, llvm::Value *value) { - const llvm::Type *varType = CGF.ConvertType(var->getType()); + llvm::Type *varType = CGF.ConvertType(var->getType()); // This can happen with promotions that actually don't change the // underlying type, like the enum promotions. @@ -872,7 +897,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) { if (FD->hasImplicitReturnZero()) { QualType RetTy = FD->getResultType().getUnqualifiedType(); - const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); + llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy); Builder.CreateStore(Zero, ReturnValue); } @@ -887,6 +912,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the struct return argument. if (CGM.ReturnTypeUsesSRet(FI)) { AI->setName("agg.result"); + AI->addAttr(llvm::Attribute::NoAlias); ++AI; } @@ -918,7 +944,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // // FIXME: We should have a common utility for generating an aggregate // copy. - const llvm::Type *I8PtrTy = Builder.getInt8PtrTy(); + llvm::Type *I8PtrTy = Builder.getInt8PtrTy(); CharUnits Size = getContext().getTypeSizeInChars(Ty); llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy); llvm::Value *Src = Builder.CreateBitCast(V, I8PtrTy); @@ -954,9 +980,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (Arg->getType().isRestrictQualified()) AI->addAttr(llvm::Attribute::NoAlias); + // Ensure the argument is the correct type. + if (V->getType() != ArgI.getCoerceToType()) + V = Builder.CreateBitCast(V, ArgI.getCoerceToType()); + if (isPromoted) V = emitArgumentDemotion(*this, Arg, V); - + EmitParmDecl(*Arg, V, ArgNo); break; } @@ -985,13 +1015,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // If the coerce-to type is a first class aggregate, we flatten it and // pass the elements. Either way is semantically identical, but fast-isel // and the optimizer generally likes scalar values better than FCAs. - if (const llvm::StructType *STy = + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType())) { Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy)); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { assert(AI != Fn->arg_end() && "Argument mismatch!"); - AI->setName(Arg->getName() + ".coerce" + llvm::Twine(i)); + AI->setName(Arg->getName() + ".coerce" + Twine(i)); llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i); Builder.CreateStore(AI++, EltPtr); } @@ -1025,7 +1055,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the arguments used in expansion and increment AI. unsigned Index = 0; for (; AI != End; ++AI, ++Index) - AI->setName(Arg->getName() + "." + llvm::Twine(Index)); + AI->setName(Arg->getName() + "." + Twine(Index)); continue; } @@ -1054,12 +1084,12 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF, if (BB->empty()) return 0; if (&BB->back() != result) return 0; - const llvm::Type *resultType = result->getType(); + llvm::Type *resultType = result->getType(); // result is in a BasicBlock and is therefore an Instruction. llvm::Instruction *generator = cast<llvm::Instruction>(result); - llvm::SmallVector<llvm::Instruction*,4> insnsToKill; + SmallVector<llvm::Instruction*,4> insnsToKill; // Look for: // %generator = bitcast %type1* %generator2 to %type2* @@ -1112,7 +1142,7 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF, } // Delete all the unnecessary instructions, from latest to earliest. - for (llvm::SmallVectorImpl<llvm::Instruction*>::iterator + for (SmallVectorImpl<llvm::Instruction*>::iterator i = insnsToKill.begin(), e = insnsToKill.end(); i != e; ++i) (*i)->eraseFromParent(); @@ -1218,7 +1248,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { break; case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + llvm_unreachable("Invalid ABI kind for return argument"); } llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid(); @@ -1324,7 +1354,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // The dest and src types don't necessarily match in LLVM terms // because of the crazy ObjC compatibility rules. - const llvm::PointerType *destType = + llvm::PointerType *destType = cast<llvm::PointerType>(CGF.ConvertType(CRE->getType())); // If the address is a constant null, just pass the appropriate null. @@ -1406,9 +1436,14 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return emitWritebackArg(*this, args, CRE); } - if (type->isReferenceType()) + assert(type->isReferenceType() == E->isGLValue() && + "reference binding to unmaterialized r-value!"); + + if (E->isGLValue()) { + assert(E->getObjectKind() == OK_Ordinary); return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0), type); + } if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() && isa<ImplicitCastExpr>(E) && @@ -1427,8 +1462,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, /// on the current state of the EH stack. llvm::CallSite CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, - llvm::ArrayRef<llvm::Value *> Args, - const llvm::Twine &Name) { + ArrayRef<llvm::Value *> Args, + const Twine &Name) { llvm::BasicBlock *InvokeDest = getInvokeDest(); if (!InvokeDest) return Builder.CreateCall(Callee, Args, Name); @@ -1442,8 +1477,8 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, llvm::CallSite CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, - const llvm::Twine &Name) { - return EmitCallOrInvoke(Callee, llvm::ArrayRef<llvm::Value *>(), Name); + const Twine &Name) { + return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name); } static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo, @@ -1456,28 +1491,45 @@ static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo, } void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, - llvm::SmallVector<llvm::Value*,16> &Args, + SmallVector<llvm::Value*,16> &Args, llvm::FunctionType *IRFuncTy) { - const RecordType *RT = Ty->getAsStructureType(); - assert(RT && "Can only expand structure types."); - - RecordDecl *RD = RT->getDecl(); - assert(RV.isAggregate() && "Unexpected rvalue during struct expansion"); - llvm::Value *Addr = RV.getAggregateAddr(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - if (CodeGenFunction::hasAggregateLLVMType(FT)) { - ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), - Args, IRFuncTy); - continue; + if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { + unsigned NumElts = AT->getSize().getZExtValue(); + QualType EltTy = AT->getElementType(); + llvm::Value *Addr = RV.getAggregateAddr(); + for (unsigned Elt = 0; Elt < NumElts; ++Elt) { + llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt); + LValue LV = MakeAddrLValue(EltAddr, EltTy); + RValue EltRV; + if (CodeGenFunction::hasAggregateLLVMType(EltTy)) + EltRV = RValue::getAggregate(LV.getAddress()); + else + EltRV = EmitLoadOfLValue(LV); + ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy); } + } else if (const RecordType *RT = Ty->getAsStructureType()) { + RecordDecl *RD = RT->getDecl(); + assert(RV.isAggregate() && "Unexpected rvalue during struct expansion"); + llvm::Value *Addr = RV.getAggregateAddr(); + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + FieldDecl *FD = *i; + QualType FT = FD->getType(); - RValue RV = EmitLoadOfLValue(LV); + // FIXME: What are the right qualifiers here? + LValue LV = EmitLValueForField(Addr, FD, 0); + RValue FldRV; + if (CodeGenFunction::hasAggregateLLVMType(FT)) + FldRV = RValue::getAggregate(LV.getAddress()); + else + FldRV = EmitLoadOfLValue(LV); + ExpandTypeToArgs(FT, FldRV, Args, IRFuncTy); + } + } else if (isa<ComplexType>(Ty)) { + ComplexPairTy CV = RV.getComplexVal(); + Args.push_back(CV.first); + Args.push_back(CV.second); + } else { assert(RV.isScalar() && "Unexpected non-scalar rvalue during struct expansion."); @@ -1499,7 +1551,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, const Decl *TargetDecl, llvm::Instruction **callOrInvoke) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. - llvm::SmallVector<llvm::Value*, 16> Args; + SmallVector<llvm::Value*, 16> Args; // Handle struct-return functions by passing a pointer to the // location that we would like to return into. @@ -1630,7 +1682,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the coerce-to type is a first class aggregate, we flatten it and // pass the elements. Either way is semantically identical, but fast-isel // and the optimizer generally likes scalar values better than FCAs. - if (const llvm::StructType *STy = + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) { SrcPtr = Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(STy)); @@ -1668,10 +1720,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // with unprototyped functions. if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Callee)) if (llvm::Function *CalleeF = dyn_cast<llvm::Function>(CE->getOperand(0))) { - const llvm::PointerType *CurPT=cast<llvm::PointerType>(Callee->getType()); - const llvm::FunctionType *CurFT = + llvm::PointerType *CurPT=cast<llvm::PointerType>(Callee->getType()); + llvm::FunctionType *CurFT = cast<llvm::FunctionType>(CurPT->getElementType()); - const llvm::FunctionType *ActualFT = CalleeF->getFunctionType(); + llvm::FunctionType *ActualFT = CalleeF->getFunctionType(); if (CE->getOpcode() == llvm::Instruction::BitCast && ActualFT->getReturnType() == CurFT->getReturnType() && @@ -1813,11 +1865,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + llvm_unreachable("Invalid ABI kind for return argument"); } - assert(0 && "Unhandled ABIArgInfo::Kind"); - return RValue::get(0); + llvm_unreachable("Unhandled ABIArgInfo::Kind"); } /* VarArg handling */ diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h index 343b944..24ed366 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h @@ -42,7 +42,7 @@ namespace clang { class VarDecl; namespace CodeGen { - typedef llvm::SmallVector<llvm::AttributeWithIndex, 8> AttributeListType; + typedef SmallVector<llvm::AttributeWithIndex, 8> AttributeListType; struct CallArg { RValue RV; @@ -56,7 +56,7 @@ namespace CodeGen { /// CallArgList - Type for representing both the value and type of /// arguments in a call. class CallArgList : - public llvm::SmallVector<CallArg, 16> { + public SmallVector<CallArg, 16> { public: struct Writeback { /// The original argument. @@ -90,18 +90,18 @@ namespace CodeGen { bool hasWritebacks() const { return !Writebacks.empty(); } - typedef llvm::SmallVectorImpl<Writeback>::const_iterator writeback_iterator; + typedef SmallVectorImpl<Writeback>::const_iterator writeback_iterator; writeback_iterator writeback_begin() const { return Writebacks.begin(); } writeback_iterator writeback_end() const { return Writebacks.end(); } private: - llvm::SmallVector<Writeback, 1> Writebacks; + SmallVector<Writeback, 1> Writebacks; }; /// FunctionArgList - Type for representing both the decl and type /// of parameters to a function. The decl must be either a /// ParmVarDecl or ImplicitParamDecl. - class FunctionArgList : public llvm::SmallVector<const VarDecl*, 16> { + class FunctionArgList : public SmallVector<const VarDecl*, 16> { }; /// CGFunctionInfo - Class to encapsulate the information about a diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp index 7dbaaf8..c28ecc0 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp @@ -62,7 +62,7 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, if (Offset.isZero()) return 0; - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = Types.ConvertType(getContext().getPointerDiffType()); return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity()); @@ -95,7 +95,7 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, // TODO: for complete types, this should be possible with a GEP. llvm::Value *V = This; if (Offset.isPositive()) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); V = Builder.CreateBitCast(V, Int8PtrTy); V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity()); } @@ -107,7 +107,7 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, static llvm::Value * ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, CharUnits NonVirtual, llvm::Value *Virtual) { - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); llvm::Value *NonVirtualOffset = 0; @@ -125,7 +125,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, BaseOffset = NonVirtualOffset; // Apply the base offset. - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr"); @@ -155,7 +155,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, Start, PathEnd); // Get the base pointer type. - const llvm::Type *BasePtrTy = + llvm::Type *BasePtrTy = ConvertType((PathEnd[-1])->getType())->getPointerTo(); if (NonVirtualOffset.isZero() && !VBase) { @@ -225,7 +225,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, QualType DerivedTy = getContext().getCanonicalType(getContext().getTagDeclType(Derived)); - const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); + llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); llvm::Value *NonVirtualOffset = CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd); @@ -398,8 +398,11 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, BaseClassDecl, isBaseVirtual); - AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(), - /*Lifetime*/ true); + AggValueSlot AggSlot = + AggValueSlot::forAddr(V, Qualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); CGF.EmitAggExpr(BaseInit->getInit(), AggSlot); @@ -436,8 +439,11 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest, LHS.isVolatileQualified()); } else { - AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(), - /*Lifetime*/ true); + AggValueSlot Slot = + AggValueSlot::forAddr(Dest, LHS.getQuals(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); CGF.EmitAggExpr(MemberInit->getInit(), Slot); } @@ -521,6 +527,12 @@ namespace { } }; } + +static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record, + bool Moving) { + return Moving ? Record->hasTrivialMoveConstructor() : + Record->hasTrivialCopyConstructor(); +} static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, @@ -547,11 +559,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); } - // FIXME: If there's no initializer and the CXXCtorInitializer - // was implicitly generated, we shouldn't be zeroing memory. - if (FieldType->isArrayType() && !MemberInit->getInit()) { - CGF.EmitNullInitialization(LHS.getAddress(), Field->getType()); - } else if (!CGF.hasAggregateLLVMType(Field->getType())) { + if (!CGF.hasAggregateLLVMType(Field->getType())) { if (LHS.isSimple()) { CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS, false); } else { @@ -565,15 +573,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, llvm::Value *ArrayIndexVar = 0; const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(FieldType); - if (Array && Constructor->isImplicit() && - Constructor->isCopyConstructor()) { - const llvm::Type *SizeTy + if (Array && Constructor->isImplicitlyDefined() && + Constructor->isCopyOrMoveConstructor()) { + llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); // The LHS is a pointer to the first object we'll be constructing, as // a flat array. QualType BaseElementTy = CGF.getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy); + llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); @@ -589,7 +597,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // constructors, perform a single aggregate copy. const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl(); if (BaseElementTy.isPODType(CGF.getContext()) || - (Record && Record->hasTrivialCopyConstructor())) { + (Record && hasTrivialCopyOrMoveConstructor(Record, + Constructor->isMoveConstructor()))) { // Find the source pointer. We knows it's the last argument because // we know we're in a copy constructor. unsigned SrcArgIndex = Args.size() - 1; @@ -684,7 +693,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // delegation optimization. if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) { if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitStopPoint(Builder); + DI->EmitLocation(Builder, Ctor->getLocEnd()); EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); return; } @@ -729,7 +738,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, const CXXRecordDecl *ClassDecl = CD->getParent(); - llvm::SmallVector<CXXCtorInitializer *, 8> MemberInitializers; + SmallVector<CXXCtorInitializer *, 8> MemberInitializers; for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); @@ -971,6 +980,10 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, const CXXRecordDecl *ClassDecl = DD->getParent(); + // Unions have no bases and do not call field destructors. + if (ClassDecl->isUnion()) + return; + // The complete-destructor phase just destructs all the virtual bases. if (DtorType == Dtor_Complete) { @@ -1018,7 +1031,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, } // Destroy direct fields. - llvm::SmallVector<const FieldDecl *, 16> FieldDecls; + SmallVector<const FieldDecl *, 16> FieldDecls; for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { const FieldDecl *field = *I; @@ -1195,7 +1208,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, } assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor"); - assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor"); + assert(D->isCopyOrMoveConstructor() && + "trivial 1-arg ctor not a copy/move ctor"); const Expr *E = (*ArgBeg); QualType Ty = E->getType(); @@ -1217,7 +1231,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, CallExpr::const_arg_iterator ArgEnd) { if (D->isTrivial()) { assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor"); - assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor"); + assert(D->isCopyOrMoveConstructor() && + "trivial 1-arg ctor not a copy/move ctor"); EmitAggregateCopy(This, Src, (*ArgBeg)->getType()); return; } @@ -1236,7 +1251,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, // Push the src ptr. QualType QT = *(FPT->arg_type_begin()); - const llvm::Type *t = CGM.getTypes().ConvertType(QT); + llvm::Type *t = CGM.getTypes().ConvertType(QT); Src = Builder.CreateBitCast(Src, t); Args.add(RValue::get(Src), QT); @@ -1258,10 +1273,8 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, EmitCallArg(Args, *Arg, ArgType); } - QualType ResultType = FPT->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, - FPT->getExtInfo()), - Callee, ReturnValueSlot(), Args, D); + EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee, + ReturnValueSlot(), Args, D); } void @@ -1326,7 +1339,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor llvm::Value *ThisPtr = LoadCXXThis(); AggValueSlot AggSlot = - AggValueSlot::forAddr(ThisPtr, Qualifiers(), /*Lifetime*/ true); + AggValueSlot::forAddr(ThisPtr, Qualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); @@ -1394,12 +1410,12 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, const CXXRecordDecl *BaseClassDecl) { llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy); CharUnits VBaseOffsetOffset = - CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); + CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(), "vbase.offset.ptr"); - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, @@ -1436,7 +1452,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, // And load the address point from the VTT. VTableAddressPoint = Builder.CreateLoad(VTT); } else { - uint64_t AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + uint64_t AddressPoint = + CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base); VTableAddressPoint = Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint); } @@ -1465,7 +1482,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, VirtualOffset); // Finally, store the address point. - const llvm::Type *AddressPointPtrTy = + llvm::Type *AddressPointPtrTy = VTableAddressPoint->getType()->getPointerTo(); VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy); Builder.CreateStore(VTableAddressPoint, VTableField); @@ -1549,7 +1566,7 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { } llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This, - const llvm::Type *Ty) { + llvm::Type *Ty) { llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo()); return Builder.CreateLoad(VTablePtrSrc, "vtable"); } @@ -1605,7 +1622,6 @@ static const Expr *skipNoOpCastsAndParens(const Expr *E) { /// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member /// function call on the given expr can be devirtualized. -/// expr can be devirtualized. static bool canDevirtualizeMemberFunctionCall(const Expr *Base, const CXXMethodDecl *MD) { // If the most derived class is marked final, we know that no subclass can @@ -1677,7 +1693,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, llvm::Value *This) { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); - const llvm::Type *Ty = + llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp index 9c5dd1f..b2d0786 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp @@ -48,7 +48,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) { if (rv.isComplex()) { CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); - const llvm::Type *ComplexTy = + llvm::Type *ComplexTy = llvm::StructType::get(V.first->getType(), V.second->getType(), (void*) 0); llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex"); @@ -119,16 +119,30 @@ char *EHScopeStack::allocate(size_t Size) { } EHScopeStack::stable_iterator -EHScopeStack::getEnclosingEHCleanup(iterator it) const { - assert(it != end()); - do { - if (isa<EHCleanupScope>(*it)) { - if (cast<EHCleanupScope>(*it).isEHCleanup()) - return stabilize(it); - return cast<EHCleanupScope>(*it).getEnclosingEHCleanup(); +EHScopeStack::getInnermostActiveNormalCleanup() const { + for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end(); + si != se; ) { + EHCleanupScope &cleanup = cast<EHCleanupScope>(*find(si)); + if (cleanup.isActive()) return si; + si = cleanup.getEnclosingNormalCleanup(); + } + return stable_end(); +} + +EHScopeStack::stable_iterator EHScopeStack::getInnermostActiveEHScope() const { + for (stable_iterator si = getInnermostEHScope(), se = stable_end(); + si != se; ) { + // Skip over inactive cleanups. + EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*find(si)); + if (cleanup && !cleanup->isActive()) { + si = cleanup->getEnclosingEHScope(); + continue; } - ++it; - } while (it != end()); + + // All other scopes are always active. + return si; + } + return stable_end(); } @@ -146,11 +160,11 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { Size, BranchFixups.size(), InnermostNormalCleanup, - InnermostEHCleanup); + InnermostEHScope); if (IsNormalCleanup) InnermostNormalCleanup = stable_begin(); if (IsEHCleanup) - InnermostEHCleanup = stable_begin(); + InnermostEHScope = stable_begin(); return Scope->getCleanupBuffer(); } @@ -161,11 +175,9 @@ void EHScopeStack::popCleanup() { assert(isa<EHCleanupScope>(*begin())); EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin()); InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); - InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); + InnermostEHScope = Cleanup.getEnclosingEHScope(); StartOfData += Cleanup.getAllocatedSize(); - if (empty()) NextEHDestIndex = FirstEHDestIndex; - // Destroy the cleanup. Cleanup.~EHCleanupScope(); @@ -182,37 +194,35 @@ void EHScopeStack::popCleanup() { } } -EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) { - char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters)); - CatchDepth++; - return new (Buffer) EHFilterScope(NumFilters); +EHFilterScope *EHScopeStack::pushFilter(unsigned numFilters) { + assert(getInnermostEHScope() == stable_end()); + char *buffer = allocate(EHFilterScope::getSizeForNumFilters(numFilters)); + EHFilterScope *filter = new (buffer) EHFilterScope(numFilters); + InnermostEHScope = stable_begin(); + return filter; } void EHScopeStack::popFilter() { assert(!empty() && "popping exception stack when not empty"); - EHFilterScope &Filter = cast<EHFilterScope>(*begin()); - StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters()); + EHFilterScope &filter = cast<EHFilterScope>(*begin()); + StartOfData += EHFilterScope::getSizeForNumFilters(filter.getNumFilters()); - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched filter push/pop"); - CatchDepth--; + InnermostEHScope = filter.getEnclosingEHScope(); } -EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) { - char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers)); - CatchDepth++; - EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers); - for (unsigned I = 0; I != NumHandlers; ++I) - Scope->getHandlers()[I].Index = getNextEHDestIndex(); - return Scope; +EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) { + char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers)); + EHCatchScope *scope = + new (buffer) EHCatchScope(numHandlers, InnermostEHScope); + InnermostEHScope = stable_begin(); + return scope; } void EHScopeStack::pushTerminate() { char *Buffer = allocate(EHTerminateScope::getSize()); - CatchDepth++; - new (Buffer) EHTerminateScope(getNextEHDestIndex()); + new (Buffer) EHTerminateScope(InnermostEHScope); + InnermostEHScope = stable_begin(); } /// Remove any 'null' fixups on the stack. However, we can't pop more @@ -384,17 +394,6 @@ static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, return Entry; } -static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF, - EHCleanupScope &Scope) { - assert(Scope.isEHCleanup()); - llvm::BasicBlock *Entry = Scope.getEHBlock(); - if (!Entry) { - Entry = CGF.createBasicBlock("eh.cleanup"); - Scope.setEHBlock(Entry); - } - return Entry; -} - /// Attempts to reduce a cleanup's entry block to a fallthrough. This /// is basically llvm::MergeBlockIntoPredecessor, except /// simplified/optimized for the tighter constraints on cleanup blocks. @@ -483,6 +482,49 @@ static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit, } } +/// We don't need a normal entry block for the given cleanup. +/// Optimistic fixup branches can cause these blocks to come into +/// existence anyway; if so, destroy it. +/// +/// The validity of this transformation is very much specific to the +/// exact ways in which we form branches to cleanup entries. +static void destroyOptimisticNormalEntry(CodeGenFunction &CGF, + EHCleanupScope &scope) { + llvm::BasicBlock *entry = scope.getNormalBlock(); + if (!entry) return; + + // Replace all the uses with unreachable. + llvm::BasicBlock *unreachableBB = CGF.getUnreachableBlock(); + for (llvm::BasicBlock::use_iterator + i = entry->use_begin(), e = entry->use_end(); i != e; ) { + llvm::Use &use = i.getUse(); + ++i; + + use.set(unreachableBB); + + // The only uses should be fixup switches. + llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser()); + if (si->getNumCases() == 2 && si->getDefaultDest() == unreachableBB) { + // Replace the switch with a branch. + llvm::BranchInst::Create(si->getSuccessor(1), si); + + // The switch operand is a load from the cleanup-dest alloca. + llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition()); + + // Destroy the switch. + si->eraseFromParent(); + + // Destroy the load. + assert(condition->getOperand(0) == CGF.NormalCleanupDest); + assert(condition->use_empty()); + condition->eraseFromParent(); + } + } + + assert(entry->use_empty()); + delete entry; +} + /// Pops a cleanup block. If the block includes a normal cleanup, the /// current insertion point is threaded through the cleanup, as are /// any branch fixups on the cleanup. @@ -501,7 +543,10 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // Check whether we need an EH cleanup. This is only true if we've // generated a lazy EH cleanup block. - bool RequiresEHCleanup = Scope.hasEHBranches(); + llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock(); + assert(Scope.hasEHBranches() == (EHEntry != 0)); + bool RequiresEHCleanup = (EHEntry != 0); + EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope(); // Check the three conditions which might require a normal cleanup: @@ -537,43 +582,37 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { RequiresNormalCleanup = true; } - EHScopeStack::Cleanup::Flags cleanupFlags; - if (Scope.isNormalCleanup()) - cleanupFlags.setIsNormalCleanupKind(); - if (Scope.isEHCleanup()) - cleanupFlags.setIsEHCleanupKind(); - - // Even if we don't need the normal cleanup, we might still have - // prebranched fallthrough to worry about. - if (Scope.isNormalCleanup() && !RequiresNormalCleanup && - HasPrebranchedFallthrough) { - assert(!IsActive); - - llvm::BasicBlock *NormalEntry = Scope.getNormalBlock(); - - // If we're branching through this cleanup, just forward the - // prebranched fallthrough to the next cleanup, leaving the insert - // point in the old block. + // If we have a prebranched fallthrough into an inactive normal + // cleanup, rewrite it so that it leads to the appropriate place. + if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) { + llvm::BasicBlock *prebranchDest; + + // If the prebranch is semantically branching through the next + // cleanup, just forward it to the next block, leaving the + // insertion point in the prebranched block. if (FallthroughIsBranchThrough) { - EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); - llvm::BasicBlock *EnclosingEntry = - CreateNormalEntry(*this, cast<EHCleanupScope>(S)); - - ForwardPrebranchedFallthrough(FallthroughSource, - NormalEntry, EnclosingEntry); - assert(NormalEntry->use_empty() && - "uses of entry remain after forwarding?"); - delete NormalEntry; + EHScope &enclosing = *EHStack.find(Scope.getEnclosingNormalCleanup()); + prebranchDest = CreateNormalEntry(*this, cast<EHCleanupScope>(enclosing)); - // Otherwise, we're branching out; just emit the next block. + // Otherwise, we need to make a new block. If the normal cleanup + // isn't being used at all, we could actually reuse the normal + // entry block, but this is simpler, and it avoids conflicts with + // dead optimistic fixup branches. } else { - EmitBlock(NormalEntry); - SimplifyCleanupEntry(*this, NormalEntry); + prebranchDest = createBasicBlock("forwarded-prebranch"); + EmitBlock(prebranchDest); } + + llvm::BasicBlock *normalEntry = Scope.getNormalBlock(); + assert(normalEntry && !normalEntry->use_empty()); + + ForwardPrebranchedFallthrough(FallthroughSource, + normalEntry, prebranchDest); } // If we don't need the cleanup at all, we're done. if (!RequiresNormalCleanup && !RequiresEHCleanup) { + destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); // safe because there are no fixups assert(EHStack.getNumBranchFixups() == 0 || EHStack.hasNormalCleanups()); @@ -583,7 +622,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // Copy the cleanup emission data out. Note that SmallVector // guarantees maximal alignment for its buffer regardless of its // type parameter. - llvm::SmallVector<char, 8*sizeof(void*)> CleanupBuffer; + SmallVector<char, 8*sizeof(void*)> CleanupBuffer; CleanupBuffer.reserve(Scope.getCleanupSize()); memcpy(CleanupBuffer.data(), Scope.getCleanupBuffer(), Scope.getCleanupSize()); @@ -591,63 +630,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EHScopeStack::Cleanup *Fn = reinterpret_cast<EHScopeStack::Cleanup*>(CleanupBuffer.data()); - // We want to emit the EH cleanup after the normal cleanup, but go - // ahead and do the setup for the EH cleanup while the scope is still - // alive. - llvm::BasicBlock *EHEntry = 0; - llvm::SmallVector<llvm::Instruction*, 2> EHInstsToAppend; - if (RequiresEHCleanup) { - EHEntry = CreateEHEntry(*this, Scope); - - // Figure out the branch-through dest if necessary. - llvm::BasicBlock *EHBranchThroughDest = 0; - if (Scope.hasEHBranchThroughs()) { - assert(Scope.getEnclosingEHCleanup() != EHStack.stable_end()); - EHScope &S = *EHStack.find(Scope.getEnclosingEHCleanup()); - EHBranchThroughDest = CreateEHEntry(*this, cast<EHCleanupScope>(S)); - } - - // If we have exactly one branch-after and no branch-throughs, we - // can dispatch it without a switch. - if (!Scope.hasEHBranchThroughs() && - Scope.getNumEHBranchAfters() == 1) { - assert(!EHBranchThroughDest); - - // TODO: remove the spurious eh.cleanup.dest stores if this edge - // never went through any switches. - llvm::BasicBlock *BranchAfterDest = Scope.getEHBranchAfterBlock(0); - EHInstsToAppend.push_back(llvm::BranchInst::Create(BranchAfterDest)); - - // Otherwise, if we have any branch-afters, we need a switch. - } else if (Scope.getNumEHBranchAfters()) { - // The default of the switch belongs to the branch-throughs if - // they exist. - llvm::BasicBlock *Default = - (EHBranchThroughDest ? EHBranchThroughDest : getUnreachableBlock()); - - const unsigned SwitchCapacity = Scope.getNumEHBranchAfters(); - - llvm::LoadInst *Load = - new llvm::LoadInst(getEHCleanupDestSlot(), "cleanup.dest"); - llvm::SwitchInst *Switch = - llvm::SwitchInst::Create(Load, Default, SwitchCapacity); - - EHInstsToAppend.push_back(Load); - EHInstsToAppend.push_back(Switch); - - for (unsigned I = 0, E = Scope.getNumEHBranchAfters(); I != E; ++I) - Switch->addCase(Scope.getEHBranchAfterIndex(I), - Scope.getEHBranchAfterBlock(I)); - - // Otherwise, we have only branch-throughs; jump to the next EH - // cleanup. - } else { - assert(EHBranchThroughDest); - EHInstsToAppend.push_back(llvm::BranchInst::Create(EHBranchThroughDest)); - } - } + EHScopeStack::Cleanup::Flags cleanupFlags; + if (Scope.isNormalCleanup()) + cleanupFlags.setIsNormalCleanupKind(); + if (Scope.isEHCleanup()) + cleanupFlags.setIsEHCleanupKind(); if (!RequiresNormalCleanup) { + destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); } else { // If we have a fallthrough and no other need for the cleanup, @@ -655,15 +645,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups && !HasExistingBranches) { - // Fixups can cause us to optimistically create a normal block, - // only to later have no real uses for it. Just delete it in - // this case. - // TODO: we can potentially simplify all the uses after this. - if (Scope.getNormalBlock()) { - Scope.getNormalBlock()->replaceAllUsesWith(getUnreachableBlock()); - delete Scope.getNormalBlock(); - } - + destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); @@ -676,18 +658,19 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // I. Set up the fallthrough edge in. + CGBuilderTy::InsertPoint savedInactiveFallthroughIP; + // If there's a fallthrough, we need to store the cleanup // destination index. For fall-throughs this is always zero. if (HasFallthrough) { if (!HasPrebranchedFallthrough) Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot()); - // Otherwise, clear the IP if we don't have fallthrough because - // the cleanup is inactive. We don't need to save it because - // it's still just FallthroughSource. + // Otherwise, save and clear the IP if we don't have fallthrough + // because the cleanup is inactive. } else if (FallthroughSource) { assert(!IsActive && "source without fallthrough for active cleanup"); - Builder.ClearInsertionPoint(); + savedInactiveFallthroughIP = Builder.saveAndClearIP(); } // II. Emit the entry block. This implicitly branches to it if @@ -716,7 +699,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } llvm::BasicBlock *FallthroughDest = 0; - llvm::SmallVector<llvm::Instruction*, 2> InstsToAppend; + SmallVector<llvm::Instruction*, 2> InstsToAppend; // If there's exactly one branch-after and no other threads, // we can route it without a switch. @@ -800,25 +783,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // V. Set up the fallthrough edge out. - // Case 1: a fallthrough source exists but shouldn't branch to - // the cleanup because the cleanup is inactive. + // Case 1: a fallthrough source exists but doesn't branch to the + // cleanup because the cleanup is inactive. if (!HasFallthrough && FallthroughSource) { + // Prebranched fallthrough was forwarded earlier. + // Non-prebranched fallthrough doesn't need to be forwarded. + // Either way, all we need to do is restore the IP we cleared before. assert(!IsActive); - - // If we have a prebranched fallthrough, that needs to be - // forwarded to the right block. - if (HasPrebranchedFallthrough) { - llvm::BasicBlock *Next; - if (FallthroughIsBranchThrough) { - Next = BranchThroughDest; - assert(!FallthroughDest); - } else { - Next = FallthroughDest; - } - - ForwardPrebranchedFallthrough(FallthroughSource, NormalEntry, Next); - } - Builder.SetInsertPoint(FallthroughSource); + Builder.restoreIP(savedInactiveFallthroughIP); // Case 2: a fallthrough source exists and should branch to the // cleanup, but we're not supposed to branch through to the next @@ -864,10 +836,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { cleanupFlags.setIsForEHCleanup(); EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); - // Append the prepared cleanup prologue from above. - llvm::BasicBlock *EHExit = Builder.GetInsertBlock(); - for (unsigned I = 0, E = EHInstsToAppend.size(); I != E; ++I) - EHExit->getInstList().push_back(EHInstsToAppend[I]); + Builder.CreateBr(getEHDispatchBlock(EHParent)); Builder.restoreIP(SavedIP); @@ -979,64 +948,6 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { Builder.ClearInsertionPoint(); } -void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) { - // We should never get invalid scope depths for an UnwindDest; that - // implies that the destination wasn't set up correctly. - assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?"); - - if (!HaveInsertPoint()) - return; - - // Create the branch. - llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); - - // Calculate the innermost active cleanup. - EHScopeStack::stable_iterator - InnermostCleanup = EHStack.getInnermostActiveEHCleanup(); - - // If the destination is in the same EH cleanup scope as us, we - // don't need to thread through anything. - if (InnermostCleanup.encloses(Dest.getScopeDepth())) { - Builder.ClearInsertionPoint(); - return; - } - assert(InnermostCleanup != EHStack.stable_end()); - - // Store the index at the start. - llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); - new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI); - - // Adjust BI to point to the first cleanup block. - { - EHCleanupScope &Scope = - cast<EHCleanupScope>(*EHStack.find(InnermostCleanup)); - BI->setSuccessor(0, CreateEHEntry(*this, Scope)); - } - - // Add this destination to all the scopes involved. - for (EHScopeStack::stable_iterator - I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) { - assert(E.strictlyEncloses(I)); - EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I)); - assert(Scope.isEHCleanup()); - I = Scope.getEnclosingEHCleanup(); - - // If this is the last cleanup we're propagating through, add this - // as a branch-after. - if (I == E) { - Scope.addEHBranchAfter(Index, Dest.getBlock()); - break; - } - - // Otherwise, add it as a branch-through. If this isn't new - // information, all the rest of the work has been done before. - if (!Scope.addEHBranchThrough(Dest.getBlock())) - break; - } - - Builder.ClearInsertionPoint(); -} - static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, EHScopeStack::stable_iterator C) { // If we needed a normal block for any reason, that counts. @@ -1057,18 +968,21 @@ static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, } static bool IsUsedAsEHCleanup(EHScopeStack &EHStack, - EHScopeStack::stable_iterator C) { + EHScopeStack::stable_iterator cleanup) { // If we needed an EH block for any reason, that counts. - if (cast<EHCleanupScope>(*EHStack.find(C)).getEHBlock()) + if (EHStack.find(cleanup)->hasEHBranches()) return true; // Check whether any enclosed cleanups were needed. for (EHScopeStack::stable_iterator - I = EHStack.getInnermostEHCleanup(); I != C; ) { - assert(C.strictlyEncloses(I)); - EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); - if (S.getEHBlock()) return true; - I = S.getEnclosingEHCleanup(); + i = EHStack.getInnermostEHScope(); i != cleanup; ) { + assert(cleanup.strictlyEncloses(i)); + + EHScope &scope = *EHStack.find(i); + if (scope.hasEHBranches()) + return true; + + i = scope.getEnclosingEHScope(); } return false; @@ -1163,10 +1077,3 @@ llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() { CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); return NormalCleanupDest; } - -llvm::Value *CodeGenFunction::getEHCleanupDestSlot() { - if (!EHCleanupDest) - EHCleanupDest = - CreateTempAlloca(Builder.getInt32Ty(), "eh.cleanup.dest.slot"); - return EHCleanupDest; -} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.h index c93ec5b..7726e44 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.h @@ -29,25 +29,102 @@ namespace CodeGen { /// A protected scope for zero-cost EH handling. class EHScope { llvm::BasicBlock *CachedLandingPad; + llvm::BasicBlock *CachedEHDispatchBlock; - unsigned K : 2; + EHScopeStack::stable_iterator EnclosingEHScope; + + class CommonBitFields { + friend class EHScope; + unsigned Kind : 2; + }; + enum { NumCommonBits = 2 }; protected: - enum { BitsRemaining = 30 }; + class CatchBitFields { + friend class EHCatchScope; + unsigned : NumCommonBits; + + unsigned NumHandlers : 32 - NumCommonBits; + }; + + class CleanupBitFields { + friend class EHCleanupScope; + unsigned : NumCommonBits; + + /// Whether this cleanup needs to be run along normal edges. + unsigned IsNormalCleanup : 1; + + /// Whether this cleanup needs to be run along exception edges. + unsigned IsEHCleanup : 1; + + /// Whether this cleanup is currently active. + unsigned IsActive : 1; + + /// Whether the normal cleanup should test the activation flag. + unsigned TestFlagInNormalCleanup : 1; + + /// Whether the EH cleanup should test the activation flag. + unsigned TestFlagInEHCleanup : 1; + + /// The amount of extra storage needed by the Cleanup. + /// Always a multiple of the scope-stack alignment. + unsigned CleanupSize : 12; + + /// The number of fixups required by enclosing scopes (not including + /// this one). If this is the top cleanup scope, all the fixups + /// from this index onwards belong to this scope. + unsigned FixupDepth : 32 - 17 - NumCommonBits; // currently 13 + }; + + class FilterBitFields { + friend class EHFilterScope; + unsigned : NumCommonBits; + + unsigned NumFilters : 32 - NumCommonBits; + }; + + union { + CommonBitFields CommonBits; + CatchBitFields CatchBits; + CleanupBitFields CleanupBits; + FilterBitFields FilterBits; + }; public: enum Kind { Cleanup, Catch, Terminate, Filter }; - EHScope(Kind K) : CachedLandingPad(0), K(K) {} + EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) + : CachedLandingPad(0), CachedEHDispatchBlock(0), + EnclosingEHScope(enclosingEHScope) { + CommonBits.Kind = kind; + } - Kind getKind() const { return static_cast<Kind>(K); } + Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); } llvm::BasicBlock *getCachedLandingPad() const { return CachedLandingPad; } - void setCachedLandingPad(llvm::BasicBlock *Block) { - CachedLandingPad = Block; + void setCachedLandingPad(llvm::BasicBlock *block) { + CachedLandingPad = block; + } + + llvm::BasicBlock *getCachedEHDispatchBlock() const { + return CachedEHDispatchBlock; + } + + void setCachedEHDispatchBlock(llvm::BasicBlock *block) { + CachedEHDispatchBlock = block; + } + + bool hasEHBranches() const { + if (llvm::BasicBlock *block = getCachedEHDispatchBlock()) + return !block->use_empty(); + return false; + } + + EHScopeStack::stable_iterator getEnclosingEHScope() const { + return EnclosingEHScope; } }; @@ -57,8 +134,6 @@ public: /// Objective C @finally blocks are represented using a cleanup scope /// after the catch scope. class EHCatchScope : public EHScope { - unsigned NumHandlers : BitsRemaining; - // In effect, we have a flexible array member // Handler Handlers[0]; // But that's only standard in C99, not C++, so we have to do @@ -73,8 +148,7 @@ public: /// The catch handler for this type. llvm::BasicBlock *Block; - /// The unwind destination index for this handler. - unsigned Index; + bool isCatchAll() const { return Type == 0; } }; private: @@ -93,12 +167,14 @@ public: return sizeof(EHCatchScope) + N * sizeof(Handler); } - EHCatchScope(unsigned NumHandlers) - : EHScope(Catch), NumHandlers(NumHandlers) { + EHCatchScope(unsigned numHandlers, + EHScopeStack::stable_iterator enclosingEHScope) + : EHScope(Catch, enclosingEHScope) { + CatchBits.NumHandlers = numHandlers; } unsigned getNumHandlers() const { - return NumHandlers; + return CatchBits.NumHandlers; } void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) { @@ -127,44 +203,16 @@ public: /// A cleanup scope which generates the cleanup blocks lazily. class EHCleanupScope : public EHScope { - /// Whether this cleanup needs to be run along normal edges. - bool IsNormalCleanup : 1; - - /// Whether this cleanup needs to be run along exception edges. - bool IsEHCleanup : 1; - - /// Whether this cleanup is currently active. - bool IsActive : 1; - - /// Whether the normal cleanup should test the activation flag. - bool TestFlagInNormalCleanup : 1; - - /// Whether the EH cleanup should test the activation flag. - bool TestFlagInEHCleanup : 1; - - /// The amount of extra storage needed by the Cleanup. - /// Always a multiple of the scope-stack alignment. - unsigned CleanupSize : 12; - - /// The number of fixups required by enclosing scopes (not including - /// this one). If this is the top cleanup scope, all the fixups - /// from this index onwards belong to this scope. - unsigned FixupDepth : BitsRemaining - 17; // currently 13 - /// The nearest normal cleanup scope enclosing this one. EHScopeStack::stable_iterator EnclosingNormal; - /// The nearest EH cleanup scope enclosing this one. + /// The nearest EH scope enclosing this one. EHScopeStack::stable_iterator EnclosingEH; /// The dual entry/exit block along the normal edge. This is lazily /// created if needed before the cleanup is popped. llvm::BasicBlock *NormalBlock; - /// The dual entry/exit block along the EH edge. This is lazily - /// created if needed before the cleanup is popped. - llvm::BasicBlock *EHBlock; - /// An optional i1 variable indicating whether this cleanup has been /// activated yet. llvm::AllocaInst *ActiveFlag; @@ -178,17 +226,8 @@ class EHCleanupScope : public EHScope { llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches; /// Normal branch-afters. - llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4> + SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4> BranchAfters; - - /// The destinations of EH branch-afters and branch-throughs. - /// TODO: optimize for the extremely common case of a single - /// branch-through. - llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches; - - /// EH branch-afters. - llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4> - EHBranchAfters; }; mutable struct ExtInfo *ExtInfo; @@ -210,56 +249,64 @@ public: } size_t getAllocatedSize() const { - return sizeof(EHCleanupScope) + CleanupSize; + return sizeof(EHCleanupScope) + CleanupBits.CleanupSize; } - EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive, - unsigned CleanupSize, unsigned FixupDepth, - EHScopeStack::stable_iterator EnclosingNormal, - EHScopeStack::stable_iterator EnclosingEH) - : EHScope(EHScope::Cleanup), - IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), IsActive(IsActive), - TestFlagInNormalCleanup(false), TestFlagInEHCleanup(false), - CleanupSize(CleanupSize), FixupDepth(FixupDepth), - EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), - NormalBlock(0), EHBlock(0), ActiveFlag(0), ExtInfo(0) - { - assert(this->CleanupSize == CleanupSize && "cleanup size overflow"); + EHCleanupScope(bool isNormal, bool isEH, bool isActive, + unsigned cleanupSize, unsigned fixupDepth, + EHScopeStack::stable_iterator enclosingNormal, + EHScopeStack::stable_iterator enclosingEH) + : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal), + NormalBlock(0), ActiveFlag(0), ExtInfo(0) { + CleanupBits.IsNormalCleanup = isNormal; + CleanupBits.IsEHCleanup = isEH; + CleanupBits.IsActive = isActive; + CleanupBits.TestFlagInNormalCleanup = false; + CleanupBits.TestFlagInEHCleanup = false; + CleanupBits.CleanupSize = cleanupSize; + CleanupBits.FixupDepth = fixupDepth; + + assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow"); } ~EHCleanupScope() { delete ExtInfo; } - bool isNormalCleanup() const { return IsNormalCleanup; } + bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; } llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; } - bool isEHCleanup() const { return IsEHCleanup; } - llvm::BasicBlock *getEHBlock() const { return EHBlock; } - void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; } + bool isEHCleanup() const { return CleanupBits.IsEHCleanup; } + llvm::BasicBlock *getEHBlock() const { return getCachedEHDispatchBlock(); } + void setEHBlock(llvm::BasicBlock *BB) { setCachedEHDispatchBlock(BB); } - bool isActive() const { return IsActive; } - void setActive(bool A) { IsActive = A; } + bool isActive() const { return CleanupBits.IsActive; } + void setActive(bool A) { CleanupBits.IsActive = A; } llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; } void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; } - void setTestFlagInNormalCleanup() { TestFlagInNormalCleanup = true; } - bool shouldTestFlagInNormalCleanup() const { return TestFlagInNormalCleanup; } + void setTestFlagInNormalCleanup() { + CleanupBits.TestFlagInNormalCleanup = true; + } + bool shouldTestFlagInNormalCleanup() const { + return CleanupBits.TestFlagInNormalCleanup; + } - void setTestFlagInEHCleanup() { TestFlagInEHCleanup = true; } - bool shouldTestFlagInEHCleanup() const { return TestFlagInEHCleanup; } + void setTestFlagInEHCleanup() { + CleanupBits.TestFlagInEHCleanup = true; + } + bool shouldTestFlagInEHCleanup() const { + return CleanupBits.TestFlagInEHCleanup; + } - unsigned getFixupDepth() const { return FixupDepth; } + unsigned getFixupDepth() const { return CleanupBits.FixupDepth; } EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { return EnclosingNormal; } - EHScopeStack::stable_iterator getEnclosingEHCleanup() const { - return EnclosingEH; - } - size_t getCleanupSize() const { return CleanupSize; } + size_t getCleanupSize() const { return CleanupBits.CleanupSize; } void *getCleanupBuffer() { return this + 1; } EHScopeStack::Cleanup *getCleanup() { @@ -327,41 +374,6 @@ public: return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); } - // Same stuff, only for EH branches instead of normal branches. - // It's quite possible that we could find a better representation - // for this. - - bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); } - void addEHBranchAfter(llvm::ConstantInt *Index, - llvm::BasicBlock *Block) { - struct ExtInfo &ExtInfo = getExtInfo(); - if (ExtInfo.EHBranches.insert(Block)) - ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index)); - } - - unsigned getNumEHBranchAfters() const { - return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0; - } - - llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const { - assert(I < getNumEHBranchAfters()); - return ExtInfo->EHBranchAfters[I].first; - } - - llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const { - assert(I < getNumEHBranchAfters()); - return ExtInfo->EHBranchAfters[I].second; - } - - bool addEHBranchThrough(llvm::BasicBlock *Block) { - return getExtInfo().EHBranches.insert(Block); - } - - bool hasEHBranchThroughs() const { - if (!ExtInfo) return false; - return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size()); - } - static bool classof(const EHScope *Scope) { return (Scope->getKind() == Cleanup); } @@ -373,8 +385,6 @@ public: /// /// This is used to implement C++ exception specifications. class EHFilterScope : public EHScope { - unsigned NumFilters : BitsRemaining; - // Essentially ends in a flexible array member: // llvm::Value *FilterTypes[0]; @@ -387,42 +397,42 @@ class EHFilterScope : public EHScope { } public: - EHFilterScope(unsigned NumFilters) : - EHScope(Filter), NumFilters(NumFilters) {} + EHFilterScope(unsigned numFilters) + : EHScope(Filter, EHScopeStack::stable_end()) { + FilterBits.NumFilters = numFilters; + } - static size_t getSizeForNumFilters(unsigned NumFilters) { - return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*); + static size_t getSizeForNumFilters(unsigned numFilters) { + return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*); } - unsigned getNumFilters() const { return NumFilters; } + unsigned getNumFilters() const { return FilterBits.NumFilters; } - void setFilter(unsigned I, llvm::Value *FilterValue) { - assert(I < getNumFilters()); - getFilters()[I] = FilterValue; + void setFilter(unsigned i, llvm::Value *filterValue) { + assert(i < getNumFilters()); + getFilters()[i] = filterValue; } - llvm::Value *getFilter(unsigned I) const { - assert(I < getNumFilters()); - return getFilters()[I]; + llvm::Value *getFilter(unsigned i) const { + assert(i < getNumFilters()); + return getFilters()[i]; } - static bool classof(const EHScope *Scope) { - return Scope->getKind() == Filter; + static bool classof(const EHScope *scope) { + return scope->getKind() == Filter; } }; /// An exceptions scope which calls std::terminate if any exception /// reaches it. class EHTerminateScope : public EHScope { - unsigned DestIndex : BitsRemaining; public: - EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {} + EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope) + : EHScope(Terminate, enclosingEHScope) {} static size_t getSize() { return sizeof(EHTerminateScope); } - unsigned getDestIndex() const { return DestIndex; } - - static bool classof(const EHScope *Scope) { - return Scope->getKind() == Terminate; + static bool classof(const EHScope *scope) { + return scope->getKind() == Terminate; } }; @@ -498,26 +508,17 @@ inline EHScopeStack::iterator EHScopeStack::end() const { inline void EHScopeStack::popCatch() { assert(!empty() && "popping exception stack when not empty"); - assert(isa<EHCatchScope>(*begin())); - StartOfData += EHCatchScope::getSizeForNumHandlers( - cast<EHCatchScope>(*begin()).getNumHandlers()); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); - CatchDepth--; + EHCatchScope &scope = cast<EHCatchScope>(*begin()); + InnermostEHScope = scope.getEnclosingEHScope(); + StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()); } inline void EHScopeStack::popTerminate() { assert(!empty() && "popping exception stack when not empty"); - assert(isa<EHTerminateScope>(*begin())); + EHTerminateScope &scope = cast<EHTerminateScope>(*begin()); + InnermostEHScope = scope.getEnclosingEHScope(); StartOfData += EHTerminateScope::getSize(); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); - CatchDepth--; } inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { @@ -532,28 +533,6 @@ EHScopeStack::stabilize(iterator ir) const { return stable_iterator(EndOfBuffer - ir.Ptr); } -inline EHScopeStack::stable_iterator -EHScopeStack::getInnermostActiveNormalCleanup() const { - for (EHScopeStack::stable_iterator - I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) { - EHCleanupScope &S = cast<EHCleanupScope>(*find(I)); - if (S.isActive()) return I; - I = S.getEnclosingNormalCleanup(); - } - return stable_end(); -} - -inline EHScopeStack::stable_iterator -EHScopeStack::getInnermostActiveEHCleanup() const { - for (EHScopeStack::stable_iterator - I = getInnermostEHCleanup(), E = stable_end(); I != E; ) { - EHCleanupScope &S = cast<EHCleanupScope>(*find(I)); - if (S.isActive()) return I; - I = S.getEnclosingEHCleanup(); - } - return stable_end(); -} - } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index 4c12445..c7a9b40 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -33,7 +33,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Dwarf.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" using namespace clang; @@ -46,12 +46,46 @@ CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) } CGDebugInfo::~CGDebugInfo() { - assert(RegionStack.empty() && "Region stack mismatch, stack not empty!"); + assert(LexicalBlockStack.empty() && + "Region stack mismatch, stack not empty!"); } void CGDebugInfo::setLocation(SourceLocation Loc) { - if (Loc.isValid()) - CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc); + // If the new location isn't valid return. + if (!Loc.isValid()) return; + + CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); + + // If we've changed files in the middle of a lexical scope go ahead + // and create a new lexical scope with file node if it's different + // from the one in the scope. + if (LexicalBlockStack.empty()) return; + + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); + PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc); + + if (PCLoc.isInvalid() || PPLoc.isInvalid() || + !strcmp(PPLoc.getFilename(), PCLoc.getFilename())) + return; + + llvm::MDNode *LB = LexicalBlockStack.back(); + llvm::DIScope Scope = llvm::DIScope(LB); + if (Scope.isLexicalBlockFile()) { + llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB); + llvm::DIDescriptor D + = DBuilder.createLexicalBlockFile(LBF.getScope(), + getOrCreateFile(CurLoc)); + llvm::MDNode *N = D; + LexicalBlockStack.pop_back(); + LexicalBlockStack.push_back(N); + } else if (Scope.isLexicalBlock()) { + llvm::DIDescriptor D + = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc)); + llvm::MDNode *N = D; + LexicalBlockStack.pop_back(); + LexicalBlockStack.push_back(N); + } } /// getContextDescriptor - Get context info for the decl. @@ -81,7 +115,7 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. -llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { +StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { assert (FD && "Invalid FunctionDecl!"); IdentifierInfo *FII = FD->getIdentifier(); if (FII) @@ -93,10 +127,10 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { // Copy this name on the side and use its reference. char *StrPtr = DebugInfoNames.Allocate<char>(NS.length()); memcpy(StrPtr, NS.data(), NS.length()); - return llvm::StringRef(StrPtr, NS.length()); + return StringRef(StrPtr, NS.length()); } -llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { +StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { llvm::SmallString<256> MethodName; llvm::raw_svector_ostream OS(MethodName); OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; @@ -116,22 +150,20 @@ llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell()); memcpy(StrPtr, MethodName.begin(), OS.tell()); - return llvm::StringRef(StrPtr, OS.tell()); + return StringRef(StrPtr, OS.tell()); } /// getSelectorName - Return selector name. This is used for debugging /// info. -llvm::StringRef CGDebugInfo::getSelectorName(Selector S) { - llvm::SmallString<256> SName; - llvm::raw_svector_ostream OS(SName); - OS << S.getAsString(); - char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell()); - memcpy(StrPtr, SName.begin(), OS.tell()); - return llvm::StringRef(StrPtr, OS.tell()); +StringRef CGDebugInfo::getSelectorName(Selector S) { + const std::string &SName = S.getAsString(); + char *StrPtr = DebugInfoNames.Allocate<char>(SName.size()); + memcpy(StrPtr, SName.data(), SName.size()); + return StringRef(StrPtr, SName.size()); } /// getClassName - Get class name including template argument list. -llvm::StringRef +StringRef CGDebugInfo::getClassName(RecordDecl *RD) { ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD); @@ -160,7 +192,7 @@ CGDebugInfo::getClassName(RecordDecl *RD) { // Copy this name on the side and use its reference. char *StrPtr = DebugInfoNames.Allocate<char>(Buffer.length()); memcpy(StrPtr, Buffer.data(), Buffer.length()); - return llvm::StringRef(StrPtr, Buffer.length()); + return StringRef(StrPtr, Buffer.length()); } /// getOrCreateFile - Get the file debug info descriptor for the input location. @@ -172,7 +204,7 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); - if (PLoc.isInvalid() || llvm::StringRef(PLoc.getFilename()).empty()) + if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty()) // If the location is not valid then use main input file. return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); @@ -202,7 +234,7 @@ llvm::DIFile CGDebugInfo::getOrCreateMainFile() { /// getLineNumber - Get line number for the location. If location is invalid /// then use current location. unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { - assert (CurLoc.isValid() && "Invalid current location!"); + assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!"); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); return PLoc.isValid()? PLoc.getLine() : 0; @@ -211,20 +243,20 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { /// getColumnNumber - Get column number for the location. If location is /// invalid then use current location. unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { - assert (CurLoc.isValid() && "Invalid current location!"); + assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!"); SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); return PLoc.isValid()? PLoc.getColumn() : 0; } -llvm::StringRef CGDebugInfo::getCurrentDirname() { +StringRef CGDebugInfo::getCurrentDirname() { if (!CWDName.empty()) return CWDName; - char *CompDirnamePtr = NULL; - llvm::sys::Path CWD = llvm::sys::Path::GetCurrentDirectory(); - CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size()); - memcpy(CompDirnamePtr, CWD.c_str(), CWD.size()); - return CWDName = llvm::StringRef(CompDirnamePtr, CWD.size()); + llvm::SmallString<256> CWD; + llvm::sys::fs::current_path(CWD); + char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size()); + memcpy(CompDirnamePtr, CWD.data(), CWD.size()); + return CWDName = StringRef(CompDirnamePtr, CWD.size()); } /// CreateCompileUnit - Create new compile unit. @@ -250,7 +282,7 @@ void CGDebugInfo::CreateCompileUnit() { // Save filename string. char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length()); memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length()); - llvm::StringRef Filename(FilenamePtr, MainFileName.length()); + StringRef Filename(FilenamePtr, MainFileName.length()); unsigned LangTag; const LangOptions &LO = CGM.getLangOptions(); @@ -289,7 +321,17 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { unsigned Encoding = 0; const char *BTName = NULL; switch (BT->getKind()) { - default: + case BuiltinType::Dependent: + llvm_unreachable("Unexpected builtin type Dependent"); + case BuiltinType::Overload: + llvm_unreachable("Unexpected builtin type Overload"); + case BuiltinType::BoundMember: + llvm_unreachable("Unexpected builtin type BoundMember"); + case BuiltinType::UnknownAny: + llvm_unreachable("Unexpected builtin type UnknownAny"); + case BuiltinType::NullPtr: + return DBuilder. + createNullPtrType(BT->getName(CGM.getContext().getLangOptions())); case BuiltinType::Void: return llvm::DIType(); case BuiltinType::ObjCClass: @@ -312,7 +354,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size); - llvm::SmallVector<llvm::Value *, 16> EltTys; + SmallVector<llvm::Value *, 16> EltTys; llvm::DIType FieldTy = DBuilder.createMemberType(getOrCreateMainFile(), "isa", getOrCreateMainFile(), 0, Size, @@ -334,17 +376,22 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; case BuiltinType::Char_S: case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break; + case BuiltinType::Char16: + case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break; case BuiltinType::UShort: case BuiltinType::UInt: case BuiltinType::UInt128: case BuiltinType::ULong: + case BuiltinType::WChar_U: case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break; case BuiltinType::Short: case BuiltinType::Int: case BuiltinType::Int128: case BuiltinType::Long: + case BuiltinType::WChar_S: case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::LongDouble: case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; @@ -432,7 +479,7 @@ llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, Ty->getPointeeType(), Unit); } -/// CreatePointeeType - Create PointTee type. If Pointee is a record +/// CreatePointeeType - Create Pointee type. If Pointee is a record /// then emit record's fwd if debug info size reduction is enabled. llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy, llvm::DIFile Unit) { @@ -477,7 +524,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().Target.getPointerWidth(AS); + uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(Ty); return @@ -489,7 +536,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, if (BlockLiteralGenericSet) return BlockLiteralGeneric; - llvm::SmallVector<llvm::Value *, 8> EltTys; + SmallVector<llvm::Value *, 8> EltTys; llvm::DIType FieldTy; QualType FType; uint64_t FieldSize, FieldOffset; @@ -567,7 +614,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIFile Unit) { - llvm::SmallVector<llvm::Value *, 16> EltTys; + SmallVector<llvm::Value *, 16> EltTys; // Add the result type at least. EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit)); @@ -587,9 +634,9 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, return DbgTy; } -llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name, +llvm::DIType CGDebugInfo::createFieldType(StringRef name, QualType type, - Expr *bitWidth, + uint64_t sizeInBitsOverride, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, @@ -606,8 +653,8 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name, if (!type->isIncompleteArrayType()) { llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type); - if (bitWidth) - sizeInBits = bitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); + if (sizeInBitsOverride) + sizeInBits = sizeInBitsOverride; } unsigned flags = 0; @@ -624,7 +671,7 @@ llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name, /// record fields. This is used while creating debug info entry for a Record. void CGDebugInfo:: CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, - llvm::SmallVectorImpl<llvm::Value *> &elements, + SmallVectorImpl<llvm::Value *> &elements, llvm::DIType RecordTy) { unsigned fieldNo = 0; const FieldDecl *LastFD = 0; @@ -644,7 +691,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, LastFD = field; } - llvm::StringRef name = field->getName(); + StringRef name = field->getName(); QualType type = field->getType(); // Ignore unnamed fields unless they're anonymous structs/unions. @@ -653,8 +700,14 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, continue; } + uint64_t SizeInBitsOverride = 0; + if (field->isBitField()) { + SizeInBitsOverride = field->getBitWidthValue(CGM.getContext()); + assert(SizeInBitsOverride && "found named 0-width bitfield"); + } + llvm::DIType fieldType - = createFieldType(name, type, field->getBitWidth(), + = createFieldType(name, type, SizeInBitsOverride, field->getLocation(), field->getAccess(), layout.getFieldOffset(fieldNo), tunit, RecordTy); @@ -674,25 +727,23 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, Unit); // Add "this" pointer. - llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray(); assert (Args.getNumElements() && "Invalid number of arguments!"); - llvm::SmallVector<llvm::Value *, 16> Elts; + SmallVector<llvm::Value *, 16> Elts; // First element is always return type. For 'void' functions it is NULL. Elts.push_back(Args.getElement(0)); - if (!Method->isStatic()) - { - // "this" pointer is always first argument. - QualType ThisPtr = Method->getThisType(CGM.getContext()); - llvm::DIType ThisPtrType = - DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit)); - - TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; - Elts.push_back(ThisPtrType); - } + if (!Method->isStatic()) { + // "this" pointer is always first argument. + QualType ThisPtr = Method->getThisType(CGM.getContext()); + llvm::DIType ThisPtrType = + DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit)); + + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; + Elts.push_back(ThisPtrType); + } // Copy rest of the arguments. for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) @@ -723,12 +774,12 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, bool IsCtorOrDtor = isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); - llvm::StringRef MethodName = getFunctionName(Method); + StringRef MethodName = getFunctionName(Method); llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit); // Since a single ctor/dtor corresponds to multiple functions, it doesn't // make sense to give a single ctor/dtor a linkage name. - llvm::StringRef MethodLinkageName; + StringRef MethodLinkageName; if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) MethodLinkageName = CGM.getMangledName(Method); @@ -750,7 +801,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa<CXXDestructorDecl>(Method)) - VIndex = CGM.getVTables().getMethodVTableIndex(Method); + VIndex = CGM.getVTableContext().getMethodVTableIndex(Method); ContainingType = RecordTy; } @@ -774,7 +825,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, Flags |= llvm::DIDescriptor::FlagPrototyped; llvm::DISubprogram SP = - DBuilder.createMethod(RecordTy , MethodName, MethodLinkageName, + DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, MethodTy, /*isLocalToUnit=*/false, /* isDefinition=*/ false, @@ -791,7 +842,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, /// a Record. void CGDebugInfo:: CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, - llvm::SmallVectorImpl<llvm::Value *> &EltTys, + SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy) { for(CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { @@ -809,11 +860,12 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, /// a Record. void CGDebugInfo:: CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit, - llvm::SmallVectorImpl<llvm::Value *> &EltTys, + SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy) { - for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(), BE = RD->friend_end(); BI != BE; ++BI) { + if ((*BI)->isUnsupportedFriend()) + continue; if (TypeSourceInfo *TInfo = (*BI)->getFriendType()) EltTys.push_back(DBuilder.createFriend(RecordTy, getOrCreateType(TInfo->getType(), @@ -826,7 +878,7 @@ CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit, /// a Record. void CGDebugInfo:: CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, - llvm::SmallVectorImpl<llvm::Value *> &EltTys, + SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -842,7 +894,8 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. BaseOffset = - 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base).getQuantity(); + 0 - CGM.getVTableContext() + .getVirtualBaseOffsetOffset(RD, Base).getQuantity(); BFlags = llvm::DIDescriptor::FlagVirtual; } else BaseOffset = RL.getBaseClassOffsetInBits(Base); @@ -868,7 +921,7 @@ llvm::DIArray CGDebugInfo:: CollectTemplateParams(const TemplateParameterList *TPList, const TemplateArgumentList &TAList, llvm::DIFile Unit) { - llvm::SmallVector<llvm::Value *, 16> TemplateParams; + SmallVector<llvm::Value *, 16> TemplateParams; for (unsigned i = 0, e = TAList.size(); i != e; ++i) { const TemplateArgument &TA = TAList[i]; const NamedDecl *ND = TPList->getParam(i); @@ -892,9 +945,11 @@ CollectTemplateParams(const TemplateParameterList *TPList, /// info for function template parameters. llvm::DIArray CGDebugInfo:: CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) { - if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization){ + if (FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { const TemplateParameterList *TList = - FD->getTemplateSpecializationInfo()->getTemplate()->getTemplateParameters(); + FD->getTemplateSpecializationInfo()->getTemplate() + ->getTemplateParameters(); return CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit); } @@ -936,14 +991,14 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { } /// getVTableName - Get vtable name for the given Class. -llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { +StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Otherwise construct gdb compatible name name. std::string Name = "_vptr$" + RD->getNameAsString(); // Copy this name on the side and use its reference. char *StrPtr = DebugInfoNames.Allocate<char>(Name.length()); memcpy(StrPtr, Name.data(), Name.length()); - return llvm::StringRef(StrPtr, Name.length()); + return StringRef(StrPtr, Name.length()); } @@ -951,7 +1006,7 @@ llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { /// debug info entry in EltTys vector. void CGDebugInfo:: CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, - llvm::SmallVectorImpl<llvm::Value *> &EltTys) { + SmallVectorImpl<llvm::Value *> &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); // If there is a primary base then it will hold vtable info. @@ -1016,11 +1071,11 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Push the struct on region stack. - RegionStack.push_back(FwdDeclNode); + LexicalBlockStack.push_back(FwdDeclNode); RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); // Convert all the elements. - llvm::SmallVector<llvm::Value *, 16> EltTys; + SmallVector<llvm::Value *, 16> EltTys; const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); if (CXXDecl) { @@ -1040,7 +1095,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { // Create the descriptor for static variable. llvm::DIFile VUnit = getOrCreateFile(V->getLocation()); - llvm::StringRef VName = V->getName(); + StringRef VName = V->getName(); llvm::DIType VTy = getOrCreateType(V->getType(), VUnit); // Do not use DIGlobalVariable for enums. if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) { @@ -1062,7 +1117,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { TParamsArray = CollectCXXTemplateParams(TSpecial, Unit); } - RegionStack.pop_back(); + LexicalBlockStack.pop_back(); llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = RegionMap.find(Ty->getDecl()); if (RI != RegionMap.end()) @@ -1070,7 +1125,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { llvm::DIDescriptor RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext())); - llvm::StringRef RDName = RD->getName(); + StringRef RDName = RD->getName(); uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); @@ -1134,8 +1189,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, unsigned Line = getLineNumber(ID->getLocation()); unsigned RuntimeLang = TheCU.getLanguage(); - // If this is just a forward declaration, return a special forward-declaration - // debug type. + // If this is just a forward declaration return a special forward-declaration + // debug type since we won't be able to lay out the entire type. if (ID->isForwardDecl()) { llvm::DIType FwdDecl = DBuilder.createStructType(Unit, ID->getName(), @@ -1144,12 +1199,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, return FwdDecl; } - // To handle recursive interface, we - // first generate a debug descriptor for the struct as a forward declaration. - // Then (if it is a definition) we go through and get debug info for all of - // its members. Finally, we create a descriptor for the complete type (which - // may refer to the forward decl if the struct is recursive) and replace all - // uses of the forward declaration with the final definition. + // To handle a recursive interface, we first generate a debug descriptor + // for the struct as a forward declaration. Then (if it is a definition) + // we go through and get debug info for all of its members. Finally, we + // create a descriptor for the complete type (which may refer to the + // forward decl if the struct is recursive) and replace all uses of the + // forward declaration with the final definition. llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit); llvm::MDNode *MN = FwdDecl; @@ -1158,11 +1213,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Push the struct on region stack. - RegionStack.push_back(FwdDeclNode); + LexicalBlockStack.push_back(FwdDeclNode); RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); // Convert all the elements. - llvm::SmallVector<llvm::Value *, 16> EltTys; + SmallVector<llvm::Value *, 16> EltTys; ObjCInterfaceDecl *SClass = ID->getSuperClass(); if (SClass) { @@ -1177,7 +1232,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, } const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID); - + ObjCImplementationDecl *ImpD = ID->getImplementation(); unsigned FieldNo = 0; for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field; Field = Field->getNextIvar(), ++FieldNo) { @@ -1185,7 +1240,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!FieldTy.isValid()) return llvm::DIType(); - llvm::StringRef FieldName = Field->getName(); + StringRef FieldName = Field->getName(); // Ignore unnamed fields. if (FieldName.empty()) @@ -1201,15 +1256,18 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = CGM.getContext().getTypeSize(FType); - Expr *BitWidth = Field->getBitWidth(); - if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - - FieldAlign = CGM.getContext().getTypeAlign(FType); + FieldSize = Field->isBitField() + ? Field->getBitWidthValue(CGM.getContext()) + : CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } - uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + // We can't know the offset of our ivar in the structure if we're using + // the non-fragile abi and the debugger should ignore the value anyways. + // Call it the FieldNo+1 due to how debuggers use the information, + // e.g. negating the value when it needs a lookup in the dynamic table. + uint64_t FieldOffset = CGM.getLangOptions().ObjCNonFragileABI ? FieldNo+1 + : RL.getFieldOffset(FieldNo); unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) @@ -1217,17 +1275,21 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DIDescriptor::FlagPrivate; - llvm::StringRef PropertyName; - llvm::StringRef PropertyGetter; - llvm::StringRef PropertySetter; + StringRef PropertyName; + StringRef PropertyGetter; + StringRef PropertySetter; unsigned PropertyAttributes = 0; - if (ObjCPropertyDecl *PD = - ID->FindPropertyVisibleInPrimaryClass(Field->getIdentifier())) { + ObjCPropertyDecl *PD = NULL; + if (ImpD) + if (ObjCPropertyImplDecl *PImpD = + ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) + PD = PImpD->getPropertyDecl(); + if (PD) { PropertyName = PD->getName(); PropertyGetter = getSelectorName(PD->getGetterName()); PropertySetter = getSelectorName(PD->getSetterName()); PropertyAttributes = PD->getPropertyAttributes(); - } + } FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, FieldOffset, Flags, FieldTy, @@ -1238,7 +1300,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - RegionStack.pop_back(); + LexicalBlockStack.pop_back(); llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = RegionMap.find(Ty->getDecl()); if (RI != RegionMap.end()) @@ -1322,7 +1384,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, // Add the dimensions of the array. FIXME: This loses CV qualifiers from // interior arrays, do we care? Why aren't nested arrays represented the // obvious/recursive way? - llvm::SmallVector<llvm::Value *, 8> Subscripts; + SmallVector<llvm::Value *, 8> Subscripts; QualType EltTy(Ty, 0); if (Ty->isIncompleteArrayType()) EltTy = Ty->getElementType(); @@ -1339,7 +1401,8 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, LowerBound = 1; // FIXME: Verify this is right for VLAs. - Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound, UpperBound)); + Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound, + UpperBound)); EltTy = Ty->getElementType(); } } @@ -1395,15 +1458,22 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes); - return DBuilder.createStructType(U, llvm::StringRef("test"), + return DBuilder.createStructType(U, StringRef("test"), U, 0, FieldOffset, 0, 0, Elements); } +llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, + llvm::DIFile U) { + // Ignore the atomic wrapping + // FIXME: What is the correct representation? + return getOrCreateType(Ty->getValueType(), U); +} + /// CreateEnumType - get enumeration type. llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { llvm::DIFile Unit = getOrCreateFile(ED->getLocation()); - llvm::SmallVector<llvm::Value *, 16> Enumerators; + SmallVector<llvm::Value *, 16> Enumerators; // Create DIEnumerator elements for each enumerator. for (EnumDecl::enumerator_iterator @@ -1522,7 +1592,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Dependent types cannot show up in debug information"); + llvm_unreachable("Dependent types cannot show up in debug information"); case Type::ExtVector: case Type::Vector: @@ -1558,6 +1628,9 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast<MemberPointerType>(Ty), Unit); + case Type::Atomic: + return CreateType(cast<AtomicType>(Ty), Unit); + case Type::Attributed: case Type::TemplateSpecialization: case Type::Elaborated: @@ -1573,7 +1646,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, } assert(Diag && "Fall through without a diagnostic?"); - unsigned DiagID = CGM.getDiags().getCustomDiagID(Diagnostic::Error, + unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error, "debug information for %0 is not yet supported"); CGM.getDiags().Report(DiagID) << Diag; @@ -1582,7 +1655,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, /// CreateMemberType - Create new member and increase Offset by FType's size. llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, - llvm::StringRef Name, + StringRef Name, uint64_t *Offset) { llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); uint64_t FieldSize = CGM.getContext().getTypeSize(FType); @@ -1627,13 +1700,14 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { // getOrCreateFunctionType - Construct DIType. If it is a c++ method, include // implicit parameter "this". -llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnType, +llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, + QualType FnType, llvm::DIFile F) { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) return getOrCreateMethodType(Method, F); else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) { // Add "self" and "_cmd" - llvm::SmallVector<llvm::Value *, 16> Elts; + SmallVector<llvm::Value *, 16> Elts; // First element is always return type. For 'void' functions it is NULL. Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); @@ -1642,7 +1716,7 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnTyp // "cmd" pointer is always second argument. Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F)); // Get rest of the arguments. - for (ObjCMethodDecl::param_iterator PI = OMethod->param_begin(), + for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(), PE = OMethod->param_end(); PI != PE; ++PI) Elts.push_back(getOrCreateType((*PI)->getType(), F)); @@ -1658,13 +1732,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { - llvm::StringRef Name; - llvm::StringRef LinkageName; + StringRef Name; + StringRef LinkageName; - FnBeginRegionCount.push_back(RegionStack.size()); + FnBeginRegionCount.push_back(LexicalBlockStack.size()); const Decl *D = GD.getDecl(); - + unsigned Flags = 0; llvm::DIFile Unit = getOrCreateFile(CurLoc); llvm::DIDescriptor FDContext(Unit); @@ -1677,7 +1751,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(&*FI->second)); if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) { llvm::MDNode *SPN = SP; - RegionStack.push_back(SPN); + LexicalBlockStack.push_back(SPN); RegionMap[D] = llvm::WeakVH(SP); return; } @@ -1687,7 +1761,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, if (!Fn->hasInternalLinkage()) LinkageName = CGM.getMangledName(GD); if (LinkageName == Name) - LinkageName = llvm::StringRef(); + LinkageName = StringRef(); if (FD->hasPrototype()) Flags |= llvm::DIDescriptor::FlagPrototyped; if (const NamespaceDecl *NSDecl = @@ -1726,121 +1800,85 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, // Push function on region stack. llvm::MDNode *SPN = SP; - RegionStack.push_back(SPN); + LexicalBlockStack.push_back(SPN); RegionMap[D] = llvm::WeakVH(SP); - - // Clear stack used to keep track of #line directives. - LineDirectiveFiles.clear(); } +/// EmitLocation - Emit metadata to indicate a change in line/column +/// information in the source file. +void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { + + // Update our current location + setLocation(Loc); -void CGDebugInfo::EmitStopPoint(CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. SourceManager &SM = CGM.getContext().getSourceManager(); - if (CurLoc == PrevLoc - || (SM.getInstantiationLineNumber(CurLoc) == - SM.getInstantiationLineNumber(PrevLoc) - && SM.isFromSameFile(CurLoc, PrevLoc))) + if (CurLoc == PrevLoc || + SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc)) // New Builder may not be in sync with CGDebugInfo. if (!Builder.getCurrentDebugLocation().isUnknown()) return; - + // Update last state. PrevLoc = CurLoc; - llvm::MDNode *Scope = RegionStack.back(); + llvm::MDNode *Scope = LexicalBlockStack.back(); Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope)); } -/// UpdateLineDirectiveRegion - Update region stack only if #line directive -/// has introduced scope change. -void CGDebugInfo::UpdateLineDirectiveRegion(CGBuilderTy &Builder) { - if (CurLoc.isInvalid() || CurLoc.isMacroID() || - PrevLoc.isInvalid() || PrevLoc.isMacroID()) - return; - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); - PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc); - - if (PCLoc.isInvalid() || PPLoc.isInvalid() || - !strcmp(PPLoc.getFilename(), PCLoc.getFilename())) - return; - - // If #line directive stack is empty then we are entering a new scope. - if (LineDirectiveFiles.empty()) { - EmitRegionStart(Builder); - LineDirectiveFiles.push_back(PCLoc.getFilename()); - return; - } - - assert (RegionStack.size() >= LineDirectiveFiles.size() - && "error handling #line regions!"); - - bool SeenThisFile = false; - // Chek if current file is already seen earlier. - for(std::vector<const char *>::iterator I = LineDirectiveFiles.begin(), - E = LineDirectiveFiles.end(); I != E; ++I) - if (!strcmp(PCLoc.getFilename(), *I)) { - SeenThisFile = true; - break; - } +/// CreateLexicalBlock - Creates a new lexical block node and pushes it on +/// the stack. +void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { + llvm::DIDescriptor D = + DBuilder.createLexicalBlock(LexicalBlockStack.empty() ? + llvm::DIDescriptor() : + llvm::DIDescriptor(LexicalBlockStack.back()), + getOrCreateFile(CurLoc), + getLineNumber(CurLoc), + getColumnNumber(CurLoc)); + llvm::MDNode *DN = D; + LexicalBlockStack.push_back(DN); +} - // If #line for this file is seen earlier then pop out #line regions. - if (SeenThisFile) { - while (!LineDirectiveFiles.empty()) { - const char *LastFile = LineDirectiveFiles.back(); - RegionStack.pop_back(); - LineDirectiveFiles.pop_back(); - if (!strcmp(PPLoc.getFilename(), LastFile)) - break; - } - return; - } +/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative +/// region - beginning of a DW_TAG_lexical_block. +void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { + // Set our current location. + setLocation(Loc); - // .. otherwise insert new #line region. - EmitRegionStart(Builder); - LineDirectiveFiles.push_back(PCLoc.getFilename()); + // Create a new lexical block and push it on the stack. + CreateLexicalBlock(Loc); - return; -} -/// EmitRegionStart- Constructs the debug code for entering a declarative -/// region - "llvm.dbg.region.start.". -void CGDebugInfo::EmitRegionStart(CGBuilderTy &Builder) { - llvm::DIDescriptor D = - DBuilder.createLexicalBlock(RegionStack.empty() ? - llvm::DIDescriptor() : - llvm::DIDescriptor(RegionStack.back()), - getOrCreateFile(CurLoc), - getLineNumber(CurLoc), - getColumnNumber(CurLoc)); - llvm::MDNode *DN = D; - RegionStack.push_back(DN); + // Emit a line table change for the current location inside the new scope. + Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc), + getColumnNumber(Loc), + LexicalBlockStack.back())); } -/// EmitRegionEnd - Constructs the debug code for exiting a declarative -/// region - "llvm.dbg.region.end." -void CGDebugInfo::EmitRegionEnd(CGBuilderTy &Builder) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); +/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative +/// region - end of a DW_TAG_lexical_block. +void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); - // Provide an region stop point. - EmitStopPoint(Builder); + // Provide an entry in the line table for the end of the block. + EmitLocation(Builder, Loc); - RegionStack.pop_back(); + LexicalBlockStack.pop_back(); } /// EmitFunctionEnd - Constructs the debug code for exiting a function. void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); unsigned RCount = FnBeginRegionCount.back(); - assert(RCount <= RegionStack.size() && "Region stack mismatch"); + assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch"); // Pop all regions for this function. - while (RegionStack.size() != RCount) - EmitRegionEnd(Builder); + while (LexicalBlockStack.size() != RCount) + EmitLexicalBlockEnd(Builder, CurLoc); FnBeginRegionCount.pop_back(); } @@ -1849,7 +1887,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, uint64_t *XOffset) { - llvm::SmallVector<llvm::Value *, 5> EltTys; + SmallVector<llvm::Value *, 5> EltTys; QualType FType; uint64_t FieldSize, FieldOffset; unsigned FieldAlign; @@ -1876,7 +1914,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( - CGM.getContext().Target.getPointerAlign(0))) { + CGM.getContext().getTargetInfo().getPointerAlign(0))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes @@ -1916,7 +1954,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Value *Storage, unsigned ArgNo, CGBuilderTy &Builder) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); llvm::DIType Ty; @@ -1940,7 +1978,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, // If an aggregate variable has non trivial destructor or non trivial copy // constructor than it is pass indirectly. Let debug info know about this // by using reference of the aggregate type as a argument type. - if (!Record->hasTrivialCopyConstructor() || !Record->hasTrivialDestructor()) + if (!Record->hasTrivialCopyConstructor() || + !Record->hasTrivialDestructor()) Ty = DBuilder.createReferenceType(Ty); } } @@ -1951,18 +1990,18 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, unsigned Flags = 0; if (VD->isImplicit()) Flags |= llvm::DIDescriptor::FlagArtificial; - llvm::MDNode *Scope = RegionStack.back(); + llvm::MDNode *Scope = LexicalBlockStack.back(); - llvm::StringRef Name = VD->getName(); + StringRef Name = VD->getName(); if (!Name.empty()) { if (VD->hasAttr<BlocksAttr>()) { CharUnits offset = CharUnits::fromQuantity(32); - llvm::SmallVector<llvm::Value *, 9> addr; - const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); + SmallVector<llvm::Value *, 9> addr; + llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( - CGM.getContext().Target.getPointerWidth(0)); + CGM.getContext().getTargetInfo().getPointerWidth(0)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); @@ -1973,14 +2012,14 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, // Create the descriptor for the variable. llvm::DIVariable D = DBuilder.createComplexVariable(Tag, - llvm::DIDescriptor(RegionStack.back()), + llvm::DIDescriptor(Scope), VD->getName(), Unit, Line, Ty, addr, ArgNo); // Insert an llvm.dbg.declare into the current block. + // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); return; } @@ -1993,7 +2032,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); return; } @@ -2008,7 +2046,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, I != E; ++I) { FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - llvm::StringRef FieldName = Field->getName(); + StringRef FieldName = Field->getName(); // Ignore unnamed fields. Do not ignore unnamed records. if (FieldName.empty() && !isa<RecordType>(Field->getType())) @@ -2024,7 +2062,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); } } @@ -2040,7 +2077,7 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (Builder.GetInsertBlock() == 0) return; @@ -2065,15 +2102,16 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( target.getStructLayout(blockInfo.StructureType) ->getElementOffset(blockInfo.getCapture(VD).getIndex())); - llvm::SmallVector<llvm::Value *, 9> addr; - const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); + SmallVector<llvm::Value *, 9> addr; + llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); if (isByRef) { addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field - offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits()); + offset = CGM.getContext() + .toCharUnitsFromBits(target.getPointerSizeInBits()); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); @@ -2085,14 +2123,13 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( // Create the descriptor for the variable. llvm::DIVariable D = DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable, - llvm::DIDescriptor(RegionStack.back()), + llvm::DIDescriptor(LexicalBlockStack.back()), VD->getName(), Unit, Line, Ty, addr); // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = + llvm::Instruction *Call = DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint()); - - llvm::MDNode *Scope = RegionStack.back(); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); + Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, + LexicalBlockStack.back())); } /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument @@ -2131,7 +2168,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, const llvm::StructLayout *blockLayout = CGM.getTargetData().getStructLayout(block.StructureType); - llvm::SmallVector<llvm::Value*, 16> fields; + SmallVector<llvm::Value*, 16> fields; fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public, blockLayout->getElementOffsetInBits(0), tunit, tunit)); @@ -2154,7 +2191,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, // We want to sort the captures by offset, not because DWARF // requires this, but because we're paranoid about debuggers. - llvm::SmallVector<BlockLayoutChunk, 8> chunks; + SmallVector<BlockLayoutChunk, 8> chunks; // 'this' capture. if (blockDecl->capturesCXXThis()) { @@ -2187,7 +2224,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, // Sort by offset. llvm::array_pod_sort(chunks.begin(), chunks.end()); - for (llvm::SmallVectorImpl<BlockLayoutChunk>::iterator + for (SmallVectorImpl<BlockLayoutChunk>::iterator i = chunks.begin(), e = chunks.end(); i != e; ++i) { uint64_t offsetInBits = i->OffsetInBits; const BlockDecl::Capture *capture = i->Capture; @@ -2204,7 +2241,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, } const VarDecl *variable = capture->getVariable(); - llvm::StringRef name = variable->getName(); + StringRef name = variable->getName(); llvm::DIType fieldType; if (capture->isByRef()) { @@ -2239,8 +2276,8 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, // Get overall information about the block. unsigned flags = llvm::DIDescriptor::FlagArtificial; - llvm::MDNode *scope = RegionStack.back(); - llvm::StringRef name = ".block_descriptor"; + llvm::MDNode *scope = LexicalBlockStack.back(); + StringRef name = ".block_descriptor"; // Create the descriptor for the parameter. llvm::DIVariable debugVar = @@ -2265,6 +2302,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, llvm::DIFile Unit = getOrCreateFile(D->getLocation()); unsigned LineNo = getLineNumber(D->getLocation()); + setLocation(D->getLocation()); + QualType T = D->getType(); if (T->isIncompleteArrayType()) { @@ -2277,13 +2316,13 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = D->getName(); - llvm::StringRef LinkageName; + StringRef DeclName = D->getName(); + StringRef LinkageName; if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) && !isa<ObjCMethodDecl>(D->getDeclContext())) LinkageName = Var->getName(); if (LinkageName == DeclName) - LinkageName = llvm::StringRef(); + LinkageName = StringRef(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast<Decl>(D->getDeclContext())); DBuilder.createStaticVariable(DContext, DeclName, LinkageName, @@ -2298,7 +2337,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, llvm::DIFile Unit = getOrCreateFile(ID->getLocation()); unsigned LineNo = getLineNumber(ID->getLocation()); - llvm::StringRef Name = ID->getName(); + StringRef Name = ID->getName(); QualType T = CGM.getContext().getObjCInterfaceType(ID); if (T->isIncompleteArrayType()) { @@ -2323,7 +2362,7 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init) { // Create the descriptor for the variable. llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); - llvm::StringRef Name = VD->getName(); + StringRef Name = VD->getName(); llvm::DIType Ty = getOrCreateType(VD->getType(), Unit); if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) { if (const EnumDecl *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h index f87d007..a4533a8 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h @@ -56,21 +56,18 @@ class CGDebugInfo { bool BlockLiteralGenericSet; llvm::DIType BlockLiteralGeneric; - std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack; + // LexicalBlockStack - Keep track of our current nested lexical block. + std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack; llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap; - // FnBeginRegionCount - Keep track of RegionStack counter at the beginning - // of a function. This is used to pop unbalanced regions at the end of a - // function. + // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the + // beginning of a function. This is used to pop unbalanced regions at + // the end of a function. std::vector<unsigned> FnBeginRegionCount; - /// LineDirectiveFiles - This stack is used to keep track of - /// scopes introduced by #line directives. - std::vector<const char *> LineDirectiveFiles; - /// DebugInfoNames - This is a storage for names that are /// constructed on demand. For example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; - llvm::StringRef CWDName; + StringRef CWDName; llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; @@ -95,6 +92,7 @@ class CGDebugInfo { llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F); llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); + llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); llvm::DIType CreateEnumType(const EnumDecl *ED); llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile F); @@ -113,17 +111,17 @@ class CGDebugInfo { void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile F, - llvm::SmallVectorImpl<llvm::Value *> &E, + SmallVectorImpl<llvm::Value *> &E, llvm::DIType T); void CollectCXXFriends(const CXXRecordDecl *Decl, llvm::DIFile F, - llvm::SmallVectorImpl<llvm::Value *> &EltTys, + SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy); void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile F, - llvm::SmallVectorImpl<llvm::Value *> &EltTys, + SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy); llvm::DIArray @@ -136,30 +134,35 @@ class CGDebugInfo { CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, llvm::DIFile F); - llvm::DIType createFieldType(llvm::StringRef name, QualType type, - Expr *bitWidth, SourceLocation loc, + llvm::DIType createFieldType(StringRef name, QualType type, + uint64_t sizeInBitsOverride, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, llvm::DIFile tunit, llvm::DIDescriptor scope); void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, - llvm::SmallVectorImpl<llvm::Value *> &E, + SmallVectorImpl<llvm::Value *> &E, llvm::DIType RecordTy); void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile F, - llvm::SmallVectorImpl<llvm::Value *> &EltTys); + SmallVectorImpl<llvm::Value *> &EltTys); + // CreateLexicalBlock - Create a new lexical block node and push it on + // the stack. + void CreateLexicalBlock(SourceLocation Loc); + public: CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); + void finalize() { DBuilder.finalize(); } /// setLocation - Update the current source location. If \arg loc is /// invalid it is ignored. void setLocation(SourceLocation Loc); - /// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of - /// source line. - void EmitStopPoint(CGBuilderTy &Builder); + /// EmitLocation - Emit metadata to indicate a change in line/column + /// information in the source file. + void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. @@ -169,21 +172,17 @@ public: /// EmitFunctionEnd - Constructs the debug code for exiting a function. void EmitFunctionEnd(CGBuilderTy &Builder); - /// UpdateLineDirectiveRegion - Update region stack only if #line directive - /// has introduced scope change. - void UpdateLineDirectiveRegion(CGBuilderTy &Builder); - /// UpdateCompletedType - Update type cache because the type is now /// translated. void UpdateCompletedType(const TagDecl *TD); - /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start - /// of a new block. - void EmitRegionStart(CGBuilderTy &Builder); + /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a + /// new lexical block and push the block onto the stack. + void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc); - /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a - /// block. - void EmitRegionEnd(CGBuilderTy &Builder); + /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical + /// block and pop the current block. + void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc); /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic /// variable declaration. @@ -234,7 +233,7 @@ private: llvm::DIDescriptor getContextDescriptor(const Decl *Decl); /// getCurrentDirname - Return current directory name. - llvm::StringRef getCurrentDirname(); + StringRef getCurrentDirname(); /// CreateCompileUnit - Create new compile unit. void CreateCompileUnit(); @@ -255,7 +254,7 @@ private: /// CreateMemberType - Create new member and increase Offset by FType's size. llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, - llvm::StringRef Name, uint64_t *Offset); + StringRef Name, uint64_t *Offset); /// getFunctionDeclaration - Return debug info descriptor to describe method /// declaration for the given method definition. @@ -264,21 +263,21 @@ private: /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. - llvm::StringRef getFunctionName(const FunctionDecl *FD); + StringRef getFunctionName(const FunctionDecl *FD); /// getObjCMethodName - Returns the unmangled name of an Objective-C method. /// This is the display name for the debugging info. - llvm::StringRef getObjCMethodName(const ObjCMethodDecl *FD); + StringRef getObjCMethodName(const ObjCMethodDecl *FD); /// getSelectorName - Return selector name. This is used for debugging /// info. - llvm::StringRef getSelectorName(Selector S); + StringRef getSelectorName(Selector S); /// getClassName - Get class name including template argument list. - llvm::StringRef getClassName(RecordDecl *RD); + StringRef getClassName(RecordDecl *RD); /// getVTableName - Get vtable name for the given Class. - llvm::StringRef getVTableName(const CXXRecordDecl *Decl); + StringRef getVTableName(const CXXRecordDecl *Decl); /// getLineNumber - Get line number for the location. If location is invalid /// then use current location. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp index 62c3a97..a6147ea 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp @@ -14,6 +14,7 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGOpenCLRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" @@ -46,7 +47,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Field: case Decl::IndirectField: case Decl::ObjCIvar: - case Decl::ObjCAtDefsField: + case Decl::ObjCAtDefsField: case Decl::ParmVar: case Decl::ImplicitParam: case Decl::ClassTemplate: @@ -70,7 +71,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: - assert(0 && "Declaration should not be in declstmts!"); + case Decl::ClassScopeFunctionSpecialization: + llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; @@ -112,7 +114,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { case SC_Register: return EmitAutoVarDecl(D); case SC_Static: { - llvm::GlobalValue::LinkageTypes Linkage = + llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::InternalLinkage; // If the function definition has some sort of weak linkage, its @@ -123,26 +125,28 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { if (getContext().getLangOptions().CPlusPlus) if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage())) Linkage = CurFn->getLinkage(); - + return EmitStaticVarDecl(D, Linkage); } case SC_Extern: case SC_PrivateExtern: // Don't emit it now, allow it to be emitted lazily on its first use. return; + case SC_OpenCLWorkGroupLocal: + return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D); } - assert(0 && "Unknown storage class"); + llvm_unreachable("Unknown storage class"); } static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, const char *Separator) { CodeGenModule &CGM = CGF.CGM; if (CGF.getContext().getLangOptions().CPlusPlus) { - llvm::StringRef Name = CGM.getMangledName(&D); + StringRef Name = CGM.getMangledName(&D); return Name.str(); } - + std::string ContextName; if (!CGF.CurFuncDecl) { // Better be in a block declared in global scope. @@ -154,15 +158,15 @@ static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, ContextName = Name.getString(); } else - assert(0 && "Unknown context for block static var decl"); + llvm_unreachable("Unknown context for block static var decl"); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) { - llvm::StringRef Name = CGM.getMangledName(FD); + StringRef Name = CGM.getMangledName(FD); ContextName = Name.str(); } else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) ContextName = CGF.CurFn->getName(); else - assert(0 && "Unknown context for static var decl"); - + llvm_unreachable("Unknown context for static var decl"); + return ContextName + Separator + D.getNameAsString(); } @@ -175,7 +179,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, std::string Name = GetStaticDeclName(*this, D, Separator); - const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); + llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, @@ -203,7 +207,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, if (!getContext().getLangOptions().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else if (Builder.GetInsertBlock()) { - // Since we have a static initializer, this global variable can't + // Since we have a static initializer, this global variable can't // be constant. GV->setConstant(false); @@ -218,7 +222,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, // in the LLVM type system.) if (GV->getType()->getElementType() != Init->getType()) { llvm::GlobalVariable *OldGV = GV; - + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), OldGV->isConstant(), OldGV->getLinkage(), Init, "", @@ -226,19 +230,19 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, D.isThreadSpecified(), CGM.getContext().getTargetAddressSpace(D.getType())); GV->setVisibility(OldGV->getVisibility()); - + // Steal the name of the old global GV->takeName(OldGV); - + // Replace all uses of the old global with the new global llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); OldGV->replaceAllUsesWith(NewPtrForOldDecl); - + // Erase the old global, since it is no longer used. OldGV->eraseFromParent(); } - + GV->setInitializer(Init); return GV; } @@ -259,7 +263,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // Make sure to evaluate VLA bounds now so that we have them for later. if (D.getType()->isVariablyModifiedType()) EmitVariablyModifiedType(D.getType()); - + // Local static block variables must be treated as globals as they may be // referenced in their RHS initializer block-literal expresion. CGM.setStaticLocalDeclAddress(&D, GV); @@ -270,14 +274,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); - // FIXME: Merge attribute handling. - if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) { - SourceManager &SM = CGM.getContext().getSourceManager(); - llvm::Constant *Ann = - CGM.EmitAnnotateAttr(GV, AA, - SM.getInstantiationLineNumber(D.getLocation())); - CGM.AddAnnotation(Ann); - } + if (D.hasAttr<AnnotateAttr>()) + CGM.AddGlobalAnnotations(&D, GV); if (const SectionAttr *SA = D.getAttr<SectionAttr>()) GV->setSection(SA->getName()); @@ -290,8 +288,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // // FIXME: It is really dangerous to store this in the map; if anyone // RAUW's the GV uses of this constant will be invalid. - const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); - const llvm::Type *LPtrTy = + llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); + llvm::Type *LPtrTy = LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType())); DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy); @@ -348,7 +346,7 @@ namespace { CGF.Builder.CreateCondBr(DidNRVO, SkipDtorBB, RunDtorBB); CGF.EmitBlock(RunDtorBB); } - + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, Loc); @@ -360,7 +358,7 @@ namespace { llvm::Value *Stack; CallStackRestore(llvm::Value *Stack) : Stack(Stack) {} void Emit(CodeGenFunction &CGF, Flags flags) { - llvm::Value *V = CGF.Builder.CreateLoad(Stack, "tmp"); + llvm::Value *V = CGF.Builder.CreateLoad(Stack); llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore); CGF.Builder.CreateCall(F, V); } @@ -384,7 +382,7 @@ namespace { llvm::Constant *CleanupFn; const CGFunctionInfo &FnInfo; const VarDecl &Var; - + CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info, const VarDecl *Var) : CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {} @@ -441,7 +439,7 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var, case Qualifiers::OCL_Autoreleasing: // nothing to do break; - + case Qualifiers::OCL_Weak: // __weak objects always get EH cleanups; otherwise, exceptions // could cause really nasty crashes instead of mere leaks. @@ -508,7 +506,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, // actually perform the initialization with an assign. bool accessedByInit = false; if (lifetime != Qualifiers::OCL_ExplicitNone) - accessedByInit = isAccessedBy(D, init); + accessedByInit = (capturedByInit || isAccessedBy(D, init)); if (accessedByInit) { LValue tempLV = lvalue; // Drill down to the __block object if necessary. @@ -519,12 +517,12 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, getByRefValueLLVMField(cast<VarDecl>(D)))); } - const llvm::PointerType *ty + llvm::PointerType *ty = cast<llvm::PointerType>(tempLV.getAddress()->getType()); ty = cast<llvm::PointerType>(ty->getElementType()); llvm::Value *zero = llvm::ConstantPointerNull::get(ty); - + // If __weak, we want to use a barrier under certain conditions. if (lifetime == Qualifiers::OCL_Weak) EmitARCInitWeak(tempLV.getAddress(), zero); @@ -613,7 +611,7 @@ void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) { break; } - EmitStoreOfScalar(init, lvalue); + EmitStoreOfScalar(init, lvalue); } /// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the @@ -640,7 +638,7 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init, } return true; } - + // Anything else is hard and scary. return false; } @@ -655,7 +653,7 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc, isa<llvm::ConstantPointerNull>(Init) || isa<llvm::UndefValue>(Init)) return; - + if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) || isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) || isa<llvm::ConstantExpr>(Init)) { @@ -663,14 +661,14 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc, Builder.CreateStore(Init, Loc, isVolatile); return; } - + assert((isa<llvm::ConstantStruct>(Init) || isa<llvm::ConstantArray>(Init)) && "Unknown value type!"); - + for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) { llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i)); if (Elt->isNullValue()) continue; - + // Otherwise, get a pointer to the element and emit it. emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i), isVolatile, Builder); @@ -694,8 +692,8 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init, // plopping in more stores. unsigned StoreBudget = 6; uint64_t SizeLimit = 32; - - return GlobalSize > SizeLimit && + + return GlobalSize > SizeLimit && canEmitInitWithFewStoresAfterMemset(Init, StoreBudget); } @@ -730,7 +728,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - bool NRVO = getContext().getLangOptions().ElideConstructors && + bool NRVO = getContext().getLangOptions().ElideConstructors && D.isNRVOVariable(); // If this value is a POD array or struct with a statically @@ -740,7 +738,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // arrays as long as the initialization is trivial (e.g. if they // have a non-trivial destructor, but not a non-trivial constructor). if (D.getInit() && - (Ty->isArrayType() || Ty->isRecordType()) && + (Ty->isArrayType() || Ty->isRecordType()) && (Ty.isPODType(getContext()) || getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) && D.getInit()->isConstantInitializer(getContext(), false)) { @@ -759,27 +757,27 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // Otherwise, tell the initialization code that we're in this case. emission.IsConstantAggregate = true; } - + // A normal fixed sized variable becomes an alloca in the entry block, // unless it's an NRVO variable. - const llvm::Type *LTy = ConvertTypeForMem(Ty); - + llvm::Type *LTy = ConvertTypeForMem(Ty); + if (NRVO) { // The named return value optimization: allocate this variable in the // return slot, so that we can elide the copy when returning this // variable (C++0x [class.copy]p34). DeclPtr = ReturnValue; - + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) { // Create a flag that is used to indicate when the NRVO was applied - // to this variable. Set it to zero to indicate that NRVO was not + // to this variable. Set it to zero to indicate that NRVO was not // applied. llvm::Value *Zero = Builder.getFalse(); llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo"); EnsureInsertPoint(); Builder.CreateStore(Zero, NRVOFlag); - + // Record the NRVO flag for this variable. NRVOFlags[&D] = NRVOFlag; emission.NRVOFlag = NRVOFlag; @@ -788,13 +786,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { } else { if (isByRef) LTy = BuildByRefType(&D); - + llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); Alloc->setName(D.getNameAsString()); CharUnits allocaAlignment = alignment; if (isByRef) - allocaAlignment = std::max(allocaAlignment, + allocaAlignment = std::max(allocaAlignment, getContext().toCharUnitsFromBits(Target.getPointerAlign(0))); Alloc->setAlignment(allocaAlignment.getQuantity()); DeclPtr = Alloc; @@ -829,7 +827,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { QualType elementType; llvm::tie(elementCount, elementType) = getVLASize(Ty); - const llvm::Type *llvmTy = ConvertTypeForMem(elementType); + llvm::Type *llvmTy = ConvertTypeForMem(elementType); // Allocate memory for the array. llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla"); @@ -853,6 +851,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); } + if (D.hasAttr<AnnotateAttr>()) + EmitVarAnnotations(&D, emission.Address); + return emission; } @@ -875,6 +876,32 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) { return false; } + if (const StmtExpr *SE = dyn_cast<StmtExpr>(e)) { + const CompoundStmt *CS = SE->getSubStmt(); + for (CompoundStmt::const_body_iterator BI = CS->body_begin(), + BE = CS->body_end(); BI != BE; ++BI) + if (Expr *E = dyn_cast<Expr>((*BI))) { + if (isCapturedBy(var, E)) + return true; + } + else if (DeclStmt *DS = dyn_cast<DeclStmt>((*BI))) { + // special case declarations + for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); + I != E; ++I) { + if (VarDecl *VD = dyn_cast<VarDecl>((*I))) { + Expr *Init = VD->getInit(); + if (Init && isCapturedBy(var, Init)) + return true; + } + } + } + else + // FIXME. Make safe assumption assuming arbitrary statements cause capturing. + // Later, provide code to poke into statements for capture analysis. + return true; + return false; + } + for (Stmt::const_child_range children = e->children(); children; ++children) if (isCapturedBy(var, cast<Expr>(*children))) return true; @@ -887,14 +914,14 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) { static bool isTrivialInitializer(const Expr *Init) { if (!Init) return true; - + if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) if (CXXConstructorDecl *Constructor = Construct->getConstructor()) if (Constructor->isTrivial() && Constructor->isDefaultConstructor() && !Construct->requiresZeroInitialization()) return true; - + return false; } void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { @@ -922,7 +949,6 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { if (isTrivialInitializer(Init)) return; - CharUnits alignment = emission.Alignment; @@ -950,16 +976,16 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { assert(constant != 0 && "Wasn't a simple constant init?"); llvm::Value *SizeVal = - llvm::ConstantInt::get(IntPtrTy, + llvm::ConstantInt::get(IntPtrTy, getContext().getTypeSizeInChars(type).getQuantity()); - const llvm::Type *BP = Int8PtrTy; + llvm::Type *BP = Int8PtrTy; if (Loc->getType() != BP) - Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + Loc = Builder.CreateBitCast(Loc, BP); // If the initializer is all or mostly zeros, codegen with memset then do // a few stores afterward. - if (shouldUseMemSetPlusStoresToInitialize(constant, + if (shouldUseMemSetPlusStoresToInitialize(constant, CGM.getTargetData().getTypeAllocSize(constant->getType()))) { Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, alignment.getQuantity(), isVolatile); @@ -968,19 +994,19 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder); } } else { - // Otherwise, create a temporary global with the initializer then + // Otherwise, create a temporary global with the initializer then // memcpy from the global to the alloca. std::string Name = GetStaticDeclName(*this, D, "."); llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true, - llvm::GlobalValue::InternalLinkage, + llvm::GlobalValue::PrivateLinkage, constant, Name, 0, false, 0); GV->setAlignment(alignment.getQuantity()); GV->setUnnamedAddr(true); - + llvm::Value *SrcPtr = GV; if (SrcPtr->getType() != BP) - SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + SrcPtr = Builder.CreateBitCast(SrcPtr, BP); Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(), isVolatile); @@ -1007,7 +1033,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, if (type->isReferenceType()) { RValue rvalue = EmitReferenceBindingToExpr(init, D); - if (capturedByInit) + if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); EmitStoreThroughLValue(rvalue, lvalue); } else if (!hasAggregateLLVMType(type)) { @@ -1019,7 +1045,10 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile()); } else { // TODO: how can we delay here if D is captured by its initializer? - EmitAggExpr(init, AggValueSlot::forLValue(lvalue, true, false)); + EmitAggExpr(init, AggValueSlot::forLValue(lvalue, + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } } @@ -1058,7 +1087,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup( case QualType::DK_objc_strong_lifetime: // Suppress cleanups for pseudo-strong variables. if (var->isARCPseudoStrong()) return; - + // Otherwise, consider whether to use an EH cleanup or not. cleanupKind = getARCCleanupKind(); @@ -1094,7 +1123,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { emitAutoVarTypeCleanup(emission, dtorKind); // In GC mode, honor objc_precise_lifetime. - if (getLangOptions().getGCMode() != LangOptions::NonGC && + if (getLangOptions().getGC() != LangOptions::NonGC && D.hasAttr<ObjCPreciseLifetimeAttr>()) { EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D); } @@ -1267,11 +1296,9 @@ static void emitPartialArrayDestroy(CodeGenFunction &CGF, if (arrayDepth) { llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, arrayDepth+1); - llvm::SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero); - begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices.begin(), - gepIndices.end(), "pad.arraybegin"); - end = CGF.Builder.CreateInBoundsGEP(end, gepIndices.begin(), - gepIndices.end(), "pad.arrayend"); + SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero); + begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices, "pad.arraybegin"); + end = CGF.Builder.CreateInBoundsGEP(end, gepIndices, "pad.arrayend"); } // Destroy the array. We don't ever need an EH cleanup because we @@ -1330,7 +1357,7 @@ namespace { /// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy /// already-constructed elements of the given array. The cleanup /// may be popped with DeactivateCleanupBlock or PopCleanupBlock. -/// +/// /// \param elementType - the immediate element type of the array; /// possibly still an array type /// \param array - a value of type elementType* @@ -1349,7 +1376,7 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, /// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy /// already-constructed elements of the given array. The cleanup /// may be popped with DeactivateCleanupBlock or PopCleanupBlock. -/// +/// /// \param elementType - the immediate element type of the array; /// possibly still an array type /// \param array - a value of type elementType* @@ -1476,4 +1503,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, // Emit debug info for param declaration. if (CGDebugInfo *DI = getDebugInfo()) DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder); + + if (D.hasAttr<AnnotateAttr>()) + EmitVarAnnotations(&D, DeclPtr); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp index 0ae6a3d..3b8f830 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp @@ -46,7 +46,9 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, } else if (type->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile()); } else { - CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv, true)); + CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } } @@ -126,17 +128,16 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, } // Get the destructor function type - llvm::Type *ArgTys[] = { Int8PtrTy }; llvm::Type *DtorFnTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), - ArgTys, false); + Int8PtrTy, false); DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy }; // Get the __cxa_atexit function type // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); - const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType *AtExitFnTy = llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, @@ -167,15 +168,15 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, static llvm::Function * CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, - const llvm::FunctionType *FTy, - llvm::StringRef Name) { + llvm::FunctionType *FTy, + StringRef Name) { llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule()); if (!CGM.getContext().getLangOptions().AppleKext) { // Set the section if needed. if (const char *Section = - CGM.getContext().Target.getStaticInitSectionSpecifier()) + CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier()) Fn->setSection(Section); } @@ -188,7 +189,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr) { - const llvm::FunctionType *FTy + llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); @@ -225,7 +226,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty()) return; - const llvm::FunctionType *FTy + llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); @@ -234,7 +235,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a"); if (!PrioritizedCXXGlobalInits.empty()) { - llvm::SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits; + SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits; llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(), PrioritizedCXXGlobalInits.end()); for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) { @@ -259,7 +260,7 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() { if (CXXGlobalDtors.empty()) return; - const llvm::FunctionType *FTy + llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); @@ -351,7 +352,7 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo()); - const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); + llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *fn = CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp index 418bea6..5e4fb98 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp @@ -29,9 +29,8 @@ using namespace CodeGen; static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); - llvm::Type *ArgTys[] = { CGF.SizeTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.Int8PtrTy, CGF.SizeTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } @@ -39,9 +38,8 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { // void __cxa_free_exception(void *thrown_exception); - llvm::Type *ArgTys[] = { CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } @@ -51,7 +49,7 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { // void (*dest) (void *)); llvm::Type *Args[3] = { CGF.Int8PtrTy, CGF.Int8PtrTy, CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, Args, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); @@ -60,7 +58,7 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { // void __cxa_rethrow(); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); @@ -69,9 +67,8 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) { // void *__cxa_get_exception_ptr(void*); - llvm::Type *ArgTys[] = { CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr"); } @@ -79,9 +76,8 @@ static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) { static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { // void *__cxa_begin_catch(void*); - llvm::Type *ArgTys[] = { CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.Int8PtrTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } @@ -89,7 +85,7 @@ static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { // void __cxa_end_catch(); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); @@ -98,17 +94,15 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { // void __cxa_call_unexepcted(void *thrown_exception); - llvm::Type *ArgTys[] = { CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } llvm::Constant *CodeGenFunction::getUnwindResumeFn() { - llvm::Type *ArgTys[] = { Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false); if (CGM.getLangOptions().SjLjExceptions) return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); @@ -116,9 +110,8 @@ llvm::Constant *CodeGenFunction::getUnwindResumeFn() { } llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { - llvm::Type *ArgTys[] = { Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(VoidTy, ArgTys, /*IsVarArgs=*/false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false); if (CGM.getLangOptions().SjLjExceptions) return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow"); @@ -128,10 +121,10 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { // void __terminate(); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false); - llvm::StringRef name; + StringRef name; // In C++, use std::terminate(). if (CGF.getLangOptions().CPlusPlus) @@ -145,10 +138,9 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { } static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF, - llvm::StringRef Name) { - llvm::Type *ArgTys[] = { CGF.Int8PtrTy }; - const llvm::FunctionType *FTy = - llvm::FunctionType::get(CGF.VoidTy, ArgTys, /*IsVarArgs=*/false); + StringRef Name) { + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, Name); } @@ -247,21 +239,34 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { continue; } - // Otherwise, it has to be a selector call. - if (!isa<llvm::EHSelectorInst>(User)) return false; + // Otherwise, it has to be a landingpad instruction. + llvm::LandingPadInst *LPI = dyn_cast<llvm::LandingPadInst>(User); + if (!LPI) return false; - llvm::EHSelectorInst *Selector = cast<llvm::EHSelectorInst>(User); - for (unsigned I = 2, E = Selector->getNumArgOperands(); I != E; ++I) { + for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) { // Look for something that would've been returned by the ObjC // runtime's GetEHType() method. - llvm::GlobalVariable *GV - = dyn_cast<llvm::GlobalVariable>(Selector->getArgOperand(I)); - if (!GV) continue; - - // ObjC EH selector entries are always global variables with - // names starting like this. - if (GV->getName().startswith("OBJC_EHTYPE")) - return false; + llvm::Value *Val = LPI->getClause(I)->stripPointerCasts(); + if (LPI->isCatch(I)) { + // Check if the catch value has the ObjC prefix. + if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val)) + // ObjC EH selector entries are always global variables with + // names starting like this. + if (GV->getName().startswith("OBJC_EHTYPE")) + return false; + } else { + // Check if any of the filter values have the ObjC prefix. + llvm::Constant *CVal = cast<llvm::Constant>(Val); + for (llvm::User::op_iterator + II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) { + if (llvm::GlobalVariable *GV = + cast<llvm::GlobalVariable>((*II)->stripPointerCasts())) + // ObjC EH selector entries are always global variables with + // names starting like this. + if (GV->getName().startswith("OBJC_EHTYPE")) + return false; + } + } } } @@ -274,7 +279,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { /// when it really needs it. void CodeGenModule::SimplifyPersonality() { // For now, this is really a Darwin-specific operation. - if (!Context.Target.getTriple().isOSDarwin()) + if (!Context.getTargetInfo().getTriple().isOSDarwin()) return; // If we're not in ObjC++ -fexceptions, there's nothing to do. @@ -314,12 +319,6 @@ static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) { return llvm::ConstantPointerNull::get(CGF.Int8PtrTy); } -/// Returns the value to inject into a selector to indicate the -/// presence of a cleanup. -static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) { - return llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0); -} - namespace { /// A cleanup to free the exception object if its initialization /// throws. @@ -346,7 +345,7 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e, // __cxa_allocate_exception returns a void*; we need to cast this // to the appropriate type for the object. - const llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo(); + llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo(); llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty); // FIXME: this isn't quite right! If there's a final unelided call @@ -375,6 +374,14 @@ llvm::Value *CodeGenFunction::getEHSelectorSlot() { return EHSelectorSlot; } +llvm::Value *CodeGenFunction::getExceptionFromSlot() { + return Builder.CreateLoad(getExceptionSlot(), "exn"); +} + +llvm::Value *CodeGenFunction::getSelectorFromSlot() { + return Builder.CreateLoad(getEHSelectorSlot(), "sel"); +} + void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { if (getInvokeDest()) { @@ -397,7 +404,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { QualType ThrowType = E->getSubExpr()->getType(); // Now allocate the exception object. - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); @@ -475,6 +482,43 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { } } +/// Emit the dispatch block for a filter scope if necessary. +static void emitFilterDispatchBlock(CodeGenFunction &CGF, + EHFilterScope &filterScope) { + llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock(); + if (!dispatchBlock) return; + if (dispatchBlock->use_empty()) { + delete dispatchBlock; + return; + } + + CGF.EmitBlockAfterUses(dispatchBlock); + + // If this isn't a catch-all filter, we need to check whether we got + // here because the filter triggered. + if (filterScope.getNumFilters()) { + // Load the selector value. + llvm::Value *selector = CGF.getSelectorFromSlot(); + llvm::BasicBlock *unexpectedBB = CGF.createBasicBlock("ehspec.unexpected"); + + llvm::Value *zero = CGF.Builder.getInt32(0); + llvm::Value *failsFilter = + CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails"); + CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock()); + + CGF.EmitBlock(unexpectedBB); + } + + // Call __cxa_call_unexpected. This doesn't need to be an invoke + // because __cxa_call_unexpected magically filters exceptions + // according to the last landing pad the exception was thrown + // into. Seriously. + llvm::Value *exn = CGF.getExceptionFromSlot(); + CGF.Builder.CreateCall(getUnexpectedFn(CGF), exn) + ->setDoesNotReturn(); + CGF.Builder.CreateUnreachable(); +} + void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (!CGM.getLangOptions().CXXExceptions) return; @@ -492,6 +536,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { EHStack.popTerminate(); } } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin()); + emitFilterDispatchBlock(*this, filterScope); EHStack.popFilter(); } } @@ -533,6 +579,50 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { } } +llvm::BasicBlock * +CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { + // The dispatch block for the end of the scope chain is a block that + // just resumes unwinding. + if (si == EHStack.stable_end()) + return getEHResumeBlock(); + + // Otherwise, we should look at the actual scope. + EHScope &scope = *EHStack.find(si); + + llvm::BasicBlock *dispatchBlock = scope.getCachedEHDispatchBlock(); + if (!dispatchBlock) { + switch (scope.getKind()) { + case EHScope::Catch: { + // Apply a special case to a single catch-all. + EHCatchScope &catchScope = cast<EHCatchScope>(scope); + if (catchScope.getNumHandlers() == 1 && + catchScope.getHandler(0).isCatchAll()) { + dispatchBlock = catchScope.getHandler(0).Block; + + // Otherwise, make a dispatch block. + } else { + dispatchBlock = createBasicBlock("catch.dispatch"); + } + break; + } + + case EHScope::Cleanup: + dispatchBlock = createBasicBlock("ehcleanup"); + break; + + case EHScope::Filter: + dispatchBlock = createBasicBlock("filter.dispatch"); + break; + + case EHScope::Terminate: + dispatchBlock = getTerminateHandler(); + break; + } + scope.setCachedEHDispatchBlock(dispatchBlock); + } + return dispatchBlock; +} + /// Check whether this is a non-EH scope, i.e. a scope which doesn't /// affect exception handling. Currently, the only non-EH scopes are /// normal-only cleanup scopes. @@ -629,280 +719,143 @@ const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup; llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { assert(EHStack.requiresLandingPad()); - for (EHScopeStack::iterator ir = EHStack.begin(); ; ) { - assert(ir != EHStack.end() && - "stack requiring landing pad is nothing but non-EH scopes?"); - - // If this is a terminate scope, just use the singleton terminate - // landing pad. - if (isa<EHTerminateScope>(*ir)) - return getTerminateLandingPad(); - - // If this isn't an EH scope, iterate; otherwise break out. - if (!isNonEHScope(*ir)) break; - ++ir; + EHScope &innermostEHScope = *EHStack.find(EHStack.getInnermostEHScope()); + switch (innermostEHScope.getKind()) { + case EHScope::Terminate: + return getTerminateLandingPad(); - // We haven't checked this scope for a cached landing pad yet. - if (llvm::BasicBlock *LP = ir->getCachedLandingPad()) - return LP; + case EHScope::Catch: + case EHScope::Cleanup: + case EHScope::Filter: + if (llvm::BasicBlock *lpad = innermostEHScope.getCachedLandingPad()) + return lpad; } // Save the current IR generation state. - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); + CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); - const EHPersonality &Personality = EHPersonality::get(getLangOptions()); + const EHPersonality &personality = EHPersonality::get(getLangOptions()); // Create and configure the landing pad. - llvm::BasicBlock *LP = createBasicBlock("lpad"); - EmitBlock(LP); + llvm::BasicBlock *lpad = createBasicBlock("lpad"); + EmitBlock(lpad); + + llvm::LandingPadInst *LPadInst = + Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL), + getOpaquePersonalityFn(CGM, personality), 0); + + llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0); + Builder.CreateStore(LPadExn, getExceptionSlot()); + llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1); + Builder.CreateStore(LPadSel, getEHSelectorSlot()); // Save the exception pointer. It's safe to use a single exception // pointer per function because EH cleanups can never have nested // try/catches. - llvm::CallInst *Exn = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn"); - Exn->setDoesNotThrow(); - Builder.CreateStore(Exn, getExceptionSlot()); - - // Build the selector arguments. - llvm::SmallVector<llvm::Value*, 8> EHSelector; - EHSelector.push_back(Exn); - EHSelector.push_back(getOpaquePersonalityFn(CGM, Personality)); + // Build the landingpad instruction. // Accumulate all the handlers in scope. - llvm::DenseMap<llvm::Value*, UnwindDest> EHHandlers; - UnwindDest CatchAll; - bool HasEHCleanup = false; - bool HasEHFilter = false; - llvm::SmallVector<llvm::Value*, 8> EHFilters; + bool hasCatchAll = false; + bool hasCleanup = false; + bool hasFilter = false; + SmallVector<llvm::Value*, 4> filterTypes; + llvm::SmallPtrSet<llvm::Value*, 4> catchTypes; for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E; ++I) { switch (I->getKind()) { case EHScope::Cleanup: - if (!HasEHCleanup) - HasEHCleanup = cast<EHCleanupScope>(*I).isEHCleanup(); - // We otherwise don't care about cleanups. + // If we have a cleanup, remember that. + hasCleanup = (hasCleanup || cast<EHCleanupScope>(*I).isEHCleanup()); continue; case EHScope::Filter: { assert(I.next() == EHStack.end() && "EH filter is not end of EH stack"); - assert(!CatchAll.isValid() && "EH filter reached after catch-all"); - - // Filter scopes get added to the selector in weird ways. - EHFilterScope &Filter = cast<EHFilterScope>(*I); - HasEHFilter = true; - - // Add all the filter values which we aren't already explicitly - // catching. - for (unsigned I = 0, E = Filter.getNumFilters(); I != E; ++I) { - llvm::Value *FV = Filter.getFilter(I); - if (!EHHandlers.count(FV)) - EHFilters.push_back(FV); - } + assert(!hasCatchAll && "EH filter reached after catch-all"); + + // Filter scopes get added to the landingpad in weird ways. + EHFilterScope &filter = cast<EHFilterScope>(*I); + hasFilter = true; + + // Add all the filter values. + for (unsigned i = 0, e = filter.getNumFilters(); i != e; ++i) + filterTypes.push_back(filter.getFilter(i)); goto done; } case EHScope::Terminate: // Terminate scopes are basically catch-alls. - assert(!CatchAll.isValid()); - CatchAll = UnwindDest(getTerminateHandler(), - EHStack.getEnclosingEHCleanup(I), - cast<EHTerminateScope>(*I).getDestIndex()); + assert(!hasCatchAll); + hasCatchAll = true; goto done; case EHScope::Catch: break; } - EHCatchScope &Catch = cast<EHCatchScope>(*I); - for (unsigned HI = 0, HE = Catch.getNumHandlers(); HI != HE; ++HI) { - EHCatchScope::Handler Handler = Catch.getHandler(HI); - - // Catch-all. We should only have one of these per catch. - if (!Handler.Type) { - assert(!CatchAll.isValid()); - CatchAll = UnwindDest(Handler.Block, - EHStack.getEnclosingEHCleanup(I), - Handler.Index); - continue; + EHCatchScope &catchScope = cast<EHCatchScope>(*I); + for (unsigned hi = 0, he = catchScope.getNumHandlers(); hi != he; ++hi) { + EHCatchScope::Handler handler = catchScope.getHandler(hi); + + // If this is a catch-all, register that and abort. + if (!handler.Type) { + assert(!hasCatchAll); + hasCatchAll = true; + goto done; } // Check whether we already have a handler for this type. - UnwindDest &Dest = EHHandlers[Handler.Type]; - if (Dest.isValid()) continue; - - EHSelector.push_back(Handler.Type); - Dest = UnwindDest(Handler.Block, - EHStack.getEnclosingEHCleanup(I), - Handler.Index); + if (catchTypes.insert(handler.Type)) + // If not, add it directly to the landingpad. + LPadInst->addClause(handler.Type); } - - // Stop if we found a catch-all. - if (CatchAll.isValid()) break; } done: - unsigned LastToEmitInLoop = EHSelector.size(); - - // If we have a catch-all, add null to the selector. - if (CatchAll.isValid()) { - EHSelector.push_back(getCatchAllValue(*this)); + // If we have a catch-all, add null to the landingpad. + assert(!(hasCatchAll && hasFilter)); + if (hasCatchAll) { + LPadInst->addClause(getCatchAllValue(*this)); // If we have an EH filter, we need to add those handlers in the - // right place in the selector, which is to say, at the end. - } else if (HasEHFilter) { - // Create a filter expression: an integer constant saying how many - // filters there are (+1 to avoid ambiguity with 0 for cleanup), - // followed by the filter types. The personality routine only - // lands here if the filter doesn't match. - EHSelector.push_back(llvm::ConstantInt::get(Builder.getInt32Ty(), - EHFilters.size() + 1)); - EHSelector.append(EHFilters.begin(), EHFilters.end()); + // right place in the landingpad, which is to say, at the end. + } else if (hasFilter) { + // Create a filter expression: a constant array indicating which filter + // types there are. The personality routine only lands here if the filter + // doesn't match. + llvm::SmallVector<llvm::Constant*, 8> Filters; + llvm::ArrayType *AType = + llvm::ArrayType::get(!filterTypes.empty() ? + filterTypes[0]->getType() : Int8PtrTy, + filterTypes.size()); + + for (unsigned i = 0, e = filterTypes.size(); i != e; ++i) + Filters.push_back(cast<llvm::Constant>(filterTypes[i])); + llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters); + LPadInst->addClause(FilterArray); // Also check whether we need a cleanup. - if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) - EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall - ? getCatchAllValue(*this) - : getCleanupValue(*this)); + if (hasCleanup) + LPadInst->setCleanup(true); // Otherwise, signal that we at least have cleanups. - } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) { - EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall - ? getCatchAllValue(*this) - : getCleanupValue(*this)); - - // At the MandatoryCleanup hack level, we don't need to actually - // spuriously tell the unwinder that we have cleanups, but we do - // need to always be prepared to handle cleanups. - } else if (CleanupHackLevel == CHL_MandatoryCleanup) { - // Just don't decrement LastToEmitInLoop. - - } else { - assert(LastToEmitInLoop > 2); - LastToEmitInLoop--; + } else if (CleanupHackLevel == CHL_MandatoryCatchall || hasCleanup) { + if (CleanupHackLevel == CHL_MandatoryCatchall) + LPadInst->addClause(getCatchAllValue(*this)); + else + LPadInst->setCleanup(true); } - assert(EHSelector.size() >= 3 && "selector call has only two arguments!"); + assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) && + "landingpad instruction has no clauses!"); // Tell the backend how to generate the landing pad. - llvm::CallInst *Selection = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector), - EHSelector, "eh.selector"); - Selection->setDoesNotThrow(); - - // Save the selector value in mandatory-cleanup mode. - if (CleanupHackLevel == CHL_MandatoryCleanup) - Builder.CreateStore(Selection, getEHSelectorSlot()); - - // Select the right handler. - llvm::Value *llvm_eh_typeid_for = - CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); - - // The results of llvm_eh_typeid_for aren't reliable --- at least - // not locally --- so we basically have to do this as an 'if' chain. - // We walk through the first N-1 catch clauses, testing and chaining, - // and then fall into the final clause (which is either a cleanup, a - // filter (possibly with a cleanup), a catch-all, or another catch). - for (unsigned I = 2; I != LastToEmitInLoop; ++I) { - llvm::Value *Type = EHSelector[I]; - UnwindDest Dest = EHHandlers[Type]; - assert(Dest.isValid() && "no handler entry for value in selector?"); - - // Figure out where to branch on a match. As a debug code-size - // optimization, if the scope depth matches the innermost cleanup, - // we branch directly to the catch handler. - llvm::BasicBlock *Match = Dest.getBlock(); - bool MatchNeedsCleanup = - Dest.getScopeDepth() != EHStack.getInnermostEHCleanup(); - if (MatchNeedsCleanup) - Match = createBasicBlock("eh.match"); - - llvm::BasicBlock *Next = createBasicBlock("eh.next"); - - // Check whether the exception matches. - llvm::CallInst *Id - = Builder.CreateCall(llvm_eh_typeid_for, - Builder.CreateBitCast(Type, Int8PtrTy)); - Id->setDoesNotThrow(); - Builder.CreateCondBr(Builder.CreateICmpEQ(Selection, Id), - Match, Next); - - // Emit match code if necessary. - if (MatchNeedsCleanup) { - EmitBlock(Match); - EmitBranchThroughEHCleanup(Dest); - } - - // Continue to the next match. - EmitBlock(Next); - } - - // Emit the final case in the selector. - // This might be a catch-all.... - if (CatchAll.isValid()) { - assert(isa<llvm::ConstantPointerNull>(EHSelector.back())); - EmitBranchThroughEHCleanup(CatchAll); - - // ...or an EH filter... - } else if (HasEHFilter) { - llvm::Value *SavedSelection = Selection; - - // First, unwind out to the outermost scope if necessary. - if (EHStack.hasEHCleanups()) { - // The end here might not dominate the beginning, so we might need to - // save the selector if we need it. - llvm::AllocaInst *SelectorVar = 0; - if (HasEHCleanup) { - SelectorVar = CreateTempAlloca(Builder.getInt32Ty(), "selector.var"); - Builder.CreateStore(Selection, SelectorVar); - } - - llvm::BasicBlock *CleanupContBB = createBasicBlock("ehspec.cleanup.cont"); - EmitBranchThroughEHCleanup(UnwindDest(CleanupContBB, EHStack.stable_end(), - EHStack.getNextEHDestIndex())); - EmitBlock(CleanupContBB); - - if (HasEHCleanup) - SavedSelection = Builder.CreateLoad(SelectorVar, "ehspec.saved-selector"); - } - - // If there was a cleanup, we'll need to actually check whether we - // landed here because the filter triggered. - if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) { - llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected"); - - llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0); - llvm::Value *FailsFilter = - Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails"); - Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock()); - - EmitBlock(UnexpectedBB); - } - - // Call __cxa_call_unexpected. This doesn't need to be an invoke - // because __cxa_call_unexpected magically filters exceptions - // according to the last landing pad the exception was thrown - // into. Seriously. - Builder.CreateCall(getUnexpectedFn(*this), - Builder.CreateLoad(getExceptionSlot())) - ->setDoesNotReturn(); - Builder.CreateUnreachable(); - - // ...or a normal catch handler... - } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) { - llvm::Value *Type = EHSelector.back(); - EmitBranchThroughEHCleanup(EHHandlers[Type]); - - // ...or a cleanup. - } else { - EmitBranchThroughEHCleanup(getRethrowDest()); - } + Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope())); // Restore the old IR generation state. - Builder.restoreIP(SavedIP); + Builder.restoreIP(savedIP); - return LP; + return lpad; } namespace { @@ -954,11 +907,11 @@ static void InitCatchParam(CodeGenFunction &CGF, const VarDecl &CatchParam, llvm::Value *ParamAddr) { // Load the exception from where the landing pad saved it. - llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn"); + llvm::Value *Exn = CGF.getExceptionFromSlot(); CanQualType CatchType = CGF.CGM.getContext().getCanonicalType(CatchParam.getType()); - const llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType); + llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType); // If we're catching by reference, we can just cast the object // pointer to the appropriate pointer. @@ -1001,7 +954,7 @@ static void InitCatchParam(CodeGenFunction &CGF, // pad. The best solution is to fix the personality function. } else { // Pull the pointer for the reference type off. - const llvm::Type *PtrTy = + llvm::Type *PtrTy = cast<llvm::PointerType>(LLVMCatchTy)->getElementType(); // Create the temporary and write the adjusted pointer into it. @@ -1037,7 +990,7 @@ static void InitCatchParam(CodeGenFunction &CGF, // Otherwise, it returns a pointer into the exception object. - const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok + llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy); if (IsComplex) { @@ -1055,7 +1008,7 @@ static void InitCatchParam(CodeGenFunction &CGF, assert(isa<RecordType>(CatchType) && "unexpected catch type!"); - const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok + llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok // Check for a copy expression. If we don't have a copy expression, // that means a trivial copy is okay. @@ -1086,8 +1039,10 @@ static void InitCatchParam(CodeGenFunction &CGF, CGF.EHStack.pushTerminate(); // Perform the copy construction. - CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(), - false)); + CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(), + AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); // Leave the terminate scope. CGF.EHStack.popTerminate(); @@ -1127,7 +1082,7 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) { VarDecl *CatchParam = S->getExceptionDecl(); if (!CatchParam) { - llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn"); + llvm::Value *Exn = CGF.getExceptionFromSlot(); CallBeginCatch(CGF, Exn, true); return; } @@ -1146,16 +1101,112 @@ namespace { }; } +/// Emit the structure of the dispatch block for the given catch scope. +/// It is an invariant that the dispatch block already exists. +static void emitCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &catchScope) { + llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); + assert(dispatchBlock); + + // If there's only a single catch-all, getEHDispatchBlock returned + // that catch-all as the dispatch block. + if (catchScope.getNumHandlers() == 1 && + catchScope.getHandler(0).isCatchAll()) { + assert(dispatchBlock == catchScope.getHandler(0).Block); + return; + } + + CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); + CGF.EmitBlockAfterUses(dispatchBlock); + + // Select the right handler. + llvm::Value *llvm_eh_typeid_for = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); + + // Load the selector value. + llvm::Value *selector = CGF.getSelectorFromSlot(); + + // Test against each of the exception types we claim to catch. + for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) { + assert(i < e && "ran off end of handlers!"); + const EHCatchScope::Handler &handler = catchScope.getHandler(i); + + llvm::Value *typeValue = handler.Type; + assert(typeValue && "fell into catch-all case!"); + typeValue = CGF.Builder.CreateBitCast(typeValue, CGF.Int8PtrTy); + + // Figure out the next block. + bool nextIsEnd; + llvm::BasicBlock *nextBlock; + + // If this is the last handler, we're at the end, and the next + // block is the block for the enclosing EH scope. + if (i + 1 == e) { + nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope()); + nextIsEnd = true; + + // If the next handler is a catch-all, we're at the end, and the + // next block is that handler. + } else if (catchScope.getHandler(i+1).isCatchAll()) { + nextBlock = catchScope.getHandler(i+1).Block; + nextIsEnd = true; + + // Otherwise, we're not at the end and we need a new block. + } else { + nextBlock = CGF.createBasicBlock("catch.fallthrough"); + nextIsEnd = false; + } + + // Figure out the catch type's index in the LSDA's type table. + llvm::CallInst *typeIndex = + CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); + typeIndex->setDoesNotThrow(); + + llvm::Value *matchesTypeIndex = + CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); + CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock); + + // If the next handler is a catch-all, we're completely done. + if (nextIsEnd) { + CGF.Builder.restoreIP(savedIP); + return; + + // Otherwise we need to emit and continue at that block. + } else { + CGF.EmitBlock(nextBlock); + } + } + + llvm_unreachable("fell out of loop!"); +} + +void CodeGenFunction::popCatchScope() { + EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin()); + if (catchScope.hasEHBranches()) + emitCatchDispatchBlock(*this, catchScope); + EHStack.popCatch(); +} + void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { unsigned NumHandlers = S.getNumHandlers(); EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin()); assert(CatchScope.getNumHandlers() == NumHandlers); + // If the catch was not required, bail out now. + if (!CatchScope.hasEHBranches()) { + EHStack.popCatch(); + return; + } + + // Emit the structure of the EH dispatch for this catch. + emitCatchDispatchBlock(*this, CatchScope); + // Copy the handler blocks off before we pop the EH stack. Emitting // the handlers might scribble on this memory. - llvm::SmallVector<EHCatchScope::Handler, 8> Handlers(NumHandlers); + SmallVector<EHCatchScope::Handler, 8> Handlers(NumHandlers); memcpy(Handlers.data(), CatchScope.begin(), NumHandlers * sizeof(EHCatchScope::Handler)); + EHStack.popCatch(); // The fall-through block. @@ -1171,12 +1222,19 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { ImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) || isa<CXXConstructorDecl>(CurCodeDecl); - for (unsigned I = 0; I != NumHandlers; ++I) { - llvm::BasicBlock *CatchBlock = Handlers[I].Block; - EmitBlock(CatchBlock); + // Perversely, we emit the handlers backwards precisely because we + // want them to appear in source order. In all of these cases, the + // catch block will have exactly one predecessor, which will be a + // particular block in the catch dispatch. However, in the case of + // a catch-all, one of the dispatch blocks will branch to two + // different handlers, and EmitBlockAfterUses will cause the second + // handler to be moved before the first. + for (unsigned I = NumHandlers; I != 0; --I) { + llvm::BasicBlock *CatchBlock = Handlers[I-1].Block; + EmitBlockAfterUses(CatchBlock); // Catch the exception if this isn't a catch-all. - const CXXCatchStmt *C = S.getHandler(I); + const CXXCatchStmt *C = S.getHandler(I-1); // Enter a cleanup scope, including the catch variable and the // end-catch. @@ -1315,7 +1373,7 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF, // In the latter case we need to pass it the exception object. // But we can't use the exception slot because the @finally might // have a landing pad (which would overwrite the exception slot). - const llvm::FunctionType *rethrowFnTy = + llvm::FunctionType *rethrowFnTy = cast<llvm::FunctionType>( cast<llvm::PointerType>(rethrowFn->getType())->getElementType()); SavedExnVar = 0; @@ -1358,7 +1416,8 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { // Leave the finally catch-all. EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin()); llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block; - CGF.EHStack.popCatch(); + + CGF.popCatchScope(); // If there are any references to the catch-all block, emit it. if (catchBB->use_empty()) { @@ -1371,13 +1430,13 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { // If there's a begin-catch function, call it. if (BeginCatchFn) { - exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); + exn = CGF.getExceptionFromSlot(); CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow(); } // If we need to remember the exception pointer to rethrow later, do so. if (SavedExnVar) { - if (!exn) exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); + if (!exn) exn = CGF.getExceptionFromSlot(); CGF.Builder.CreateStore(exn, SavedExnVar); } @@ -1405,19 +1464,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { Builder.SetInsertPoint(TerminateLandingPad); // Tell the backend that this is a landing pad. - llvm::CallInst *Exn = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn"); - Exn->setDoesNotThrow(); - const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions()); - - // Tell the backend what the exception table should be: - // nothing but a catch-all. - llvm::Value *Args[3] = { Exn, getOpaquePersonalityFn(CGM, Personality), - getCatchAllValue(*this) }; - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector), - Args, "eh.selector") - ->setDoesNotThrow(); + llvm::LandingPadInst *LPadInst = + Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL), + getOpaquePersonalityFn(CGM, Personality), 0); + LPadInst->addClause(getCatchAllValue(*this)); llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this)); TerminateCall->setDoesNotReturn(); @@ -1451,26 +1502,26 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { return TerminateHandler; } -CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { - if (RethrowBlock.isValid()) return RethrowBlock; +llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() { + if (EHResumeBlock) return EHResumeBlock; CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); // We emit a jump to a notional label at the outermost unwind state. - llvm::BasicBlock *Unwind = createBasicBlock("eh.resume"); - Builder.SetInsertPoint(Unwind); + EHResumeBlock = createBasicBlock("eh.resume"); + Builder.SetInsertPoint(EHResumeBlock); const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions()); // This can always be a call because we necessarily didn't find // anything on the EH stack which needs our help. - llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName(); + StringRef RethrowName = Personality.getCatchallRethrowFnName(); if (!RethrowName.empty()) { Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName), - Builder.CreateLoad(getExceptionSlot())) + getExceptionFromSlot()) ->setDoesNotReturn(); } else { - llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot()); + llvm::Value *Exn = getExceptionFromSlot(); switch (CleanupHackLevel) { case CHL_MandatoryCatchall: @@ -1481,12 +1532,21 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { ->setDoesNotReturn(); break; case CHL_MandatoryCleanup: { - // In mandatory-cleanup mode, we should use llvm.eh.resume. - llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot()); - Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume), - Exn, Selector) - ->setDoesNotReturn(); - break; + // In mandatory-cleanup mode, we should use 'resume'. + + // Recreate the landingpad's return value for the 'resume' instruction. + llvm::Value *Exn = getExceptionFromSlot(); + llvm::Value *Sel = getSelectorFromSlot(); + + llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), + Sel->getType(), NULL); + llvm::Value *LPadVal = llvm::UndefValue::get(LPadType); + LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val"); + LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val"); + + Builder.CreateResume(LPadVal); + Builder.restoreIP(SavedIP); + return EHResumeBlock; } case CHL_Ideal: // In an idealized mode where we don't have to worry about the @@ -1502,7 +1562,5 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { Builder.restoreIP(SavedIP); - RethrowBlock = UnwindDest(Unwind, EHStack.stable_end(), 0); - return RethrowBlock; + return EHResumeBlock; } - diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.h b/contrib/llvm/tools/clang/lib/CodeGen/CGException.h index 5a743b5..d021616 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.h @@ -24,15 +24,15 @@ namespace CodeGen { /// The exceptions personality for a function. When class EHPersonality { - llvm::StringRef PersonalityFn; + StringRef PersonalityFn; // If this is non-null, this personality requires a non-standard // function for rethrowing an exception after a catchall cleanup. // This function must have prototype void(void*). - llvm::StringRef CatchallRethrowFn; + StringRef CatchallRethrowFn; - EHPersonality(llvm::StringRef PersonalityFn, - llvm::StringRef CatchallRethrowFn = llvm::StringRef()) + EHPersonality(StringRef PersonalityFn, + StringRef CatchallRethrowFn = StringRef()) : PersonalityFn(PersonalityFn), CatchallRethrowFn(CatchallRethrowFn) {} @@ -46,8 +46,8 @@ public: static const EHPersonality GNU_CPlusPlus; static const EHPersonality GNU_CPlusPlus_SJLJ; - llvm::StringRef getPersonalityFnName() const { return PersonalityFn; } - llvm::StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; } + StringRef getPersonalityFnName() const { return PersonalityFn; } + StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; } }; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index a7e8003..bd4e553 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -18,6 +18,7 @@ #include "CGDebugInfo.h" #include "CGRecordLayout.h" #include "CGObjCRuntime.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/Frontend/CodeGenOptions.h" @@ -34,7 +35,7 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) { unsigned addressSpace = cast<llvm::PointerType>(value->getType())->getAddressSpace(); - const llvm::PointerType *destType = Int8PtrTy; + llvm::PointerType *destType = Int8PtrTy; if (addressSpace) destType = llvm::Type::getInt8PtrTy(getLLVMContext(), addressSpace); @@ -44,8 +45,8 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) { /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. -llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, - const llvm::Twine &Name) { +llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, + const Twine &Name) { if (!Builder.isNamePreserving()) return new llvm::AllocaInst(Ty, 0, "", AllocaInsertPt); return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); @@ -59,7 +60,7 @@ void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var, } llvm::AllocaInst *CodeGenFunction::CreateIRTemp(QualType Ty, - const llvm::Twine &Name) { + const Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name); // FIXME: Should we prefer the preferred type alignment here? CharUnits Align = getContext().getTypeAlignInChars(Ty); @@ -68,7 +69,7 @@ llvm::AllocaInst *CodeGenFunction::CreateIRTemp(QualType Ty, } llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty, - const llvm::Twine &Name) { + const Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name); // FIXME: Should we prefer the preferred type alignment here? CharUnits Align = getContext().getTypeAlignInChars(Ty); @@ -136,7 +137,10 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, if (E->getType()->isAnyComplexType()) EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile()); else if (hasAggregateLLVMType(E->getType())) - EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, IsInit)); + EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, + AggValueSlot::IsDestructed_t(IsInit), + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsAliased_t(!IsInit))); else { RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); LValue LV = MakeAddrLValue(Location, E->getType()); @@ -174,7 +178,7 @@ namespace { } static llvm::Value * -CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type, +CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type, const NamedDecl *InitializedDecl) { if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) { if (VD->hasGlobalStorage()) { @@ -183,7 +187,7 @@ CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type, CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out); Out.flush(); - const llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); + llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); // Create the reference temporary. llvm::GlobalValue *RefTemp = @@ -310,7 +314,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, return ReferenceTemporary; } - llvm::SmallVector<SubobjectAdjustment, 2> Adjustments; + SmallVector<SubobjectAdjustment, 2> Adjustments; while (true) { E = E->IgnoreParens(); @@ -354,8 +358,12 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, !E->getType()->isAnyComplexType()) { ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), InitializedDecl); + AggValueSlot::IsDestructed_t isDestructed + = AggValueSlot::IsDestructed_t(InitializedDecl != 0); AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(), - InitializedDecl != 0); + isDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); } if (InitializedDecl) { @@ -466,7 +474,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, else { switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { case Qualifiers::OCL_None: - assert(0 && "Not a reference temporary that needs to be deallocated"); + llvm_unreachable( + "Not a reference temporary that needs to be deallocated"); case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: // Nothing to do. @@ -578,7 +587,7 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) { return RValue::get(0); if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { - const llvm::Type *EltTy = ConvertType(CTy->getElementType()); + llvm::Type *EltTy = ConvertType(CTy->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return RValue::getComplex(std::make_pair(U, U)); } @@ -652,7 +661,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitVAArgExprLValue(cast<VAArgExpr>(E)); case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E)); - case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); + case Expr::ParenExprClass: + return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); case Expr::GenericSelectionExprClass: return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr()); case Expr::PredefinedExprClass: @@ -731,7 +741,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) { llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, llvm::MDNode *TBAAInfo) { - llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp"); + llvm::LoadInst *Load = Builder.CreateLoad(Addr); if (Volatile) Load->setVolatile(true); if (Alignment) @@ -812,7 +822,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) { if (LV.isVectorElt()) { llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), - LV.isVolatileQualified(), "tmp"); + LV.isVolatileQualified()); return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(), "vecext")); } @@ -833,7 +843,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); // Get the output type. - const llvm::Type *ResLTy = ConvertType(LV.getType()); + llvm::Type *ResLTy = ConvertType(LV.getType()); unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); // Compute the result as an OR of all of the individual component accesses. @@ -857,7 +867,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { } // Cast to the access type. - const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), + llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth, CGM.getContext().getTargetAddressSpace(LV.getType())); Ptr = Builder.CreateBitCast(Ptr, PTy); @@ -905,7 +915,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { // appropriate shufflevector. RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(), - LV.isVolatileQualified(), "tmp"); + LV.isVolatileQualified()); const llvm::Constant *Elts = LV.getExtVectorElts(); @@ -915,13 +925,13 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { if (!ExprVT) { unsigned InIdx = getAccessedFieldNo(0, Elts); llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx); - return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); + return RValue::get(Builder.CreateExtractElement(Vec, Elt)); } // Always use shuffle vector to try to retain the original program structure unsigned NumResultElts = ExprVT->getNumElements(); - llvm::SmallVector<llvm::Constant*, 4> Mask; + SmallVector<llvm::Constant*, 4> Mask; for (unsigned i = 0; i != NumResultElts; ++i) { unsigned InIdx = getAccessedFieldNo(i, Elts); Mask.push_back(llvm::ConstantInt::get(Int32Ty, InIdx)); @@ -929,7 +939,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { llvm::Value *MaskV = llvm::ConstantVector::get(Mask); Vec = Builder.CreateShuffleVector(Vec, llvm::UndefValue::get(Vec->getType()), - MaskV, "tmp"); + MaskV); return RValue::get(Vec); } @@ -943,7 +953,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) { if (Dst.isVectorElt()) { // Read/modify/write the vector, inserting the new element. llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(), - Dst.isVolatileQualified(), "tmp"); + Dst.isVolatileQualified()); Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), Dst.getVectorIdx(), "vecins"); Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified()); @@ -1002,7 +1012,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) { llvm::Value *src = Src.getScalarVal(); if (Dst.isObjCIvar()) { assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL"); - const llvm::Type *ResultType = ConvertType(getContext().LongTy); + llvm::Type *ResultType = ConvertType(getContext().LongTy); llvm::Value *RHS = EmitScalarExpr(Dst.getBaseIvarExp()); llvm::Value *dst = RHS; RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); @@ -1029,7 +1039,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); // Get the output type. - const llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType()); + llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType()); unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); // Get the source value, truncated to the width of the bit-field. @@ -1045,7 +1055,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // Return the new value of the bit-field, if requested. if (Result) { // Cast back to the proper type for result. - const llvm::Type *SrcTy = Src.getScalarVal()->getType(); + llvm::Type *SrcTy = Src.getScalarVal()->getType(); llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false, "bf.reload.val"); @@ -1082,10 +1092,10 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, } // Cast to the access type. - const llvm::Type *AccessLTy = + llvm::Type *AccessLTy = llvm::Type::getIntNTy(getLLVMContext(), AI.AccessWidth); - const llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace); + llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace); Ptr = Builder.CreateBitCast(Ptr, PTy); // Extract the piece of the bit-field value to write in this access, limited @@ -1134,7 +1144,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // This access turns into a read/modify/write of the vector. Load the input // value now. llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(), - Dst.isVolatileQualified(), "tmp"); + Dst.isVolatileQualified()); const llvm::Constant *Elts = Dst.getExtVectorElts(); llvm::Value *SrcVal = Src.getScalarVal(); @@ -1147,7 +1157,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // Use shuffle vector is the src and destination are the same number of // elements and restore the vector mask since it is on the side it will be // stored. - llvm::SmallVector<llvm::Constant*, 4> Mask(NumDstElts); + SmallVector<llvm::Constant*, 4> Mask(NumDstElts); for (unsigned i = 0; i != NumSrcElts; ++i) { unsigned InIdx = getAccessedFieldNo(i, Elts); Mask[InIdx] = llvm::ConstantInt::get(Int32Ty, i); @@ -1156,13 +1166,13 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, llvm::Value *MaskV = llvm::ConstantVector::get(Mask); Vec = Builder.CreateShuffleVector(SrcVal, llvm::UndefValue::get(Vec->getType()), - MaskV, "tmp"); + MaskV); } else if (NumDstElts > NumSrcElts) { // Extended the source vector to the same length and then shuffle it // into the destination. // FIXME: since we're shuffling with undef, can we just use the indices // into that? This could be simpler. - llvm::SmallVector<llvm::Constant*, 4> ExtMask; + SmallVector<llvm::Constant*, 4> ExtMask; unsigned i; for (i = 0; i != NumSrcElts; ++i) ExtMask.push_back(llvm::ConstantInt::get(Int32Ty, i)); @@ -1172,9 +1182,9 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, llvm::Value *ExtSrcVal = Builder.CreateShuffleVector(SrcVal, llvm::UndefValue::get(SrcVal->getType()), - ExtMaskV, "tmp"); + ExtMaskV); // build identity - llvm::SmallVector<llvm::Constant*, 4> Mask; + SmallVector<llvm::Constant*, 4> Mask; for (unsigned i = 0; i != NumDstElts; ++i) Mask.push_back(llvm::ConstantInt::get(Int32Ty, i)); @@ -1184,16 +1194,16 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, Mask[Idx] = llvm::ConstantInt::get(Int32Ty, i+NumDstElts); } llvm::Value *MaskV = llvm::ConstantVector::get(Mask); - Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp"); + Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV); } else { // We should never shorten the vector - assert(0 && "unexpected shorten vector length"); + llvm_unreachable("unexpected shorten vector length"); } } else { // If the Src is a scalar (not a vector) it must be updating one element. unsigned InIdx = getAccessedFieldNo(0, Elts); llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx); - Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); + Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt); } Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified()); @@ -1203,11 +1213,23 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // generating write-barries API. It is currently a global, ivar, // or neither. static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, - LValue &LV) { - if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC) + LValue &LV, + bool IsMemberAccess=false) { + if (Ctx.getLangOptions().getGC() == LangOptions::NonGC) return; if (isa<ObjCIvarRefExpr>(E)) { + QualType ExpTy = E->getType(); + if (IsMemberAccess && ExpTy->isPointerType()) { + // If ivar is a structure pointer, assigning to field of + // this struct follows gcc's behavior and makes it a non-ivar + // writer-barrier conservatively. + ExpTy = ExpTy->getAs<PointerType>()->getPointeeType(); + if (ExpTy->isRecordType()) { + LV.setObjCIvar(false); + return; + } + } LV.setObjCIvar(true); ObjCIvarRefExpr *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr*>(E)); LV.setBaseIvarExp(Exp->getBase()); @@ -1227,12 +1249,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, } if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) { - setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess); return; } if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) { - setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess); if (LV.isObjCIvar()) { // If cast is to a structure pointer, follow gcc's behavior and make it // a non-ivar write-barrier. @@ -1251,17 +1273,17 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, } if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) { - setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess); return; } if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) { - setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess); return; } if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) { - setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess); return; } @@ -1277,9 +1299,9 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LV.setGlobalObjCRef(false); return; } - + if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) { - setObjCGCLValueClass(Ctx, Exp->getBase(), LV); + setObjCGCLValueClass(Ctx, Exp->getBase(), LV, true); // We don't know if member is an 'ivar', but this flag is looked at // only in the context of LV.isObjCIvar(). LV.setObjCArray(E->getType()->isArrayType()); @@ -1290,7 +1312,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, static llvm::Value * EmitBitCastOfLValueToProperType(CodeGenFunction &CGF, llvm::Value *V, llvm::Type *IRType, - llvm::StringRef Name = llvm::StringRef()) { + StringRef Name = StringRef()) { unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace(); return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name); } @@ -1302,7 +1324,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) - V = CGF.Builder.CreateLoad(V, "tmp"); + V = CGF.Builder.CreateLoad(V); V = EmitBitCastOfLValueToProperType(CGF, V, CGF.getTypes().ConvertTypeForMem(E->getType())); @@ -1325,7 +1347,7 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, QualType NoProtoType = CGF.getContext().getFunctionNoProtoType(Proto->getResultType()); NoProtoType = CGF.getContext().getPointerType(NoProtoType); - V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp"); + V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType)); } } unsigned Alignment = CGF.getContext().getDeclAlign(FD).getQuantity(); @@ -1361,7 +1383,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { V = BuildBlockByrefAddress(V, VD); if (VD->getType()->isReferenceType()) - V = Builder.CreateLoad(V, "tmp"); + V = Builder.CreateLoad(V); V = EmitBitCastOfLValueToProperType(*this, V, getTypes().ConvertTypeForMem(E->getType())); @@ -1378,7 +1400,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, fn); - assert(false && "Unhandled DeclRefExpr"); + llvm_unreachable("Unhandled DeclRefExpr"); // an invalid LValue, but the assert will // ensure that this point is never reached. @@ -1398,7 +1420,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType()); switch (E->getOpcode()) { - default: assert(0 && "Unknown unary operator lvalue!"); + default: llvm_unreachable("Unknown unary operator lvalue!"); case UO_Deref: { QualType T = E->getSubExpr()->getType()->getPointeeType(); assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); @@ -1411,7 +1433,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // But, we continue to generate __strong write barrier on indirect write // into a pointer to object. if (getContext().getLangOptions().ObjC1 && - getContext().getLangOptions().getGCMode() != LangOptions::NonGC && + getContext().getLangOptions().getGC() != LangOptions::NonGC && LV.isObjCWeak()) LV.setNonGC(!E->isOBJCGCCandidate(getContext())); return LV; @@ -1474,7 +1496,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { std::string GlobalVarName; switch (Type) { - default: assert(0 && "Invalid type"); + default: llvm_unreachable("Invalid type"); case PredefinedExpr::Func: GlobalVarName = "__func__."; break; @@ -1486,7 +1508,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { break; } - llvm::StringRef FnName = CurFn->getName(); + StringRef FnName = CurFn->getName(); if (FnName.startswith("\01")) FnName = FnName.substr(1); GlobalVarName += FnName; @@ -1646,9 +1668,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { ArrayAlignment = ArrayLV.getAlignment(); if (getContext().getLangOptions().isSignedOverflowDefined()) - Address = Builder.CreateGEP(ArrayPtr, Args, Args+2, "arrayidx"); + Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx"); else - Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx"); + Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx"); } else { // The base must be a pointer, which is not an aggregate. Emit it. llvm::Value *Base = EmitScalarExpr(E->getBase()); @@ -1672,7 +1694,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace()); if (getContext().getLangOptions().ObjC1 && - getContext().getLangOptions().getGCMode() != LangOptions::NonGC) { + getContext().getLangOptions().getGC() != LangOptions::NonGC) { LV.setNonGC(!E->isOBJCGCCandidate(getContext())); setObjCGCLValueClass(getContext(), E, LV); } @@ -1681,10 +1703,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { static llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext, - llvm::SmallVector<unsigned, 4> &Elts) { - llvm::SmallVector<llvm::Constant*, 4> CElts; + SmallVector<unsigned, 4> &Elts) { + SmallVector<llvm::Constant*, 4> CElts; - const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); for (unsigned i = 0, e = Elts.size(); i != e; ++i) CElts.push_back(llvm::ConstantInt::get(Int32Ty, Elts[i])); @@ -1725,7 +1747,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { E->getType().withCVRQualifiers(Base.getQuals().getCVRQualifiers()); // Encode the element access list into a vector of unsigned indices. - llvm::SmallVector<unsigned, 4> Indices; + SmallVector<unsigned, 4> Indices; E->getEncodedElementAccess(Indices); if (Base.isSimple()) { @@ -1735,7 +1757,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!"); llvm::Constant *BaseElts = Base.getExtVectorElts(); - llvm::SmallVector<llvm::Constant *, 4> CElts; + SmallVector<llvm::Constant *, 4> CElts; for (unsigned i = 0, e = Indices.size(); i != e; ++i) { if (isa<llvm::ConstantAggregateZero>(BaseElts)) @@ -1784,8 +1806,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) return EmitFunctionDeclLValue(*this, E, FD); - assert(false && "Unhandled member declaration!"); - return LValue(); + llvm_unreachable("Unhandled member declaration!"); } LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value *BaseValue, @@ -1867,6 +1888,9 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr, CGM.getTypes().ConvertTypeForMem(type), field->getName()); + if (field->hasAttr<AnnotateAttr>()) + addr = EmitFieldAnnotations(field, addr); + unsigned alignment = getContext().getDeclAlign(field).getQuantity(); LValue LV = MakeAddrLValue(addr, type, alignment); LV.getQuals().addCVRQualifiers(cvr); @@ -1896,7 +1920,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue, const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(Field->getParent()); unsigned idx = RL.getLLVMFieldNo(Field); - llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); + llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx); assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); @@ -1904,7 +1928,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue, // for both unions and structs. A union needs a bitcast, a struct element // will need a bitcast if the LLVM type laid out doesn't match the desired // type. - const llvm::Type *llvmType = ConvertTypeForMem(FieldType); + llvm::Type *llvmType = ConvertTypeForMem(FieldType); unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace(); V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS)); @@ -2048,9 +2072,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_BaseToDerivedMemberPointer: case CK_MemberPointerToBoolean: case CK_AnyPointerToBlockPointerCast: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: { + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: { // These casts only produce lvalues when we're binding a reference to a // temporary realized from a (converted) pure rvalue. Emit the expression // as a value, copy it into a temporary, and return an lvalue referring to @@ -2069,7 +2094,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_ConstructorConversion: case CK_UserDefinedConversion: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: return EmitLValue(E->getSubExpr()); case CK_UncheckedDerivedToBase: @@ -2143,8 +2169,7 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) { LValue CodeGenFunction::EmitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - RValue RV = EmitReferenceBindingToExpr(E->GetTemporaryExpr(), - /*InitializedDecl=*/0); + RValue RV = EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0); return MakeAddrLValue(RV.getScalarVal(), E->getType()); } @@ -2155,11 +2180,8 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { - if (CGDebugInfo *DI = getDebugInfo()) { - DI->setLocation(E->getLocStart()); - DI->UpdateLineDirectiveRegion(Builder); - DI->EmitStopPoint(Builder); - } + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitLocation(Builder, E->getLocStart()); // Builtins never have block type. if (E->getCallee()->getType()->isBlockPointerType()) @@ -2168,14 +2190,13 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E)) return EmitCXXMemberCallExpr(CE, ReturnValue); - const Decl *TargetDecl = 0; - if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) { - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) { - TargetDecl = DRE->getDecl(); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(TargetDecl)) - if (unsigned builtinID = FD->getBuiltinID()) - return EmitBuiltinExpr(FD, builtinID, E); - } + if (const CUDAKernelCallExpr *CE = dyn_cast<CUDAKernelCallExpr>(E)) + return EmitCUDAKernelCallExpr(CE, ReturnValue); + + const Decl *TargetDecl = E->getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) { + if (unsigned builtinID = FD->getBuiltinID()) + return EmitBuiltinExpr(FD, builtinID, E); } if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E)) @@ -2306,7 +2327,7 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { assert(E->getType()->getAsCXXRecordDecl()->hasTrivialDestructor() && "binding l-value to type which needs a temporary"); - AggValueSlot Slot = CreateAggTemp(E->getType(), "tmp"); + AggValueSlot Slot = CreateAggTemp(E->getType()); EmitCXXConstructExpr(E, Slot); return MakeAddrLValue(Slot.getAddr(), E->getType()); } @@ -2319,7 +2340,7 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue"); - Slot.setLifetimeExternallyManaged(); + Slot.setExternallyDestructed(); EmitAggExpr(E->getSubExpr(), Slot); EmitCXXTemporary(E->getTemporary(), Slot.getAddr()); return MakeAddrLValue(Slot.getAddr(), E->getType()); @@ -2406,8 +2427,35 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, CallArgList Args; EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); - return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType), - Callee, ReturnValue, Args, TargetDecl); + const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType); + + // C99 6.5.2.2p6: + // If the expression that denotes the called function has a type + // that does not include a prototype, [the default argument + // promotions are performed]. If the number of arguments does not + // equal the number of parameters, the behavior is undefined. If + // the function is defined with a type that includes a prototype, + // and either the prototype ends with an ellipsis (, ...) or the + // types of the arguments after promotion are not compatible with + // the types of the parameters, the behavior is undefined. If the + // function is defined with a type that does not include a + // prototype, and the types of the arguments after promotion are + // not compatible with those of the parameters after promotion, + // the behavior is undefined [except in some trivial cases]. + // That is, in the general case, we should assume that a call + // through an unprototyped function type works like a *non-variadic* + // call. The way we make this work is to cast to the exact type + // of the promoted arguments. + if (isa<FunctionNoProtoType>(FnType) && + !getTargetHooks().isNoProtoCallVariadic(FnType->getCallConv())) { + assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0)) + ->isVarArg()); + llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false); + CalleeTy = CalleeTy->getPointerTo(); + Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast"); + } + + return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl); } LValue CodeGenFunction:: @@ -2428,3 +2476,279 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { return MakeAddrLValue(AddV, MPT->getPointeeType()); } + +static void +EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest, + llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2, + uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) { + if (E->isCmpXChg()) { + // Note that cmpxchg only supports specifying one ordering and + // doesn't support weak cmpxchg, at least at the moment. + llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1); + LoadVal1->setAlignment(Align); + llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2); + LoadVal2->setAlignment(Align); + llvm::AtomicCmpXchgInst *CXI = + CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order); + CXI->setVolatile(E->isVolatile()); + llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1); + StoreVal1->setAlignment(Align); + llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1); + CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType())); + return; + } + + if (E->getOp() == AtomicExpr::Load) { + llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr); + Load->setAtomic(Order); + Load->setAlignment(Size); + Load->setVolatile(E->isVolatile()); + llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest); + StoreDest->setAlignment(Align); + return; + } + + if (E->getOp() == AtomicExpr::Store) { + assert(!Dest && "Store does not return a value"); + llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1); + LoadVal1->setAlignment(Align); + llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr); + Store->setAtomic(Order); + Store->setAlignment(Size); + Store->setVolatile(E->isVolatile()); + return; + } + + llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add; + switch (E->getOp()) { + case AtomicExpr::CmpXchgWeak: + case AtomicExpr::CmpXchgStrong: + case AtomicExpr::Store: + case AtomicExpr::Load: assert(0 && "Already handled!"); + case AtomicExpr::Add: Op = llvm::AtomicRMWInst::Add; break; + case AtomicExpr::Sub: Op = llvm::AtomicRMWInst::Sub; break; + case AtomicExpr::And: Op = llvm::AtomicRMWInst::And; break; + case AtomicExpr::Or: Op = llvm::AtomicRMWInst::Or; break; + case AtomicExpr::Xor: Op = llvm::AtomicRMWInst::Xor; break; + case AtomicExpr::Xchg: Op = llvm::AtomicRMWInst::Xchg; break; + } + llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1); + LoadVal1->setAlignment(Align); + llvm::AtomicRMWInst *RMWI = + CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order); + RMWI->setVolatile(E->isVolatile()); + llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(RMWI, Dest); + StoreDest->setAlignment(Align); +} + +// This function emits any expression (scalar, complex, or aggregate) +// into a temporary alloca. +static llvm::Value * +EmitValToTemp(CodeGenFunction &CGF, Expr *E) { + llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp"); + CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(), + /*Init*/ true); + return DeclPtr; +} + +static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty, + llvm::Value *Dest) { + if (Ty->isAnyComplexType()) + return RValue::getComplex(CGF.LoadComplexFromAddr(Dest, false)); + if (CGF.hasAggregateLLVMType(Ty)) + return RValue::getAggregate(Dest); + return RValue::get(CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(Dest, Ty))); +} + +RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { + QualType AtomicTy = E->getPtr()->getType()->getPointeeType(); + QualType MemTy = AtomicTy->getAs<AtomicType>()->getValueType(); + CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy); + uint64_t Size = sizeChars.getQuantity(); + CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy); + unsigned Align = alignChars.getQuantity(); + unsigned MaxInlineWidth = + getContext().getTargetInfo().getMaxAtomicInlineWidth(); + bool UseLibcall = (Size != Align || Size > MaxInlineWidth); + + llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0; + Ptr = EmitScalarExpr(E->getPtr()); + Order = EmitScalarExpr(E->getOrder()); + if (E->isCmpXChg()) { + Val1 = EmitScalarExpr(E->getVal1()); + Val2 = EmitValToTemp(*this, E->getVal2()); + OrderFail = EmitScalarExpr(E->getOrderFail()); + (void)OrderFail; // OrderFail is unused at the moment + } else if ((E->getOp() == AtomicExpr::Add || E->getOp() == AtomicExpr::Sub) && + MemTy->isPointerType()) { + // For pointers, we're required to do a bit of math: adding 1 to an int* + // is not the same as adding 1 to a uintptr_t. + QualType Val1Ty = E->getVal1()->getType(); + llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1()); + CharUnits PointeeIncAmt = + getContext().getTypeSizeInChars(MemTy->getPointeeType()); + Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt)); + Val1 = CreateMemTemp(Val1Ty, ".atomictmp"); + EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty)); + } else if (E->getOp() != AtomicExpr::Load) { + Val1 = EmitValToTemp(*this, E->getVal1()); + } + + if (E->getOp() != AtomicExpr::Store && !Dest) + Dest = CreateMemTemp(E->getType(), ".atomicdst"); + + if (UseLibcall) { + // FIXME: Finalize what the libcalls are actually supposed to look like. + // See also http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary . + return EmitUnsupportedRValue(E, "atomic library call"); + } +#if 0 + if (UseLibcall) { + const char* LibCallName; + switch (E->getOp()) { + case AtomicExpr::CmpXchgWeak: + LibCallName = "__atomic_compare_exchange_generic"; break; + case AtomicExpr::CmpXchgStrong: + LibCallName = "__atomic_compare_exchange_generic"; break; + case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break; + case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break; + case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break; + case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break; + case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break; + case AtomicExpr::Xchg: LibCallName = "__atomic_exchange_generic"; break; + case AtomicExpr::Store: LibCallName = "__atomic_store_generic"; break; + case AtomicExpr::Load: LibCallName = "__atomic_load_generic"; break; + } + llvm::SmallVector<QualType, 4> Params; + CallArgList Args; + QualType RetTy = getContext().VoidTy; + if (E->getOp() != AtomicExpr::Store && !E->isCmpXChg()) + Args.add(RValue::get(EmitCastToVoidPtr(Dest)), + getContext().VoidPtrTy); + Args.add(RValue::get(EmitCastToVoidPtr(Ptr)), + getContext().VoidPtrTy); + if (E->getOp() != AtomicExpr::Load) + Args.add(RValue::get(EmitCastToVoidPtr(Val1)), + getContext().VoidPtrTy); + if (E->isCmpXChg()) { + Args.add(RValue::get(EmitCastToVoidPtr(Val2)), + getContext().VoidPtrTy); + RetTy = getContext().IntTy; + } + Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)), + getContext().getSizeType()); + const CGFunctionInfo &FuncInfo = + CGM.getTypes().getFunctionInfo(RetTy, Args, FunctionType::ExtInfo()); + llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo, false); + llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName); + RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args); + if (E->isCmpXChg()) + return Res; + if (E->getOp() == AtomicExpr::Store) + return RValue::get(0); + return ConvertTempToRValue(*this, E->getType(), Dest); + } +#endif + llvm::Type *IPtrTy = + llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo(); + llvm::Value *OrigDest = Dest; + Ptr = Builder.CreateBitCast(Ptr, IPtrTy); + if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy); + if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy); + if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy); + + if (isa<llvm::ConstantInt>(Order)) { + int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); + switch (ord) { + case 0: // memory_order_relaxed + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Monotonic); + break; + case 1: // memory_order_consume + case 2: // memory_order_acquire + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Acquire); + break; + case 3: // memory_order_release + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Release); + break; + case 4: // memory_order_acq_rel + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::AcquireRelease); + break; + case 5: // memory_order_seq_cst + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::SequentiallyConsistent); + break; + default: // invalid order + // We should not ever get here normally, but it's hard to + // enforce that in general. + break; + } + if (E->getOp() == AtomicExpr::Store) + return RValue::get(0); + return ConvertTempToRValue(*this, E->getType(), OrigDest); + } + + // Long case, when Order isn't obviously constant. + + // Create all the relevant BB's + llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0, + *AcqRelBB = 0, *SeqCstBB = 0; + MonotonicBB = createBasicBlock("monotonic", CurFn); + if (E->getOp() != AtomicExpr::Store) + AcquireBB = createBasicBlock("acquire", CurFn); + if (E->getOp() != AtomicExpr::Load) + ReleaseBB = createBasicBlock("release", CurFn); + if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store) + AcqRelBB = createBasicBlock("acqrel", CurFn); + SeqCstBB = createBasicBlock("seqcst", CurFn); + llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn); + + // Create the switch for the split + // MonotonicBB is arbitrarily chosen as the default case; in practice, this + // doesn't matter unless someone is crazy enough to use something that + // doesn't fold to a constant for the ordering. + Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); + llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB); + + // Emit all the different atomics + Builder.SetInsertPoint(MonotonicBB); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Monotonic); + Builder.CreateBr(ContBB); + if (E->getOp() != AtomicExpr::Store) { + Builder.SetInsertPoint(AcquireBB); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Acquire); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(1), AcquireBB); + SI->addCase(Builder.getInt32(2), AcquireBB); + } + if (E->getOp() != AtomicExpr::Load) { + Builder.SetInsertPoint(ReleaseBB); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::Release); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(3), ReleaseBB); + } + if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store) { + Builder.SetInsertPoint(AcqRelBB); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::AcquireRelease); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(4), AcqRelBB); + } + Builder.SetInsertPoint(SeqCstBB); + EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, + llvm::SequentiallyConsistent); + Builder.CreateBr(ContBB); + SI->addCase(Builder.getInt32(5), SeqCstBB); + + // Cleanup and return + Builder.SetInsertPoint(ContBB); + if (E->getOp() == AtomicExpr::Store) + return RValue::get(0); + return ConvertTempToRValue(*this, E->getType(), OrigDest); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp index 915ffd6..97754d5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp @@ -35,11 +35,18 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { AggValueSlot Dest; bool IgnoreResult; + /// We want to use 'dest' as the return slot except under two + /// conditions: + /// - The destination slot requires garbage collection, so we + /// need to use the GC API. + /// - The destination slot is potentially aliased. + bool shouldUseDestForReturnSlot() const { + return !(Dest.requiresGCollection() || Dest.isPotentiallyAliased()); + } + ReturnValueSlot getReturnValueSlot() const { - // If the destination slot requires garbage collection, we can't - // use the real return value slot, because we have to use the GC - // API. - if (Dest.requiresGCollection()) return ReturnValueSlot(); + if (!shouldUseDestForReturnSlot()) + return ReturnValueSlot(); return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile()); } @@ -69,7 +76,13 @@ public: void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false); void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false); - void EmitGCMove(const Expr *E, RValue Src); + void EmitMoveFromReturnSlot(const Expr *E, RValue Src); + + AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) { + if (CGF.getLangOptions().getGC() && TypeRequiresGCollection(T)) + return AggValueSlot::NeedsGCBarriers; + return AggValueSlot::DoesNotNeedGCBarriers; + } bool TypeRequiresGCollection(QualType T); @@ -141,6 +154,9 @@ public: void EmitNullInitializationToLValue(LValue Address); // case Expr::ChooseExprClass: void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); } + void VisitAtomicExpr(AtomicExpr *E) { + CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr()); + } }; } // end anonymous namespace. @@ -173,23 +189,27 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) { return Record->hasObjectMember(); } -/// \brief Perform the final move to DestPtr if RequiresGCollection is set. +/// \brief Perform the final move to DestPtr if for some reason +/// getReturnValueSlot() didn't use it directly. /// /// The idea is that you do something like this: /// RValue Result = EmitSomething(..., getReturnValueSlot()); -/// EmitGCMove(E, Result); -/// If GC doesn't interfere, this will cause the result to be emitted -/// directly into the return value slot. If GC does interfere, a final -/// move will be performed. -void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { - if (Dest.requiresGCollection()) { - CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType()); - const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); - CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), - Src.getAggregateAddr(), - SizeVal); +/// EmitMoveFromReturnSlot(E, Result); +/// +/// If nothing interferes, this will cause the result to be emitted +/// directly into the return value slot. Otherwise, a final move +/// will be performed. +void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) { + if (shouldUseDestForReturnSlot()) { + // Logically, Dest.getAddr() should equal Src.getAggregateAddr(). + // The possibility of undef rvalues complicates that a lot, + // though, so we can't really assert. + return; } + + // Otherwise, do a final copy, + assert(Dest.getAddr() != Src.getAggregateAddr()); + EmitFinalDestCopy(E, Src, /*Ignore*/ true); } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. @@ -215,7 +235,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { if (Dest.requiresGCollection()) { CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType()); - const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), @@ -301,16 +321,15 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_DerivedToBase: case CK_BaseToDerived: case CK_UncheckedDerivedToBase: { - assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: " + llvm_unreachable("cannot perform hierarchy conversion in EmitAggExpr: " "should have been unpacked before we got here"); - break; } case CK_GetObjCProperty: { LValue LV = CGF.EmitLValue(E->getSubExpr()); assert(LV.isPropertyRef()); RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); break; } @@ -348,7 +367,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: @@ -361,9 +381,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: llvm_unreachable("cast kind invalid for aggregate types"); } } @@ -375,12 +396,12 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { } RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); } void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); } void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { @@ -426,10 +447,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // as it may change the 'forwarding' field via call to Block_copy. LValue RHS = CGF.EmitLValue(E->getRHS()); LValue LHS = CGF.EmitLValue(E->getLHS()); - bool GCollection = false; - if (CGF.getContext().getLangOptions().getGCMode()) - GCollection = TypeRequiresGCollection(E->getLHS()->getType()); - Dest = AggValueSlot::forLValue(LHS, true, GCollection); + Dest = AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, + needsGC(E->getLHS()->getType()), + AggValueSlot::IsAliased); EmitFinalDestCopy(E, RHS, true); return; } @@ -451,13 +471,11 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { } CGF.EmitStoreThroughPropertyRefLValue(Src, LHS); } else { - bool GCollection = false; - if (CGF.getContext().getLangOptions().getGCMode()) - GCollection = TypeRequiresGCollection(E->getLHS()->getType()); - // Codegen the RHS so that it stores directly into the LHS. - AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true, - GCollection); + AggValueSlot LHSSlot = + AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, + needsGC(E->getLHS()->getType()), + AggValueSlot::IsAliased); CGF.EmitAggExpr(E->getRHS(), LHSSlot, false); EmitFinalDestCopy(E, LHS, true); } @@ -476,7 +494,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); // Save whether the destination's lifetime is externally managed. - bool DestLifetimeManaged = Dest.isLifetimeExternallyManaged(); + bool isExternallyDestructed = Dest.isExternallyDestructed(); eval.begin(CGF); CGF.EmitBlock(LHSBlock); @@ -489,8 +507,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { // If the result of an agg expression is unused, then the emission // of the LHS might need to create a destination slot. That's fine // with us, and we can safely emit the RHS into the same slot, but - // we shouldn't claim that its lifetime is externally managed. - Dest.setLifetimeExternallyManaged(DestLifetimeManaged); + // we shouldn't claim that it's already being destructed. + Dest.setExternallyDestructed(isExternallyDestructed); eval.begin(CGF); CGF.EmitBlock(RHSBlock); @@ -518,16 +536,17 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { // Ensure that we have a slot, but if we already do, remember - // whether its lifetime was externally managed. - bool WasManaged = Dest.isLifetimeExternallyManaged(); + // whether it was externally destructed. + bool wasExternallyDestructed = Dest.isExternallyDestructed(); Dest = EnsureSlot(E->getType()); - Dest.setLifetimeExternallyManaged(); + + // We're going to push a destructor if there isn't already one. + Dest.setExternallyDestructed(); Visit(E->getSubExpr()); - // Set up the temporary's destructor if its lifetime wasn't already - // being managed. - if (!WasManaged) + // Push that destructor we promised. + if (!wasExternallyDestructed) CGF.EmitCXXTemporary(E->getTemporary(), Dest.getAddr()); } @@ -596,7 +615,10 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { } else if (type->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false); } else if (CGF.hasAggregateLLVMType(type)) { - CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, true, false, + CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, Dest.isZeroed())); } else if (LV.isSimple()) { CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false); @@ -647,9 +669,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // Handle initialization of an array. if (E->getType()->isArrayType()) { - const llvm::PointerType *APType = + llvm::PointerType *APType = cast<llvm::PointerType>(DestPtr->getType()); - const llvm::ArrayType *AType = + llvm::ArrayType *AType = cast<llvm::ArrayType>(APType->getElementType()); uint64_t NumInitElements = E->getNumInits(); @@ -676,7 +698,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); llvm::Value *indices[] = { zero, zero }; llvm::Value *begin = - Builder.CreateInBoundsGEP(DestPtr, indices, indices+2, "arrayinit.begin"); + Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin"); // Exception safety requires us to destroy all the // already-constructed members if an initializer throws. @@ -839,7 +861,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // We'll need to enter cleanup scopes in case any of the member // initializers throw an exception. - llvm::SmallVector<EHScopeStack::stable_iterator, 16> cleanups; + SmallVector<EHScopeStack::stable_iterator, 16> cleanups; // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. @@ -948,7 +970,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { // Reference values are always non-null and have the width of a pointer. if (Field->getType()->isReferenceType()) NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits( - CGF.getContext().Target.getPointerWidth(0)); + CGF.getContext().getTargetInfo().getPointerWidth(0)); else NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF); } @@ -999,7 +1021,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E, CharUnits Align = TypeInfo.second; llvm::Value *Loc = Slot.getAddr(); - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); Loc = CGF.Builder.CreateBitCast(Loc, BP); CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, @@ -1036,7 +1058,9 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!"); llvm::Value *Temp = CreateMemTemp(E->getType()); LValue LV = MakeAddrLValue(Temp, E->getType()); - EmitAggExpr(E, AggValueSlot::forLValue(LV, false)); + EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); return LV; } @@ -1049,7 +1073,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); assert((Record->hasTrivialCopyConstructor() || - Record->hasTrivialCopyAssignment()) && + Record->hasTrivialCopyAssignment() || + Record->hasTrivialMoveConstructor() || + Record->hasTrivialMoveAssignment()) && "Trying to aggregate-copy a type without a trivial copy " "constructor or assignment operator"); // Ignore empty classes in C++. @@ -1088,24 +1114,24 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, // we need to use a different call here. We use isVolatile to indicate when // either the source or the destination is volatile. - const llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType()); - const llvm::Type *DBP = + llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType()); + llvm::Type *DBP = llvm::Type::getInt8PtrTy(getLLVMContext(), DPT->getAddressSpace()); - DestPtr = Builder.CreateBitCast(DestPtr, DBP, "tmp"); + DestPtr = Builder.CreateBitCast(DestPtr, DBP); - const llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType()); - const llvm::Type *SBP = + llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType()); + llvm::Type *SBP = llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace()); - SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp"); + SrcPtr = Builder.CreateBitCast(SrcPtr, SBP); // Don't do any of the memmove_collectable tests if GC isn't set. - if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) { + if (CGM.getLangOptions().getGC() == LangOptions::NonGC) { // fall through } else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { RecordDecl *Record = RecordTy->getDecl(); if (Record->hasObjectMember()) { CharUnits size = TypeInfo.first; - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); @@ -1116,7 +1142,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) { if (RecordTy->getDecl()->hasObjectMember()) { CharUnits size = TypeInfo.first; - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp index 4396f56..78db590 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp @@ -13,6 +13,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "CodeGenFunction.h" +#include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGDebugInfo.h" @@ -206,16 +207,17 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, cast<CXXConstructorDecl>(MD)->isDefaultConstructor()) return RValue::get(0); - if (MD->isCopyAssignmentOperator()) { - // We don't like to generate the trivial copy assignment operator when - // it isn't necessary; just produce the proper effect here. + if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) { + // We don't like to generate the trivial copy/move assignment operator + // when it isn't necessary; just produce the proper effect here. llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); EmitAggregateCopy(This, RHS, CE->getType()); return RValue::get(This); } if (isa<CXXConstructorDecl>(MD) && - cast<CXXConstructorDecl>(MD)->isCopyConstructor()) { + cast<CXXConstructorDecl>(MD)->isCopyOrMoveConstructor()) { + // Trivial move and copy ctor are the same. llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); EmitSynthesizedCXXCopyCtorCall(cast<CXXConstructorDecl>(MD), This, RHS, CE->arg_begin(), CE->arg_end()); @@ -236,7 +238,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, FInfo = &CGM.getTypes().getFunctionInfo(MD); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty + llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic()); // C++ [class.virtual]p12: @@ -333,16 +335,12 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, LValue LV = EmitLValue(E->getArg(0)); llvm::Value *This = LV.getAddress(); - if (MD->isCopyAssignmentOperator()) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext()); - if (ClassDecl->hasTrivialCopyAssignment()) { - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); - llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); - QualType Ty = E->getType(); - EmitAggregateCopy(This, Src, Ty); - return RValue::get(This); - } + if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) && + MD->isTrivial()) { + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); + QualType Ty = E->getType(); + EmitAggregateCopy(This, Src, Ty); + return RValue::get(This); } llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This); @@ -350,6 +348,54 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, E->arg_begin() + 1, E->arg_end()); } +RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, + ReturnValueSlot ReturnValue) { + return CGM.getCUDARuntime().EmitCUDAKernelCallExpr(*this, E, ReturnValue); +} + +static void EmitNullBaseClassInitialization(CodeGenFunction &CGF, + llvm::Value *DestPtr, + const CXXRecordDecl *Base) { + if (Base->isEmpty()) + return; + + DestPtr = CGF.EmitCastToVoidPtr(DestPtr); + + const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Base); + CharUnits Size = Layout.getNonVirtualSize(); + CharUnits Align = Layout.getNonVirtualAlign(); + + llvm::Value *SizeVal = CGF.CGM.getSize(Size); + + // If the type contains a pointer to data member we can't memset it to zero. + // Instead, create a null constant and copy it to the destination. + // TODO: there are other patterns besides zero that we can usefully memset, + // like -1, which happens to be the pattern used by member-pointers. + // TODO: isZeroInitializable can be over-conservative in the case where a + // virtual base contains a member pointer. + if (!CGF.CGM.getTypes().isZeroInitializable(Base)) { + llvm::Constant *NullConstant = CGF.CGM.EmitNullConstantForBase(Base); + + llvm::GlobalVariable *NullVariable = + new llvm::GlobalVariable(CGF.CGM.getModule(), NullConstant->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + NullConstant, Twine()); + NullVariable->setAlignment(Align.getQuantity()); + llvm::Value *SrcPtr = CGF.EmitCastToVoidPtr(NullVariable); + + // Get and call the appropriate llvm.memcpy overload. + CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity()); + return; + } + + // Otherwise, just memset the whole thing to zero. This is legal + // because in LLVM, all default initializers (other than the ones we just + // handled above) are guaranteed to have a bit pattern of all zeros. + CGF.Builder.CreateMemSet(DestPtr, CGF.Builder.getInt8(0), SizeVal, + Align.getQuantity()); +} + void CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest) { @@ -360,8 +406,19 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, // constructor, as can be the case with a non-user-provided default // constructor, emit the zero initialization now, unless destination is // already zeroed. - if (E->requiresZeroInitialization() && !Dest.isZeroed()) - EmitNullInitialization(Dest.getAddr(), E->getType()); + if (E->requiresZeroInitialization() && !Dest.isZeroed()) { + switch (E->getConstructionKind()) { + case CXXConstructExpr::CK_Delegating: + assert(0 && "Delegating constructor should not need zeroing"); + case CXXConstructExpr::CK_Complete: + EmitNullInitialization(Dest.getAddr(), E->getType()); + break; + case CXXConstructExpr::CK_VirtualBase: + case CXXConstructExpr::CK_NonVirtualBase: + EmitNullBaseClassInitialization(*this, Dest.getAddr(), CD->getParent()); + break; + } + } // If this is a call to a trivial default constructor, do nothing. if (CD->isTrivial() && CD->isDefaultConstructor()) @@ -483,7 +540,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, // the cookie size would bring the total size >= 0. bool isSigned = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType(); - const llvm::IntegerType *numElementsType + llvm::IntegerType *numElementsType = cast<llvm::IntegerType>(numElements->getType()); unsigned numElementsWidth = numElementsType->getBitWidth(); @@ -703,63 +760,85 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, AllocType.isVolatileQualified()); else { AggValueSlot Slot - = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), true); + = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); CGF.EmitAggExpr(Init, Slot); } } void CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, - llvm::Value *NewPtr, - llvm::Value *NumElements) { + QualType elementType, + llvm::Value *beginPtr, + llvm::Value *numElements) { // We have a POD type. if (E->getNumConstructorArgs() == 0) return; - - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); - llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); - Builder.CreateStore(Zero, IndexPtr); - - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the constructor call on the array element. - Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *Address = Builder.CreateInBoundsGEP(NewPtr, Counter, - "arrayidx"); - StoreAnyExprIntoOneUnit(*this, E, Address); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); + + // Check if the number of elements is constant. + bool checkZero = true; + if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) { + // If it's constant zero, skip the whole loop. + if (constNum->isZero()) return; + + checkZero = false; + } + + // Find the end of the array, hoisted out of the loop. + llvm::Value *endPtr = + Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end"); + + // Create the continuation block. + llvm::BasicBlock *contBB = createBasicBlock("new.loop.end"); + + // If we need to check for zero, do so now. + if (checkZero) { + llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty"); + llvm::Value *isEmpty = Builder.CreateICmpEQ(beginPtr, endPtr, + "array.isempty"); + Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB); + EmitBlock(nonEmptyBB); + } + + // Enter the loop. + llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); + llvm::BasicBlock *loopBB = createBasicBlock("new.loop"); + + EmitBlock(loopBB); + + // Set up the current-element phi. + llvm::PHINode *curPtr = + Builder.CreatePHI(beginPtr->getType(), 2, "array.cur"); + curPtr->addIncoming(beginPtr, entryBB); + + // Enter a partial-destruction cleanup if necessary. + QualType::DestructionKind dtorKind = elementType.isDestructedType(); + EHScopeStack::stable_iterator cleanup; + if (needsEHCleanup(dtorKind)) { + pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType, + getDestroyer(dtorKind)); + cleanup = EHStack.stable_begin(); + } + + // Emit the initializer into this element. + StoreAnyExprIntoOneUnit(*this, E, curPtr); + + // Leave the cleanup if we entered one. + if (cleanup != EHStack.stable_end()) + DeactivateCleanupBlock(cleanup); + + // Advance to the next element. + llvm::Value *nextPtr = Builder.CreateConstGEP1_32(curPtr, 1, "array.next"); + + // Check whether we've gotten to the end of the array and, if so, + // exit the loop. + llvm::Value *isEnd = Builder.CreateICmpEQ(nextPtr, endPtr, "array.atend"); + Builder.CreateCondBr(isEnd, contBB, loopBB); + curPtr->addIncoming(nextPtr, Builder.GetInsertBlock()); + + EmitBlock(contBB); } static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T, @@ -771,6 +850,7 @@ static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T, } static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, + QualType ElementType, llvm::Value *NewPtr, llvm::Value *NumElements, llvm::Value *AllocSizeWithoutCookie) { @@ -783,11 +863,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, if (!E->hasInitializer() || Ctor->getParent()->isEmpty()) return; - if (CGF.CGM.getTypes().isZeroInitializable(E->getAllocatedType())) { + if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) { // Optimization: since zero initialization will just set the memory // to all zeroes, generate a single memset to do it in one shot. - EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr, - AllocSizeWithoutCookie); + EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie); return; } @@ -803,11 +882,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) { // Optimization: since zero initialization will just set the memory // to all zeroes, generate a single memset to do it in one shot. - EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr, - AllocSizeWithoutCookie); - return; + EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie); + return; } else { - CGF.EmitNewArrayInitializer(E, NewPtr, NumElements); + CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements); return; } } @@ -819,7 +897,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, if (E->hasInitializer() && !Ctor->getParent()->hasUserDeclaredConstructor() && !Ctor->getParent()->isEmpty()) - CGF.EmitNullInitialization(NewPtr, E->getAllocatedType()); + CGF.EmitNullInitialization(NewPtr, ElementType); CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, NewPtr, E->constructor_arg_begin(), @@ -1086,15 +1164,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { Builder.CreateCondBr(isNull, contBB, notNullBB); EmitBlock(notNullBB); } - - assert((allocSize == allocSizeWithoutCookie) == - CalculateCookiePadding(*this, E).isZero()); - if (allocSize != allocSizeWithoutCookie) { - assert(E->isArray()); - allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation, - numElements, - E, allocType); - } // If there's an operator delete, enter a cleanup to call it if an // exception is thrown. @@ -1105,21 +1174,28 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { operatorDeleteCleanup = EHStack.stable_begin(); } - const llvm::Type *elementPtrTy + assert((allocSize == allocSizeWithoutCookie) == + CalculateCookiePadding(*this, E).isZero()); + if (allocSize != allocSizeWithoutCookie) { + assert(E->isArray()); + allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation, + numElements, + E, allocType); + } + + llvm::Type *elementPtrTy = ConvertTypeForMem(allocType)->getPointerTo(AS); llvm::Value *result = Builder.CreateBitCast(allocation, elementPtrTy); + EmitNewInitializer(*this, E, allocType, result, numElements, + allocSizeWithoutCookie); if (E->isArray()) { - EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie); - // NewPtr is a pointer to the base element type. If we're // allocating an array of arrays, we'll need to cast back to the // array pointer type. - const llvm::Type *resultType = ConvertTypeForMem(E->getType()); + llvm::Type *resultType = ConvertTypeForMem(E->getType()); if (result->getType() != resultType) result = Builder.CreateBitCast(result, resultType); - } else { - EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie); } // Deactivate the 'operator delete' cleanup if we finished @@ -1206,7 +1282,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor = 0; if (const RecordType *RT = ElementType->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!RD->hasTrivialDestructor()) { + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) { Dtor = RD->getDestructor(); if (Dtor->isVirtual()) { @@ -1218,7 +1294,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF, ElementType); } - const llvm::Type *Ty = + llvm::Type *Ty = CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor, Dtor_Complete), /*isVariadic=*/false); @@ -1307,7 +1383,7 @@ namespace { // Pass the original requested size as the second argument. if (DeleteFTy->getNumArgs() == 2) { QualType size_t = DeleteFTy->getArgType(1); - const llvm::IntegerType *SizeTy + llvm::IntegerType *SizeTy = cast<llvm::IntegerType>(CGF.ConvertType(size_t)); CharUnits ElementTypeSize = @@ -1406,7 +1482,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType(); if (DeleteTy->isConstantArrayType()) { llvm::Value *Zero = Builder.getInt32(0); - llvm::SmallVector<llvm::Value*,8> GEP; + SmallVector<llvm::Value*,8> GEP; GEP.push_back(Zero); // point at the outermost array @@ -1420,7 +1496,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { GEP.push_back(Zero); } - Ptr = Builder.CreateInBoundsGEP(Ptr, GEP.begin(), GEP.end(), "del.first"); + Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, "del.first"); } assert(ConvertTypeForMem(DeleteTy) == @@ -1439,8 +1515,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) { // void __cxa_bad_typeid(); - const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); - const llvm::FunctionType *FTy = + llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); @@ -1454,7 +1530,7 @@ static void EmitBadTypeidCall(CodeGenFunction &CGF) { static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, - const llvm::Type *StdTypeInfoPtrTy) { + llvm::Type *StdTypeInfoPtrTy) { // Get the vtable pointer. llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress(); @@ -1487,7 +1563,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, } llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { - const llvm::Type *StdTypeInfoPtrTy = + llvm::Type *StdTypeInfoPtrTy = ConvertType(E->getType())->getPointerTo(); if (E->isTypeOperand()) { @@ -1528,7 +1604,7 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) { llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy }; - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"); @@ -1537,8 +1613,8 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) { static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) { // void __cxa_bad_cast(); - const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); - const llvm::FunctionType *FTy = + llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast"); @@ -1554,9 +1630,9 @@ static llvm::Value * EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, QualType SrcTy, QualType DestTy, llvm::BasicBlock *CastEnd) { - const llvm::Type *PtrDiffLTy = + llvm::Type *PtrDiffLTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); - const llvm::Type *DestLTy = CGF.ConvertType(DestTy); + llvm::Type *DestLTy = CGF.ConvertType(DestTy); if (const PointerType *PTy = DestTy->getAs<PointerType>()) { if (PTy->getPointeeType()->isVoidType()) { @@ -1626,7 +1702,7 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, QualType DestTy) { - const llvm::Type *DestLTy = CGF.ConvertType(DestTy); + llvm::Type *DestLTy = CGF.ConvertType(DestTy); if (DestTy->isPointerType()) return llvm::Constant::getNullValue(DestLTy); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp index 35cff1d..4a31bcf 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp @@ -103,8 +103,7 @@ public: ComplexPairTy VisitStmt(Stmt *S) { S->dump(CGF.getContext().getSourceManager()); - assert(0 && "Stmt can't have complex result type!"); - return ComplexPairTy(); + llvm_unreachable("Stmt can't have complex result type!"); } ComplexPairTy VisitExpr(Expr *S); ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} @@ -119,6 +118,7 @@ public: // l-values. ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitBlockDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E); } @@ -266,6 +266,10 @@ public: ComplexPairTy VisitInitListExpr(InitListExpr *E); ComplexPairTy VisitVAArgExpr(VAArgExpr *E); + + ComplexPairTy VisitAtomicExpr(AtomicExpr *E) { + return CGF.EmitAtomicExpr(E).getComplexVal(); + } }; } // end anonymous namespace. @@ -312,8 +316,8 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr, ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) { CGF.ErrorUnsupported(E, "complex expression"); - const llvm::Type *EltTy = - CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType()); + llvm::Type *EltTy = + CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return ComplexPairTy(U, U); } @@ -402,16 +406,18 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: @@ -524,40 +530,40 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *DSTr, *DSTi; if (Op.LHS.first->getType()->isFloatingPointTy()) { // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) - llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c - llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d - llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2, "tmp"); // ac+bd + llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr); // a*c + llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi); // b*d + llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2); // ac+bd - llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr, "tmp"); // c*c - llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi, "tmp"); // d*d - llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5, "tmp"); // cc+dd + llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr); // c*c + llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi); // d*d + llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5); // cc+dd - llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr, "tmp"); // b*c - llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi, "tmp"); // a*d - llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8, "tmp"); // bc-ad + llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr); // b*c + llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi); // a*d + llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8); // bc-ad - DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp"); + DSTr = Builder.CreateFDiv(Tmp3, Tmp6); + DSTi = Builder.CreateFDiv(Tmp9, Tmp6); } else { // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) - llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c - llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d - llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd + llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr); // a*c + llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi); // b*d + llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2); // ac+bd - llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c - llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d - llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd + llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr); // c*c + llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi); // d*d + llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5); // cc+dd - llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c - llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d - llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad + llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr); // b*c + llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d + llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad if (Op.Ty->getAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) { - DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp"); + DSTr = Builder.CreateUDiv(Tmp3, Tmp6); + DSTi = Builder.CreateUDiv(Tmp9, Tmp6); } else { - DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp"); + DSTr = Builder.CreateSDiv(Tmp3, Tmp6); + DSTi = Builder.CreateSDiv(Tmp9, Tmp6); } } @@ -735,12 +741,19 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) { Ignore = TestAndClearIgnoreImag(); (void)Ignore; assert (Ignore == false && "init list ignored"); - if (E->getNumInits()) + + if (E->getNumInits() == 2) { + llvm::Value *Real = CGF.EmitScalarExpr(E->getInit(0)); + llvm::Value *Imag = CGF.EmitScalarExpr(E->getInit(1)); + return ComplexPairTy(Real, Imag); + } else if (E->getNumInits() == 1) { return Visit(E->getInit(0)); + } // Empty init list intializes to null + assert(E->getNumInits() == 0 && "Unexpected number of inits"); QualType Ty = E->getType()->getAs<ComplexType>()->getElementType(); - const llvm::Type* LTy = CGF.ConvertType(Ty); + llvm::Type* LTy = CGF.ConvertType(Ty); llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy); return ComplexPairTy(zeroConstant, zeroConstant); } @@ -751,7 +764,7 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) { if (!ArgPtr) { CGF.ErrorUnsupported(E, "complex va_arg expression"); - const llvm::Type *EltTy = + llvm::Type *EltTy = CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return ComplexPairTy(U, U); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp index 45e44dd..3997866 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp @@ -138,13 +138,12 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, // We need to add padding. CharUnits PadSize = Context.toCharUnitsFromBits( llvm::RoundUpToAlignment(FieldOffset - NextFieldOffsetInBits, - Context.Target.getCharAlign())); + Context.getTargetInfo().getCharAlign())); AppendPadding(PadSize); } - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t FieldSize = Field->getBitWidthValue(Context); llvm::APInt FieldValue = CI->getValue(); @@ -213,7 +212,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, // padding and then an hole for our i8 to get plopped into. assert(isa<llvm::ArrayType>(LastElt->getType()) && "Expected array padding of undefs"); - const llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType()); + llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType()); assert(AT->getElementType()->isIntegerTy(CharWidth) && AT->getNumElements() != 0 && "Expected non-empty array padding of undefs"); @@ -281,7 +280,7 @@ void ConstStructBuilder::AppendPadding(CharUnits PadSize) { if (PadSize.isZero()) return; - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); if (PadSize > CharUnits::One()) Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity()); @@ -317,7 +316,7 @@ void ConstStructBuilder::ConvertStructToPacked() { CharUnits NumChars = AlignedElementOffsetInChars - ElementOffsetInChars; - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); if (NumChars > CharUnits::One()) Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity()); @@ -364,7 +363,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { continue; // Don't emit anonymous bitfields, they just affect layout. - if (Field->isBitField() && !Field->getIdentifier()) { + if (Field->isUnnamedBitfield()) { LastFD = (*Field); continue; } @@ -435,11 +434,11 @@ llvm::Constant *ConstStructBuilder:: // Pick the type to use. If the type is layout identical to the ConvertType // type then use it, otherwise use whatever the builder produced for us. - const llvm::StructType *STy = + llvm::StructType *STy = llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(), Builder.Elements,Builder.Packed); - const llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType()); - if (const llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) { + llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType()); + if (llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) { if (ILESTy->isLayoutIdentical(STy)) STy = ILESTy; } @@ -513,7 +512,7 @@ public: llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(), E->getRHS()->getType(), CGF); - const llvm::Type *ResultType = ConvertType(E->getType()); + llvm::Type *ResultType = ConvertType(E->getType()); LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType); RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType); @@ -527,7 +526,7 @@ public: llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF); if (!C) return 0; - const llvm::Type *destType = ConvertType(E->getType()); + llvm::Type *destType = ConvertType(E->getType()); switch (E->getCastKind()) { case CK_ToUnion: { @@ -571,7 +570,8 @@ public: case CK_NoOp: return C; - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_LValueBitCast: case CK_BitCast: @@ -585,9 +585,10 @@ public: case CK_GetObjCProperty: case CK_ToVoid: case CK_Dynamic: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: return 0; // These might need to be supported for constexpr. @@ -680,9 +681,9 @@ public: return Visit(ILE->getInit(0)); std::vector<llvm::Constant*> Elts; - const llvm::ArrayType *AType = + llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ILE->getType())); - const llvm::Type *ElemTy = AType->getElementType(); + llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); // Initialising an array requires us to automatically @@ -719,7 +720,7 @@ public: std::vector<llvm::Type*> Types; for (unsigned i = 0; i < Elts.size(); ++i) Types.push_back(Elts[i]->getType()); - const llvm::StructType *SType = llvm::StructType::get(AType->getContext(), + llvm::StructType *SType = llvm::StructType::get(AType->getContext(), Types, true); return llvm::ConstantStruct::get(SType, Elts); } @@ -740,6 +741,22 @@ public: } llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { + if (ILE->getType()->isAnyComplexType() && ILE->getNumInits() == 2) { + // Complex type with element initializers + Expr *Real = ILE->getInit(0); + Expr *Imag = ILE->getInit(1); + llvm::Constant *Complex[2]; + Complex[0] = CGM.EmitConstantExpr(Real, Real->getType(), CGF); + if (!Complex[0]) + return 0; + Complex[1] = CGM.EmitConstantExpr(Imag, Imag->getType(), CGF); + if (!Complex[1]) + return 0; + llvm::StructType *STy = + cast<llvm::StructType>(ConvertType(ILE->getType())); + return llvm::ConstantStruct::get(STy, Complex); + } + if (ILE->getType()->isScalarType()) { // We have a scalar in braces. Just use the first element. if (ILE->getNumInits() > 0) { @@ -762,10 +779,7 @@ public: if (ILE->getType()->isVectorType()) return 0; - assert(0 && "Unable to handle InitListExpr"); - // Get rid of control reaches end of void function warning. - // Not reached. - return 0; + llvm_unreachable("Unable to handle InitListExpr"); } llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) { @@ -789,8 +803,8 @@ public: if (E->getNumArgs()) { assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument"); - assert(E->getConstructor()->isCopyConstructor() && - "trivial ctor has argument but isn't a copy ctor"); + assert(E->getConstructor()->isCopyOrMoveConstructor() && + "trivial ctor has argument but isn't a copy/move ctor"); Expr *Arg = E->getArg(0); assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) && @@ -831,7 +845,7 @@ public: } // Utility methods - const llvm::Type *ConvertType(QualType T) { + llvm::Type *ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); } @@ -948,10 +962,9 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, if (Success && !Result.HasSideEffects) { switch (Result.Val.getKind()) { case APValue::Uninitialized: - assert(0 && "Constant expressions should be initialized."); - return 0; + llvm_unreachable("Constant expressions should be initialized."); case APValue::LValue: { - const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); + llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); llvm::Constant *Offset = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), Result.Val.getLValueOffset().getQuantity()); @@ -962,9 +975,9 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, // Apply offset if necessary. if (!Offset->isNullValue()) { - const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); + llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type); - Casted = llvm::ConstantExpr::getGetElementPtr(Casted, &Offset, 1); + Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset); C = llvm::ConstantExpr::getBitCast(Casted, C->getType()); } @@ -994,7 +1007,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, Result.Val.getInt()); if (C->getType()->isIntegerTy(1)) { - const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); C = llvm::ConstantExpr::getZExt(C, BoolTy); } return C; @@ -1013,8 +1026,13 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, NULL); return llvm::ConstantStruct::get(STy, Complex); } - case APValue::Float: - return llvm::ConstantFP::get(VMContext, Result.Val.getFloat()); + case APValue::Float: { + const llvm::APFloat &Init = Result.Val.getFloat(); + if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf) + return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); + else + return llvm::ConstantFP::get(VMContext, Init); + } case APValue::ComplexFloat: { llvm::Constant *Complex[2]; @@ -1030,7 +1048,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, return llvm::ConstantStruct::get(STy, Complex); } case APValue::Vector: { - llvm::SmallVector<llvm::Constant *, 4> Inits; + SmallVector<llvm::Constant *, 4> Inits; unsigned NumElts = Result.Val.getVectorLength(); if (Context.getLangOptions().AltiVec && @@ -1064,7 +1082,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E)); if (C && C->getType()->isIntegerTy(1)) { - const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); + llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); C = llvm::ConstantExpr::getZExt(C, BoolTy); } return C; @@ -1181,14 +1199,14 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, } static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, - const llvm::Type *baseType, + llvm::Type *baseType, const CXXRecordDecl *base); static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, const CXXRecordDecl *record, bool asCompleteObject) { const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record); - const llvm::StructType *structure = + llvm::StructType *structure = (asCompleteObject ? layout.getLLVMType() : layout.getBaseSubobjectLLVMType()); @@ -1212,7 +1230,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, continue; unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base); - const llvm::Type *baseType = structure->getElementType(fieldIndex); + llvm::Type *baseType = structure->getElementType(fieldIndex); elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base); } @@ -1245,7 +1263,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, // We might have already laid this field out. if (elements[fieldIndex]) continue; - const llvm::Type *baseType = structure->getElementType(fieldIndex); + llvm::Type *baseType = structure->getElementType(fieldIndex); elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base); } } @@ -1261,7 +1279,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, /// Emit the null constant for a base subobject. static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, - const llvm::Type *baseType, + llvm::Type *baseType, const CXXRecordDecl *base) { const CGRecordLayout &baseLayout = CGM.getTypes().getCGRecordLayout(base); @@ -1277,7 +1295,7 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, // Otherwise, some bases are represented as arrays of i8 if the size // of the base is smaller than its corresponding LLVM type. Figure // out how many elements this base array has. - const llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType); + llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType); unsigned numBaseElements = baseArrayType->getNumElements(); // Fill in null data member pointers. @@ -1287,7 +1305,7 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, // Now go through all other elements and zero them out. if (numBaseElements) { - const llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext()); llvm::Constant *i8_zero = llvm::Constant::getNullValue(i8); for (unsigned i = 0; i != numBaseElements; ++i) { if (!baseElements[i]) @@ -1312,7 +1330,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { for (unsigned i = 0; i != NumElements; ++i) Array[i] = Element; - const llvm::ArrayType *ATy = + llvm::ArrayType *ATy = cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T)); return llvm::ConstantArray::get(ATy, Array); } @@ -1330,3 +1348,8 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { // A NULL pointer is represented as -1. return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>()); } + +llvm::Constant * +CodeGenModule::EmitNullConstantForBase(const CXXRecordDecl *Record) { + return ::EmitNullConstant(*this, Record, false); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp index a73e667..3a9fbee 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -78,7 +78,7 @@ public: return I; } - const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } + llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); } @@ -153,8 +153,7 @@ public: Value *VisitStmt(Stmt *S) { S->dump(CGF.getContext().getSourceManager()); - assert(0 && "Stmt can't have complex result type!"); - return 0; + llvm_unreachable("Stmt can't have complex result type!"); } Value *VisitExpr(Expr *S); @@ -343,6 +342,10 @@ public: } // C++ + Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) { + return EmitLoadOfLValue(E); + } + Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } @@ -510,6 +513,7 @@ public: return CGF.EmitObjCStringLiteral(E); } Value *VisitAsTypeExpr(AsTypeExpr *CE); + Value *VisitAtomicExpr(AtomicExpr *AE); }; } // end anonymous namespace. @@ -548,14 +552,24 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (DstType->isVoidType()) return 0; + llvm::Type *SrcTy = Src->getType(); + + // Floating casts might be a bit special: if we're doing casts to / from half + // FP, we should go via special intrinsics. + if (SrcType->isHalfType()) { + Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src); + SrcType = CGF.getContext().FloatTy; + SrcTy = llvm::Type::getFloatTy(VMContext); + } + // Handle conversions to bool first, they are special: comparisons against 0. if (DstType->isBooleanType()) return EmitConversionToBool(Src, SrcType); - const llvm::Type *DstTy = ConvertType(DstType); + llvm::Type *DstTy = ConvertType(DstType); // Ignore conversions like int -> uint. - if (Src->getType() == DstTy) + if (SrcTy == DstTy) return Src; // Handle pointer conversions next: pointers can only be converted to/from @@ -563,13 +577,13 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // some native types (like Obj-C id) may map to a pointer type. if (isa<llvm::PointerType>(DstTy)) { // The source value may be an integer, or a pointer. - if (isa<llvm::PointerType>(Src->getType())) + if (isa<llvm::PointerType>(SrcTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); // First, convert to the correct width so that we control the kind of // extension. - const llvm::Type *MiddleTy = CGF.IntPtrTy; + llvm::Type *MiddleTy = CGF.IntPtrTy; bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); @@ -577,7 +591,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateIntToPtr(IntResult, DstTy, "conv"); } - if (isa<llvm::PointerType>(Src->getType())) { + if (isa<llvm::PointerType>(SrcTy)) { // Must be an ptr to int cast. assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?"); return Builder.CreatePtrToInt(Src, DstTy, "conv"); @@ -592,10 +606,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // Insert the element in element zero of an undef vector llvm::Value *UnV = llvm::UndefValue::get(DstTy); llvm::Value *Idx = Builder.getInt32(0); - UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); + UnV = Builder.CreateInsertElement(UnV, Elt, Idx); // Splat the element across to all elements - llvm::SmallVector<llvm::Constant*, 16> Args; + SmallVector<llvm::Constant*, 16> Args; unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements(); for (unsigned i = 0; i != NumElements; ++i) Args.push_back(Builder.getInt32(0)); @@ -606,34 +620,47 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, } // Allow bitcast from vector to integer/fp of the same size. - if (isa<llvm::VectorType>(Src->getType()) || + if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); // Finally, we have the arithmetic types: real int/float. - if (isa<llvm::IntegerType>(Src->getType())) { + Value *Res = NULL; + llvm::Type *ResTy = DstTy; + + // Cast to half via float + if (DstType->isHalfType()) + DstTy = llvm::Type::getFloatTy(VMContext); + + if (isa<llvm::IntegerType>(SrcTy)) { bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); if (isa<llvm::IntegerType>(DstTy)) - return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); + Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); else if (InputSigned) - return Builder.CreateSIToFP(Src, DstTy, "conv"); + Res = Builder.CreateSIToFP(Src, DstTy, "conv"); else - return Builder.CreateUIToFP(Src, DstTy, "conv"); - } - - assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion"); - if (isa<llvm::IntegerType>(DstTy)) { + Res = Builder.CreateUIToFP(Src, DstTy, "conv"); + } else if (isa<llvm::IntegerType>(DstTy)) { + assert(SrcTy->isFloatingPointTy() && "Unknown real conversion"); if (DstType->isSignedIntegerOrEnumerationType()) - return Builder.CreateFPToSI(Src, DstTy, "conv"); + Res = Builder.CreateFPToSI(Src, DstTy, "conv"); else - return Builder.CreateFPToUI(Src, DstTy, "conv"); + Res = Builder.CreateFPToUI(Src, DstTy, "conv"); + } else { + assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() && + "Unknown real conversion"); + if (DstTy->getTypeID() < SrcTy->getTypeID()) + Res = Builder.CreateFPTrunc(Src, DstTy, "conv"); + else + Res = Builder.CreateFPExt(Src, DstTy, "conv"); } - assert(DstTy->isFloatingPointTy() && "Unknown real conversion"); - if (DstTy->getTypeID() < Src->getType()->getTypeID()) - return Builder.CreateFPTrunc(Src, DstTy, "conv"); - else - return Builder.CreateFPExt(Src, DstTy, "conv"); + if (DstTy != ResTy) { + assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion"); + Res = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), Res); + } + + return Res; } /// EmitComplexToScalarConversion - Emit a conversion from the specified complex @@ -686,14 +713,14 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { Value *RHS = CGF.EmitScalarExpr(E->getExpr(1)); Value *Mask; - const llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType()); + llvm::VectorType *LTy = cast<llvm::VectorType>(LHS->getType()); unsigned LHSElts = LTy->getNumElements(); if (E->getNumSubExprs() == 3) { Mask = CGF.EmitScalarExpr(E->getExpr(2)); // Shuffle LHS & RHS into one input vector. - llvm::SmallVector<llvm::Constant*, 32> concat; + SmallVector<llvm::Constant*, 32> concat; for (unsigned i = 0; i != LHSElts; ++i) { concat.push_back(Builder.getInt32(2*i)); concat.push_back(Builder.getInt32(2*i+1)); @@ -706,7 +733,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { Mask = RHS; } - const llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType()); + llvm::VectorType *MTy = cast<llvm::VectorType>(Mask->getType()); llvm::Constant* EltMask; // Treat vec3 like vec4. @@ -721,7 +748,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { (1 << llvm::Log2_32(LHSElts))-1); // Mask off the high bits of each shuffle index. - llvm::SmallVector<llvm::Constant *, 32> MaskV; + SmallVector<llvm::Constant *, 32> MaskV; for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) MaskV.push_back(EltMask); @@ -734,7 +761,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { // n = extract mask i // x = extract val n // newv = insert newv, x, i - const llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(), + llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(), MTy->getNumElements()); Value* NewV = llvm::UndefValue::get(RTy); for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) { @@ -760,8 +787,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { Value* V2 = CGF.EmitScalarExpr(E->getExpr(1)); // Handle vec3 special since the index will be off by one for the RHS. - const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType()); - llvm::SmallVector<llvm::Constant*, 32> indices; + llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType()); + SmallVector<llvm::Constant*, 32> indices; for (unsigned i = 2; i < E->getNumSubExprs(); i++) { unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2); if (VTy->getNumElements() == 3 && Idx > 3) @@ -815,7 +842,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { } static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, - unsigned Off, const llvm::Type *I32Ty) { + unsigned Off, llvm::Type *I32Ty) { int MV = SVI->getMaskValue(Idx); if (MV == -1) return llvm::UndefValue::get(I32Ty); @@ -831,12 +858,17 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { if (E->hadArrayRangeDesignator()) CGF.ErrorUnsupported(E, "GNU array range designator extension"); - const llvm::VectorType *VType = + llvm::VectorType *VType = dyn_cast<llvm::VectorType>(ConvertType(E->getType())); - // We have a scalar in braces. Just use the first element. - if (!VType) + if (!VType) { + if (NumInitElements == 0) { + // C++11 value-initialization for the scalar. + return EmitNullValue(E->getType()); + } + // We have a scalar in braces. Just use the first element. return Visit(E->getInit(0)); + } unsigned ResElts = VType->getNumElements(); @@ -851,9 +883,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { for (unsigned i = 0; i != NumInitElements; ++i) { Expr *IE = E->getInit(i); Value *Init = Visit(IE); - llvm::SmallVector<llvm::Constant*, 16> Args; + SmallVector<llvm::Constant*, 16> Args; - const llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType()); + llvm::VectorType *VVT = dyn_cast<llvm::VectorType>(Init->getType()); // Handle scalar elements. If the scalar initializer is actually one // element of a different vector of the same width, use shuffle instead of @@ -911,7 +943,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { if (isa<ExtVectorElementExpr>(IE)) { llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init); Value *SVOp = SVI->getOperand(0); - const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); + llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); if (OpTy->getNumElements() == ResElts) { for (unsigned j = 0; j != CurIdx; ++j) { @@ -968,7 +1000,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { // FIXME: evaluate codegen vs. shuffling against constant null vector. // Emit remaining default initializers. - const llvm::Type *EltTy = VType->getElementType(); + llvm::Type *EltTy = VType->getElementType(); // Emit remaining default initializers for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) { @@ -1023,8 +1055,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { ConvertType(CGF.getContext().getPointerType(DestTy))); return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy)); } - - case CK_AnyPointerToObjCPointerCast: + + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: { Value *Src = Visit(const_cast<Expr*>(E)); @@ -1075,7 +1108,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { V = Builder.CreateStructGEP(V, 0, "arraydecay"); } - return V; + // Make sure the array decay ends up being the right type. This matters if + // the array type was of an incomplete type. + return CGF.Builder.CreateBitCast(V, ConvertType(CE->getType())); } case CK_FunctionToPointerDecay: return EmitLValue(E).getAddress(); @@ -1108,15 +1143,17 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src); } - case CK_ObjCProduceObject: + case CK_ARCProduceObject: return CGF.EmitARCRetainScalarExpr(E); - case CK_ObjCConsumeObject: + case CK_ARCConsumeObject: return CGF.EmitObjCConsumeObject(E->getType(), Visit(E)); - case CK_ObjCReclaimReturnedObject: { + case CK_ARCReclaimReturnedObject: { llvm::Value *value = Visit(E); value = CGF.EmitARCRetainAutoreleasedReturnValue(value); return CGF.EmitObjCConsumeObject(E->getType(), value); } + case CK_ARCExtendBlockObject: + return CGF.EmitARCExtendBlockObject(E); case CK_FloatingRealToComplex: case CK_FloatingComplexCast: @@ -1147,7 +1184,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // First, convert to the correct width so that we control the kind of // extension. - const llvm::Type *MiddleTy = CGF.IntPtrTy; + llvm::Type *MiddleTy = CGF.IntPtrTy; bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); @@ -1163,16 +1200,16 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return 0; } case CK_VectorSplat: { - const llvm::Type *DstTy = ConvertType(DestTy); + llvm::Type *DstTy = ConvertType(DestTy); Value *Elt = Visit(const_cast<Expr*>(E)); // Insert the element in element zero of an undef vector llvm::Value *UnV = llvm::UndefValue::get(DstTy); llvm::Value *Idx = Builder.getInt32(0); - UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); + UnV = Builder.CreateInsertElement(UnV, Elt, Idx); // Splat the element across to all elements - llvm::SmallVector<llvm::Constant*, 16> Args; + SmallVector<llvm::Constant*, 16> Args; unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements(); llvm::Constant *Zero = Builder.getInt32(0); for (unsigned i = 0; i < NumElements; i++) @@ -1188,7 +1225,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_FloatingToIntegral: case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: @@ -1253,10 +1289,8 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E, BinOp.Opcode = BO_Add; BinOp.E = E; return EmitOverflowCheckedBinOp(BinOp); - break; } - assert(false && "Unknown SignedOverflowBehaviorTy"); - return 0; + llvm_unreachable("Unknown SignedOverflowBehaviorTy"); } llvm::Value * @@ -1344,6 +1378,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } else if (type->isRealFloatingType()) { // Add the inc/dec to the real part. llvm::Value *amt; + + if (type->isHalfType()) { + // Another special case: half FP increment should be done via float + value = + Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), + input); + } + if (value->getType()->isFloatTy()) amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast<float>(amount))); @@ -1359,6 +1401,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); + if (type->isHalfType()) + value = + Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), + value); + // Objective-C pointer types. } else { const ObjCObjectPointerType *OPT = type->castAs<ObjCObjectPointerType>(); @@ -1375,13 +1422,13 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); value = Builder.CreateBitCast(value, input->getType()); } - + // Store the updated result through the lvalue. if (LV.isBitField()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value); else CGF.EmitStoreThroughLValue(RValue::get(value), LV); - + // If this is a postinc, return the value read from memory, otherwise use the // updated value. return isPre ? value : input; @@ -1432,7 +1479,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { // Loop over the components of the offsetof to compute the value. unsigned n = E->getNumComponents(); - const llvm::Type* ResultType = ConvertType(E->getType()); + llvm::Type* ResultType = ConvertType(E->getType()); llvm::Value* Result = llvm::Constant::getNullValue(ResultType); QualType CurrentType = E->getTypeSourceInfo()->getType(); for (unsigned i = 0; i != n; ++i) { @@ -1686,7 +1733,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( llvm::next(insertPt)); llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn); - const llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); + llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); if (Ops.Ty->hasSignedIntegerRepresentation()) { llvm::Value *IntMin = @@ -1769,7 +1816,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { IID = llvm::Intrinsic::smul_with_overflow; break; default: - assert(false && "Unsupported operation for overflow detection"); + llvm_unreachable("Unsupported operation for overflow detection"); IID = 0; } OpID <<= 1; @@ -2065,7 +2112,7 @@ enum IntrinsicType { VCMPEQ, VCMPGT }; static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT, BuiltinType::Kind ElemKind) { switch (ElemKind) { - default: assert(0 && "unexpected element type"); + default: llvm_unreachable("unexpected element type"); case BuiltinType::Char_U: case BuiltinType::UChar: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p : @@ -2135,7 +2182,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, BuiltinType::Kind ElementKind = BTy->getKind(); switch(E->getOpcode()) { - default: assert(0 && "is not a comparison operation"); + default: llvm_unreachable("is not a comparison operation"); case BO_EQ: CR6 = CR6_LT; ID = GetIntrinsic(VCMPEQ, ElementKind); @@ -2294,7 +2341,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { - const llvm::Type *ResTy = ConvertType(E->getType()); + llvm::Type *ResTy = ConvertType(E->getType()); // If we have 0 && RHS, see if we can elide RHS, if so, just return 0. // If we have 1 && X, just emit X without inserting the control flow. @@ -2349,7 +2396,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { - const llvm::Type *ResTy = ConvertType(E->getType()); + llvm::Type *ResTy = ConvertType(E->getType()); // If we have 1 || RHS, see if we can elide RHS, if so, just return 1. // If we have 0 || X, just emit X without inserting the control flow. @@ -2471,11 +2518,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { llvm::Value *LHS = Visit(lhsExpr); llvm::Value *RHS = Visit(rhsExpr); - const llvm::Type *condType = ConvertType(condExpr->getType()); - const llvm::VectorType *vecTy = cast<llvm::VectorType>(condType); + llvm::Type *condType = ConvertType(condExpr->getType()); + llvm::VectorType *vecTy = cast<llvm::VectorType>(condType); unsigned numElem = vecTy->getNumElements(); - const llvm::Type *elemType = vecTy->getElementType(); + llvm::Type *elemType = vecTy->getElementType(); std::vector<llvm::Constant*> Zvals; for (unsigned i = 0; i < numElem; ++i) @@ -2493,7 +2540,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { llvm::Value *RHSTmp = RHS; llvm::Value *LHSTmp = LHS; bool wasCast = false; - const llvm::VectorType *rhsVTy = cast<llvm::VectorType>(RHS->getType()); + llvm::VectorType *rhsVTy = cast<llvm::VectorType>(RHS->getType()); if (rhsVTy->getElementType()->isFloatTy()) { RHSTmp = Builder.CreateBitCast(RHS, tmp2->getType()); LHSTmp = Builder.CreateBitCast(LHS, tmp->getType()); @@ -2578,11 +2625,11 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) { Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); - const llvm::Type *DstTy = ConvertType(E->getType()); + llvm::Type *DstTy = ConvertType(E->getType()); // Going from vec4->vec3 or vec3->vec4 is a special case and requires // a shuffle vector instead of a bitcast. - const llvm::Type *SrcTy = Src->getType(); + llvm::Type *SrcTy = Src->getType(); if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) { unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements(); unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements(); @@ -2592,15 +2639,15 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { // In the case of going from int4->float3, a bitcast is needed before // doing a shuffle. - const llvm::Type *srcElemTy = + llvm::Type *srcElemTy = cast<llvm::VectorType>(SrcTy)->getElementType(); - const llvm::Type *dstElemTy = + llvm::Type *dstElemTy = cast<llvm::VectorType>(DstTy)->getElementType(); if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy()) || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) { // Create a float type of the same size as the source or destination. - const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, + llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, numElementsSrc); Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); @@ -2608,7 +2655,7 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); - llvm::SmallVector<llvm::Constant*, 3> Args; + SmallVector<llvm::Constant*, 3> Args; Args.push_back(Builder.getInt32(0)); Args.push_back(Builder.getInt32(1)); Args.push_back(Builder.getInt32(2)); @@ -2626,6 +2673,10 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { return Builder.CreateBitCast(Src, DstTy, "astype"); } +Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) { + return CGF.EmitAtomicExpr(E).getScalarVal(); +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// @@ -2678,7 +2729,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { // object->isa or (*object).isa // Generate code as for: *(Class*)object // build Class* type - const llvm::Type *ClassPtrTy = ConvertType(E->getType()); + llvm::Type *ClassPtrTy = ConvertType(E->getType()); Expr *BaseExpr = E->getBase(); if (BaseExpr->isRValue()) { @@ -2744,8 +2795,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue( case BO_LOr: case BO_Assign: case BO_Comma: - assert(false && "Not valid compound assignment operators"); - break; + llvm_unreachable("Not valid compound assignment operators"); } llvm_unreachable("Unhandled compound assignment operator"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp index 426cca0..51f2053 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp @@ -33,7 +33,7 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); /// Given the address of a variable of pointer type, find the correct /// null to store into it. static llvm::Constant *getNullForVariable(llvm::Value *addr) { - const llvm::Type *type = + llvm::Type *type = cast<llvm::PointerType>(addr->getType())->getElementType(); return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type)); } @@ -80,6 +80,53 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF, CGF.ConvertType(E->getType()))); } +/// Decide whether to extend the lifetime of the receiver of a +/// returns-inner-pointer message. +static bool +shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) { + switch (message->getReceiverKind()) { + + // For a normal instance message, we should extend unless the + // receiver is loaded from a variable with precise lifetime. + case ObjCMessageExpr::Instance: { + const Expr *receiver = message->getInstanceReceiver(); + const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver); + if (!ice || ice->getCastKind() != CK_LValueToRValue) return true; + receiver = ice->getSubExpr()->IgnoreParens(); + + // Only __strong variables. + if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong) + return true; + + // All ivars and fields have precise lifetime. + if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver)) + return false; + + // Otherwise, check for variables. + const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr()); + if (!declRef) return true; + const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl()); + if (!var) return true; + + // All variables have precise lifetime except local variables with + // automatic storage duration that aren't specially marked. + return (var->hasLocalStorage() && + !var->hasAttr<ObjCPreciseLifetimeAttr>()); + } + + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + // It's never necessary for class objects. + return false; + + case ObjCMessageExpr::SuperInstance: + // We generally assume that 'self' lives throughout a method call. + return false; + } + + llvm_unreachable("invalid receiver kind"); +} + RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return) { // Only the lookup mechanism and first two arguments of the method @@ -88,6 +135,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool isDelegateInit = E->isDelegateInitCall(); + const ObjCMethodDecl *method = E->getMethodDecl(); + // We don't retain the receiver in delegate init calls, and this is // safe because the receiver value is always loaded from 'self', // which we zero out. We don't want to Block_copy block receivers, @@ -95,8 +144,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool retainSelf = (!isDelegateInit && CGM.getLangOptions().ObjCAutoRefCount && - E->getMethodDecl() && - E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>()); + method && + method->hasAttr<NSConsumesSelfAttr>()); CGObjCRuntime &Runtime = CGM.getObjCRuntime(); bool isSuperMessage = false; @@ -112,8 +161,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, E->getInstanceReceiver()); Receiver = ter.getPointer(); - if (!ter.getInt()) - Receiver = EmitARCRetainNonBlock(Receiver); + if (ter.getInt()) retainSelf = false; } else Receiver = EmitScalarExpr(E->getInstanceReceiver()); break; @@ -126,9 +174,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, assert(OID && "Invalid Objective-C class message send"); Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; } @@ -136,9 +181,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; case ObjCMessageExpr::SuperClass: @@ -146,17 +188,25 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Receiver = LoadObjCSelf(); isSuperMessage = true; isClassMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; } + if (retainSelf) + Receiver = EmitARCRetainNonBlock(Receiver); + + // In ARC, we sometimes want to "extend the lifetime" + // (i.e. retain+autorelease) of receivers of returns-inner-pointer + // messages. + if (getLangOptions().ObjCAutoRefCount && method && + method->hasAttr<ObjCReturnsInnerPointerAttr>() && + shouldExtendReceiverForInnerPointerMessage(E)) + Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver); + QualType ResultType = - E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType(); + method ? method->getResultType() : E->getType(); CallArgList Args; - EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end()); + EmitCallArgs(Args, method, E->arg_begin(), E->arg_end()); // For delegate init calls in ARC, do an unsafe store of null into // self. This represents the call taking direct ownership of that @@ -189,12 +239,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Receiver, isClassMessage, Args, - E->getMethodDecl()); + method); } else { result = Runtime.GenerateMessageSend(*this, Return, ResultType, E->getSelector(), Receiver, Args, OID, - E->getMethodDecl()); + method); } // For delegate init calls in ARC, implicitly store the result of @@ -206,14 +256,14 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, // The delegate return type isn't necessarily a matching type; in // fact, it's quite likely to be 'id'. - const llvm::Type *selfTy = + llvm::Type *selfTy = cast<llvm::PointerType>(selfAddr->getType())->getElementType(); newSelf = Builder.CreateBitCast(newSelf, selfTy); Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result); + return AdjustRelatedResultType(*this, E, method, result); } namespace { @@ -263,7 +313,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, args.push_back(OMD->getSelfDecl()); args.push_back(OMD->getCmdDecl()); - for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + for (ObjCMethodDecl::param_const_iterator PI = OMD->param_begin(), E = OMD->param_end(); PI != E; ++PI) args.push_back(*PI); @@ -285,39 +335,6 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF, LValue lvalue, QualType type); -void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, - bool IsAtomic, bool IsStrong) { - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), - Ivar, 0); - llvm::Value *GetCopyStructFn = - CGM.getObjCRuntime().GetGetStructFunction(); - CodeGenTypes &Types = CGM.getTypes(); - // objc_copyStruct (ReturnValue, &structIvar, - // sizeof (Type of Ivar), isAtomic, false); - CallArgList Args; - RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy)); - Args.add(RV, getContext().VoidPtrTy); - RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy)); - Args.add(RV, getContext().VoidPtrTy); - // sizeof (Type of Ivar) - CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType()); - llvm::Value *SizeVal = - llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), - Size.getQuantity()); - Args.add(RValue::get(SizeVal), getContext().LongTy); - llvm::Value *isAtomic = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), - IsAtomic ? 1 : 0); - Args.add(RValue::get(isAtomic), getContext().BoolTy); - llvm::Value *hasStrong = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), - IsStrong ? 1 : 0); - Args.add(RValue::get(hasStrong), getContext().BoolTy); - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, - FunctionType::ExtInfo()), - GetCopyStructFn, ReturnValueSlot(), Args); -} - /// Generate an Objective-C method. An Objective-C method is a C function with /// its pointer, name, and types registered in the class struture. void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { @@ -326,218 +343,599 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { FinishFunction(OMD->getBodyRBrace()); } -// FIXME: I wasn't sure about the synthesis approach. If we end up generating an -// AST for the whole body we can just fall back to having a GenerateFunction -// which takes the body Stmt. +/// emitStructGetterCall - Call the runtime function to load a property +/// into the return value slot. +static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar, + bool isAtomic, bool hasStrong) { + ASTContext &Context = CGF.getContext(); + + llvm::Value *src = + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), + ivar, 0).getAddress(); + + // objc_copyStruct (ReturnValue, &structIvar, + // sizeof (Type of Ivar), isAtomic, false); + CallArgList args; + + llvm::Value *dest = CGF.Builder.CreateBitCast(CGF.ReturnValue, CGF.VoidPtrTy); + args.add(RValue::get(dest), Context.VoidPtrTy); + + src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy); + args.add(RValue::get(src), Context.VoidPtrTy); + + CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType()); + args.add(RValue::get(CGF.CGM.getSize(size)), Context.getSizeType()); + args.add(RValue::get(CGF.Builder.getInt1(isAtomic)), Context.BoolTy); + args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy); + + llvm::Value *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction(); + CGF.EmitCall(CGF.getTypes().getFunctionInfo(Context.VoidTy, args, + FunctionType::ExtInfo()), + fn, ReturnValueSlot(), args); +} + +/// Determine whether the given architecture supports unaligned atomic +/// accesses. They don't have to be fast, just faster than a function +/// call and a mutex. +static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) { + // FIXME: Allow unaligned atomic load/store on x86. (It is not + // currently supported by the backend.) + return 0; +} + +/// Return the maximum size that permits atomic accesses for the given +/// architecture. +static CharUnits getMaxAtomicAccessSize(CodeGenModule &CGM, + llvm::Triple::ArchType arch) { + // ARM has 8-byte atomic accesses, but it's not clear whether we + // want to rely on them here. + + // In the default case, just assume that any size up to a pointer is + // fine given adequate alignment. + return CharUnits::fromQuantity(CGM.PointerSizeInBytes); +} + +namespace { + class PropertyImplStrategy { + public: + enum StrategyKind { + /// The 'native' strategy is to use the architecture's provided + /// reads and writes. + Native, + + /// Use objc_setProperty and objc_getProperty. + GetSetProperty, + + /// Use objc_setProperty for the setter, but use expression + /// evaluation for the getter. + SetPropertyAndExpressionGet, + + /// Use objc_copyStruct. + CopyStruct, + + /// The 'expression' strategy is to emit normal assignment or + /// lvalue-to-rvalue expressions. + Expression + }; + + StrategyKind getKind() const { return StrategyKind(Kind); } + + bool hasStrongMember() const { return HasStrong; } + bool isAtomic() const { return IsAtomic; } + bool isCopy() const { return IsCopy; } + + CharUnits getIvarSize() const { return IvarSize; } + CharUnits getIvarAlignment() const { return IvarAlignment; } + + PropertyImplStrategy(CodeGenModule &CGM, + const ObjCPropertyImplDecl *propImpl); + + private: + unsigned Kind : 8; + unsigned IsAtomic : 1; + unsigned IsCopy : 1; + unsigned HasStrong : 1; + + CharUnits IvarSize; + CharUnits IvarAlignment; + }; +} + +/// Pick an implementation strategy for the the given property synthesis. +PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM, + const ObjCPropertyImplDecl *propImpl) { + const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); + ObjCPropertyDecl::SetterKind setterKind = prop->getSetterKind(); + + IsCopy = (setterKind == ObjCPropertyDecl::Copy); + IsAtomic = prop->isAtomic(); + HasStrong = false; // doesn't matter here. + + // Evaluate the ivar's size and alignment. + ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); + QualType ivarType = ivar->getType(); + llvm::tie(IvarSize, IvarAlignment) + = CGM.getContext().getTypeInfoInChars(ivarType); + + // If we have a copy property, we always have to use getProperty/setProperty. + // TODO: we could actually use setProperty and an expression for non-atomics. + if (IsCopy) { + Kind = GetSetProperty; + return; + } + + // Handle retain. + if (setterKind == ObjCPropertyDecl::Retain) { + // In GC-only, there's nothing special that needs to be done. + if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) { + // fallthrough + + // In ARC, if the property is non-atomic, use expression emission, + // which translates to objc_storeStrong. This isn't required, but + // it's slightly nicer. + } else if (CGM.getLangOptions().ObjCAutoRefCount && !IsAtomic) { + Kind = Expression; + return; + + // Otherwise, we need to at least use setProperty. However, if + // the property isn't atomic, we can use normal expression + // emission for the getter. + } else if (!IsAtomic) { + Kind = SetPropertyAndExpressionGet; + return; + + // Otherwise, we have to use both setProperty and getProperty. + } else { + Kind = GetSetProperty; + return; + } + } + + // If we're not atomic, just use expression accesses. + if (!IsAtomic) { + Kind = Expression; + return; + } + + // Properties on bitfield ivars need to be emitted using expression + // accesses even if they're nominally atomic. + if (ivar->isBitField()) { + Kind = Expression; + return; + } + + // GC-qualified or ARC-qualified ivars need to be emitted as + // expressions. This actually works out to being atomic anyway, + // except for ARC __strong, but that should trigger the above code. + if (ivarType.hasNonTrivialObjCLifetime() || + (CGM.getLangOptions().getGC() && + CGM.getContext().getObjCGCAttrKind(ivarType))) { + Kind = Expression; + return; + } + + // Compute whether the ivar has strong members. + if (CGM.getLangOptions().getGC()) + if (const RecordType *recordType = ivarType->getAs<RecordType>()) + HasStrong = recordType->getDecl()->hasObjectMember(); + + // We can never access structs with object members with a native + // access, because we need to use write barriers. This is what + // objc_copyStruct is for. + if (HasStrong) { + Kind = CopyStruct; + return; + } + + // Otherwise, this is target-dependent and based on the size and + // alignment of the ivar. + + // If the size of the ivar is not a power of two, give up. We don't + // want to get into the business of doing compare-and-swaps. + if (!IvarSize.isPowerOfTwo()) { + Kind = CopyStruct; + return; + } + + llvm::Triple::ArchType arch = + CGM.getContext().getTargetInfo().getTriple().getArch(); + + // Most architectures require memory to fit within a single cache + // line, so the alignment has to be at least the size of the access. + // Otherwise we have to grab a lock. + if (IvarAlignment < IvarSize && !hasUnalignedAtomics(arch)) { + Kind = CopyStruct; + return; + } + + // If the ivar's size exceeds the architecture's maximum atomic + // access size, we have to use CopyStruct. + if (IvarSize > getMaxAtomicAccessSize(CGM, arch)) { + Kind = CopyStruct; + return; + } + + // Otherwise, we can use native loads and stores. + Kind = Native; +} /// GenerateObjCGetter - Generate an Objective-C property getter /// function. The given Decl must be an ObjCImplementationDecl. @synthesize /// is illegal within a category. void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { - ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - bool IsAtomic = - !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart()); - - // Determine if we should use an objc_getProperty call for - // this. Non-atomic properties are directly evaluated. - // atomic 'copy' and 'retain' properties are also directly - // evaluated in gc-only mode. - if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && - IsAtomic && - (PD->getSetterKind() == ObjCPropertyDecl::Copy || - PD->getSetterKind() == ObjCPropertyDecl::Retain)) { - llvm::Value *GetPropertyFn = - CGM.getObjCRuntime().GetPropertyGetFunction(); - if (!GetPropertyFn) { - CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy"); - FinishFunction(); + generateObjCGetterBody(IMP, PID); + + FinishFunction(); +} + +static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) { + const Expr *getter = propImpl->getGetterCXXConstructor(); + if (!getter) return true; + + // Sema only makes only of these when the ivar has a C++ class type, + // so the form is pretty constrained. + + // If the property has a reference type, we might just be binding a + // reference, in which case the result will be a gl-value. We should + // treat this as a non-trivial operation. + if (getter->isGLValue()) + return false; + + // If we selected a trivial copy-constructor, we're okay. + if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(getter)) + return (construct->getConstructor()->isTrivial()); + + // The constructor might require cleanups (in which case it's never + // trivial). + assert(isa<ExprWithCleanups>(getter)); + return false; +} + +void +CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, + const ObjCPropertyImplDecl *propImpl) { + // If there's a non-trivial 'get' expression, we just have to emit that. + if (!hasTrivialGetExpr(propImpl)) { + ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(), + /*nrvo*/ 0); + EmitReturnStmt(ret); + return; + } + + const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); + QualType propType = prop->getType(); + ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl(); + + ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); + + // Pick an implementation strategy. + PropertyImplStrategy strategy(CGM, propImpl); + switch (strategy.getKind()) { + case PropertyImplStrategy::Native: { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0); + + // Currently, all atomic accesses have to be through integer + // types, so there's no point in trying to pick a prettier type. + llvm::Type *bitcastType = + llvm::Type::getIntNTy(getLLVMContext(), + getContext().toBits(strategy.getIvarSize())); + bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay + + // Perform an atomic load. This does not impose ordering constraints. + llvm::Value *ivarAddr = LV.getAddress(); + ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType); + llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load"); + load->setAlignment(strategy.getIvarAlignment().getQuantity()); + load->setAtomic(llvm::Unordered); + + // Store that value into the return address. Doing this with a + // bitcast is likely to produce some pretty ugly IR, but it's not + // the *most* terrible thing in the world. + Builder.CreateStore(load, Builder.CreateBitCast(ReturnValue, bitcastType)); + + // Make sure we don't do an autorelease. + AutoreleaseResult = false; + return; + } + + case PropertyImplStrategy::GetSetProperty: { + llvm::Value *getPropertyFn = + CGM.getObjCRuntime().GetPropertyGetFunction(); + if (!getPropertyFn) { + CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy"); return; } // Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true). // FIXME: Can't this be simpler? This might even be worse than the // corresponding gcc code. - CodeGenTypes &Types = CGM.getTypes(); - ValueDecl *Cmd = OMD->getCmdDecl(); - llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd"); - QualType IdTy = getContext().getObjCIdType(); - llvm::Value *SelfAsId = - Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); - llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar); - llvm::Value *True = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); - CallArgList Args; - Args.add(RValue::get(SelfAsId), IdTy); - Args.add(RValue::get(CmdVal), Cmd->getType()); - Args.add(RValue::get(Offset), getContext().getPointerDiffType()); - Args.add(RValue::get(True), getContext().BoolTy); + llvm::Value *cmd = + Builder.CreateLoad(LocalDeclMap[getterMethod->getCmdDecl()], "cmd"); + llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy); + llvm::Value *ivarOffset = + EmitIvarOffset(classImpl->getClassInterface(), ivar); + + CallArgList args; + args.add(RValue::get(self), getContext().getObjCIdType()); + args.add(RValue::get(cmd), getContext().getObjCSelType()); + args.add(RValue::get(ivarOffset), getContext().getPointerDiffType()); + args.add(RValue::get(Builder.getInt1(strategy.isAtomic())), + getContext().BoolTy); + // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. - RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args, - FunctionType::ExtInfo()), - GetPropertyFn, ReturnValueSlot(), Args); + RValue RV = EmitCall(getTypes().getFunctionInfo(propType, args, + FunctionType::ExtInfo()), + getPropertyFn, ReturnValueSlot(), args); + // We need to fix the type here. Ivars with copy & retain are // always objects so we don't need to worry about complex or // aggregates. RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), - Types.ConvertType(PD->getType()))); - EmitReturnOfRValue(RV, PD->getType()); + getTypes().ConvertType(propType))); + + EmitReturnOfRValue(RV, propType); // objc_getProperty does an autorelease, so we should suppress ours. AutoreleaseResult = false; - } else { - const llvm::Triple &Triple = getContext().Target.getTriple(); - QualType IVART = Ivar->getType(); - if (IsAtomic && - IVART->isScalarType() && - (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb) && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, true, false); - } - else if (IsAtomic && - (IVART->isScalarType() && !IVART->isRealFloatingType()) && - Triple.getArch() == llvm::Triple::x86 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, true, false); - } - else if (IsAtomic && - (IVART->isScalarType() && !IVART->isRealFloatingType()) && - Triple.getArch() == llvm::Triple::x86_64 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(8)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, true, false); - } - else if (IVART->isAnyComplexType()) { - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), - Ivar, 0); - ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(), + + return; + } + + case PropertyImplStrategy::CopyStruct: + emitStructGetterCall(*this, ivar, strategy.isAtomic(), + strategy.hasStrongMember()); + return; + + case PropertyImplStrategy::Expression: + case PropertyImplStrategy::SetPropertyAndExpressionGet: { + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0); + + QualType ivarType = ivar->getType(); + if (ivarType->isAnyComplexType()) { + ComplexPairTy pair = LoadComplexFromAddr(LV.getAddress(), LV.isVolatileQualified()); - StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); - } - else if (hasAggregateLLVMType(IVART)) { - bool IsStrong = false; - if ((IsStrong = IvarTypeWithAggrGCObjects(IVART)) - && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect - && CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, IsAtomic, IsStrong); - } - else { - const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl(); - - if (PID->getGetterCXXConstructor() && - classDecl && !classDecl->hasTrivialDefaultConstructor()) { - ReturnStmt *Stmt = - new (getContext()) ReturnStmt(SourceLocation(), - PID->getGetterCXXConstructor(), - 0); - EmitReturnStmt(*Stmt); - } else if (IsAtomic && - !IVART->isAnyComplexType() && - Triple.getArch() == llvm::Triple::x86 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, true, false); - } - else if (IsAtomic && - !IVART->isAnyComplexType() && - Triple.getArch() == llvm::Triple::x86_64 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(8)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCGetterBody(Ivar, true, false); - } - else { - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), - Ivar, 0); - EmitAggregateCopy(ReturnValue, LV.getAddress(), IVART); - } - } - } - else { - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), - Ivar, 0); - QualType propType = PD->getType(); - - llvm::Value *value; - if (propType->isReferenceType()) { - value = LV.getAddress(); + StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified()); + } else if (hasAggregateLLVMType(ivarType)) { + // The return value slot is guaranteed to not be aliased, but + // that's not necessarily the same as "on the stack", so + // we still potentially need objc_memmove_collectable. + EmitAggregateCopy(ReturnValue, LV.getAddress(), ivarType); + } else { + llvm::Value *value; + if (propType->isReferenceType()) { + value = LV.getAddress(); + } else { + // We want to load and autoreleaseReturnValue ARC __weak ivars. + if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { + value = emitARCRetainLoadOfScalar(*this, LV, ivarType); + + // Otherwise we want to do a simple load, suppressing the + // final autorelease. } else { - // In ARC, we want to emit this retained. - if (getLangOptions().ObjCAutoRefCount && - PD->getType()->isObjCRetainableType()) - value = emitARCRetainLoadOfScalar(*this, LV, IVART); - else - value = EmitLoadOfLValue(LV).getScalarVal(); - - value = Builder.CreateBitCast(value, ConvertType(propType)); + value = EmitLoadOfLValue(LV).getScalarVal(); + AutoreleaseResult = false; } - EmitReturnOfRValue(RValue::get(value), propType); + value = Builder.CreateBitCast(value, ConvertType(propType)); + } + + EmitReturnOfRValue(RValue::get(value), propType); } + return; } - FinishFunction(); + } + llvm_unreachable("bad @property implementation strategy!"); } -void CodeGenFunction::GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD, - ObjCIvarDecl *Ivar) { +/// emitStructSetterCall - Call the runtime function to store the value +/// from the first formal parameter into the given ivar. +static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD, + ObjCIvarDecl *ivar) { // objc_copyStruct (&structIvar, &Arg, // sizeof (struct something), true, false); - llvm::Value *GetCopyStructFn = - CGM.getObjCRuntime().GetSetStructFunction(); - CodeGenTypes &Types = CGM.getTypes(); - CallArgList Args; - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - RValue RV = - RValue::get(Builder.CreateBitCast(LV.getAddress(), - Types.ConvertType(getContext().VoidPtrTy))); - Args.add(RV, getContext().VoidPtrTy); - llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; - llvm::Value *ArgAsPtrTy = - Builder.CreateBitCast(Arg, - Types.ConvertType(getContext().VoidPtrTy)); - RV = RValue::get(ArgAsPtrTy); - Args.add(RV, getContext().VoidPtrTy); - // sizeof (Type of Ivar) - CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType()); - llvm::Value *SizeVal = - llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), - Size.getQuantity()); - Args.add(RValue::get(SizeVal), getContext().LongTy); - llvm::Value *True = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); - Args.add(RValue::get(True), getContext().BoolTy); - llvm::Value *False = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); - Args.add(RValue::get(False), getContext().BoolTy); - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, - FunctionType::ExtInfo()), - GetCopyStructFn, ReturnValueSlot(), Args); + CallArgList args; + + // The first argument is the address of the ivar. + llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), + CGF.LoadObjCSelf(), ivar, 0) + .getAddress(); + ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy); + args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy); + + // The second argument is the address of the parameter variable. + ParmVarDecl *argVar = *OMD->param_begin(); + DeclRefExpr argRef(argVar, argVar->getType(), VK_LValue, SourceLocation()); + llvm::Value *argAddr = CGF.EmitLValue(&argRef).getAddress(); + argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy); + args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy); + + // The third argument is the sizeof the type. + llvm::Value *size = + CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType())); + args.add(RValue::get(size), CGF.getContext().getSizeType()); + + // The fourth argument is the 'isAtomic' flag. + args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy); + + // The fifth argument is the 'hasStrong' flag. + // FIXME: should this really always be false? + args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy); + + llvm::Value *copyStructFn = CGF.CGM.getObjCRuntime().GetSetStructFunction(); + CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args, + FunctionType::ExtInfo()), + copyStructFn, ReturnValueSlot(), args); +} + +static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) { + Expr *setter = PID->getSetterCXXAssignment(); + if (!setter) return true; + + // Sema only makes only of these when the ivar has a C++ class type, + // so the form is pretty constrained. + + // An operator call is trivial if the function it calls is trivial. + // This also implies that there's nothing non-trivial going on with + // the arguments, because operator= can only be trivial if it's a + // synthesized assignment operator and therefore both parameters are + // references. + if (CallExpr *call = dyn_cast<CallExpr>(setter)) { + if (const FunctionDecl *callee + = dyn_cast_or_null<FunctionDecl>(call->getCalleeDecl())) + if (callee->isTrivial()) + return true; + return false; + } + + assert(isa<ExprWithCleanups>(setter)); + return false; } -static bool -IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID, - QualType IvarT) { - bool HasTrvialAssignment = true; - if (PID->getSetterCXXAssignment()) { - const CXXRecordDecl *classDecl = IvarT->getAsCXXRecordDecl(); - HasTrvialAssignment = - (!classDecl || classDecl->hasTrivialCopyAssignment()); +void +CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, + const ObjCPropertyImplDecl *propImpl) { + // Just use the setter expression if Sema gave us one and it's + // non-trivial. There's no way to do this atomically. + if (!hasTrivialSetExpr(propImpl)) { + EmitStmt(propImpl->getSetterCXXAssignment()); + return; + } + + const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); + ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); + ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl(); + + PropertyImplStrategy strategy(CGM, propImpl); + switch (strategy.getKind()) { + case PropertyImplStrategy::Native: { + llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()]; + + LValue ivarLValue = + EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0); + llvm::Value *ivarAddr = ivarLValue.getAddress(); + + // Currently, all atomic accesses have to be through integer + // types, so there's no point in trying to pick a prettier type. + llvm::Type *bitcastType = + llvm::Type::getIntNTy(getLLVMContext(), + getContext().toBits(strategy.getIvarSize())); + bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay + + // Cast both arguments to the chosen operation type. + argAddr = Builder.CreateBitCast(argAddr, bitcastType); + ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType); + + // This bitcast load is likely to cause some nasty IR. + llvm::Value *load = Builder.CreateLoad(argAddr); + + // Perform an atomic store. There are no memory ordering requirements. + llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr); + store->setAlignment(strategy.getIvarAlignment().getQuantity()); + store->setAtomic(llvm::Unordered); + return; + } + + case PropertyImplStrategy::GetSetProperty: + case PropertyImplStrategy::SetPropertyAndExpressionGet: { + llvm::Value *setPropertyFn = + CGM.getObjCRuntime().GetPropertySetFunction(); + if (!setPropertyFn) { + CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy"); + return; + } + + // Emit objc_setProperty((id) self, _cmd, offset, arg, + // <is-atomic>, <is-copy>). + llvm::Value *cmd = + Builder.CreateLoad(LocalDeclMap[setterMethod->getCmdDecl()]); + llvm::Value *self = + Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy); + llvm::Value *ivarOffset = + EmitIvarOffset(classImpl->getClassInterface(), ivar); + llvm::Value *arg = LocalDeclMap[*setterMethod->param_begin()]; + arg = Builder.CreateBitCast(Builder.CreateLoad(arg, "arg"), VoidPtrTy); + + CallArgList args; + args.add(RValue::get(self), getContext().getObjCIdType()); + args.add(RValue::get(cmd), getContext().getObjCSelType()); + args.add(RValue::get(ivarOffset), getContext().getPointerDiffType()); + args.add(RValue::get(arg), getContext().getObjCIdType()); + args.add(RValue::get(Builder.getInt1(strategy.isAtomic())), + getContext().BoolTy); + args.add(RValue::get(Builder.getInt1(strategy.isCopy())), + getContext().BoolTy); + // FIXME: We shouldn't need to get the function info here, the runtime + // already should have computed it to build the function. + EmitCall(getTypes().getFunctionInfo(getContext().VoidTy, args, + FunctionType::ExtInfo()), + setPropertyFn, ReturnValueSlot(), args); + return; + } + + case PropertyImplStrategy::CopyStruct: + emitStructSetterCall(*this, setterMethod, ivar); + return; + + case PropertyImplStrategy::Expression: + break; + } + + // Otherwise, fake up some ASTs and emit a normal assignment. + ValueDecl *selfDecl = setterMethod->getSelfDecl(); + DeclRefExpr self(selfDecl, selfDecl->getType(), VK_LValue, SourceLocation()); + ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack, + selfDecl->getType(), CK_LValueToRValue, &self, + VK_RValue); + ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(), + SourceLocation(), &selfLoad, true, true); + + ParmVarDecl *argDecl = *setterMethod->param_begin(); + QualType argType = argDecl->getType().getNonReferenceType(); + DeclRefExpr arg(argDecl, argType, VK_LValue, SourceLocation()); + ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack, + argType.getUnqualifiedType(), CK_LValueToRValue, + &arg, VK_RValue); + + // The property type can differ from the ivar type in some situations with + // Objective-C pointer types, we can always bit cast the RHS in these cases. + // The following absurdity is just to ensure well-formed IR. + CastKind argCK = CK_NoOp; + if (ivarRef.getType()->isObjCObjectPointerType()) { + if (argLoad.getType()->isObjCObjectPointerType()) + argCK = CK_BitCast; + else if (argLoad.getType()->isBlockPointerType()) + argCK = CK_BlockPointerToObjCPointerCast; + else + argCK = CK_CPointerToObjCPointerCast; + } else if (ivarRef.getType()->isBlockPointerType()) { + if (argLoad.getType()->isBlockPointerType()) + argCK = CK_BitCast; + else + argCK = CK_AnyPointerToBlockPointerCast; + } else if (ivarRef.getType()->isPointerType()) { + argCK = CK_BitCast; } - return HasTrvialAssignment; + ImplicitCastExpr argCast(ImplicitCastExpr::OnStack, + ivarRef.getType(), argCK, &argLoad, + VK_RValue); + Expr *finalArg = &argLoad; + if (!getContext().hasSameUnqualifiedType(ivarRef.getType(), + argLoad.getType())) + finalArg = &argCast; + + + BinaryOperator assign(&ivarRef, finalArg, BO_Assign, + ivarRef.getType(), VK_RValue, OK_Ordinary, + SourceLocation()); + EmitStmt(&assign); } /// GenerateObjCSetter - Generate an Objective-C property setter @@ -545,136 +943,12 @@ IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID, /// is illegal within a category. void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { - ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart()); - const llvm::Triple &Triple = getContext().Target.getTriple(); - QualType IVART = Ivar->getType(); - bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; - bool IsAtomic = - !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); - - // Determine if we should use an objc_setProperty call for - // this. Properties with 'copy' semantics always use it, as do - // non-atomic properties with 'release' semantics as long as we are - // not in gc-only mode. - if (IsCopy || - (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && - PD->getSetterKind() == ObjCPropertyDecl::Retain)) { - llvm::Value *SetPropertyFn = - CGM.getObjCRuntime().GetPropertySetFunction(); - - if (!SetPropertyFn) { - CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy"); - FinishFunction(); - return; - } - // Emit objc_setProperty((id) self, _cmd, offset, arg, - // <is-atomic>, <is-copy>). - // FIXME: Can't this be simpler? This might even be worse than the - // corresponding gcc code. - CodeGenTypes &Types = CGM.getTypes(); - ValueDecl *Cmd = OMD->getCmdDecl(); - llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd"); - QualType IdTy = getContext().getObjCIdType(); - llvm::Value *SelfAsId = - Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); - llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar); - llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; - llvm::Value *ArgAsId = - Builder.CreateBitCast(Builder.CreateLoad(Arg, "arg"), - Types.ConvertType(IdTy)); - llvm::Value *True = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); - llvm::Value *False = - llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); - CallArgList Args; - Args.add(RValue::get(SelfAsId), IdTy); - Args.add(RValue::get(CmdVal), Cmd->getType()); - Args.add(RValue::get(Offset), getContext().getPointerDiffType()); - Args.add(RValue::get(ArgAsId), IdTy); - Args.add(RValue::get(IsAtomic ? True : False), getContext().BoolTy); - Args.add(RValue::get(IsCopy ? True : False), getContext().BoolTy); - // FIXME: We shouldn't need to get the function info here, the runtime - // already should have computed it to build the function. - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, - FunctionType::ExtInfo()), - SetPropertyFn, - ReturnValueSlot(), Args); - } else if (IsAtomic && hasAggregateLLVMType(IVART) && - !IVART->isAnyComplexType() && - IvarAssignHasTrvialAssignment(PID, IVART) && - ((Triple.getArch() == llvm::Triple::x86 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4))) || - (Triple.getArch() == llvm::Triple::x86_64 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(8)))) - && CGM.getObjCRuntime().GetSetStructFunction()) { - // objc_copyStruct (&structIvar, &Arg, - // sizeof (struct something), true, false); - GenerateObjCAtomicSetterBody(OMD, Ivar); - } else if (PID->getSetterCXXAssignment()) { - EmitIgnoredExpr(PID->getSetterCXXAssignment()); - } else { - if (IsAtomic && - IVART->isScalarType() && - (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb) && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCAtomicSetterBody(OMD, Ivar); - } - else if (IsAtomic && - (IVART->isScalarType() && !IVART->isRealFloatingType()) && - Triple.getArch() == llvm::Triple::x86 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(4)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCAtomicSetterBody(OMD, Ivar); - } - else if (IsAtomic && - (IVART->isScalarType() && !IVART->isRealFloatingType()) && - Triple.getArch() == llvm::Triple::x86_64 && - (getContext().getTypeSizeInChars(IVART) - > CharUnits::fromQuantity(8)) && - CGM.getObjCRuntime().GetGetStructFunction()) { - GenerateObjCAtomicSetterBody(OMD, Ivar); - } - else { - // FIXME: Find a clean way to avoid AST node creation. - SourceLocation Loc = PID->getLocStart(); - ValueDecl *Self = OMD->getSelfDecl(); - ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); - DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc); - ParmVarDecl *ArgDecl = *OMD->param_begin(); - QualType T = ArgDecl->getType(); - if (T->isReferenceType()) - T = cast<ReferenceType>(T)->getPointeeType(); - DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc); - ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true); - - // The property type can differ from the ivar type in some situations with - // Objective-C pointer types, we can always bit cast the RHS in these cases. - if (getContext().getCanonicalType(Ivar->getType()) != - getContext().getCanonicalType(ArgDecl->getType())) { - ImplicitCastExpr ArgCasted(ImplicitCastExpr::OnStack, - Ivar->getType(), CK_BitCast, &Arg, - VK_RValue); - BinaryOperator Assign(&IvarRef, &ArgCasted, BO_Assign, - Ivar->getType(), VK_RValue, OK_Ordinary, Loc); - EmitStmt(&Assign); - } else { - BinaryOperator Assign(&IvarRef, &Arg, BO_Assign, - Ivar->getType(), VK_RValue, OK_Ordinary, Loc); - EmitStmt(&Assign); - } - } - } + generateObjCSetterBody(IMP, PID); FinishFunction(); } @@ -716,9 +990,8 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF, llvm::Value *self = CGF.LoadObjCSelf(); - ObjCInterfaceDecl *iface - = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface()); - for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); + const ObjCInterfaceDecl *iface = impl->getClassInterface(); + for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); ivar; ivar = ivar->getNextIvar()) { QualType type = ivar->getType(); @@ -758,7 +1031,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, // Suppress the final autorelease in ARC. AutoreleaseResult = false; - llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers; + SmallVector<CXXCtorInitializer *, 8> IvarInitializers; for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), E = IMP->init_end(); B != E; ++B) { CXXCtorInitializer *IvarInit = (*B); @@ -766,7 +1039,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, true)); + EmitAggExpr(IvarInit->getInit(), + AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } // constructor returns 'self'. CodeGenTypes &Types = CGM.getTypes(); @@ -791,7 +1067,7 @@ bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) { } bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { - if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + if (CGM.getLangOptions().getGC() == LangOptions::NonGC) return false; if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>()) return FDTTy->getDecl()->hasObjectMember(); @@ -896,7 +1172,7 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, if (Src.isScalar()) { llvm::Value *SrcVal = Src.getScalarVal(); QualType DstType = getContext().getCanonicalType(ArgType); - const llvm::Type *DstTy = ConvertType(DstType); + llvm::Type *DstTy = ConvertType(DstType); if (SrcVal->getType() != DstTy) Src = RValue::get(EmitScalarConversion(SrcVal, E->getType(), DstType)); @@ -932,10 +1208,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ } CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getSourceRange().getBegin()); - DI->EmitRegionStart(Builder); - } + if (DI) + DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); // The local variable comes into scope immediately. AutoVarEmission variable = AutoVarEmission::invalid(); @@ -943,10 +1217,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl())); JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end"); - JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next"); // Fast enumeration state. - QualType StateTy = getContext().getObjCFastEnumerationStateType(); + QualType StateTy = CGM.getObjCFastEnumerationStateType(); llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr"); EmitNullInitialization(StatePtr, StateTy); @@ -968,8 +1241,20 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ ArrayType::Normal, 0); llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr"); - // Emit the collection pointer. - llvm::Value *Collection = EmitScalarExpr(S.getCollection()); + // Emit the collection pointer. In ARC, we do a retain. + llvm::Value *Collection; + if (getLangOptions().ObjCAutoRefCount) { + Collection = EmitARCRetainScalarExpr(S.getCollection()); + + // Enter a cleanup to do the release. + EmitObjCConsumeObject(S.getCollection()->getType(), Collection); + } else { + Collection = EmitScalarExpr(S.getCollection()); + } + + // The 'continue' label needs to appear within the cleanup for the + // collection object. + JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next"); // Send it our message: CallArgList Args; @@ -985,7 +1270,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ Args.add(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. - const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); + llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems); Args.add(RValue::get(Count), getContext().UnsignedLongTy); @@ -1053,8 +1338,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(WasMutatedBB); llvm::Value *V = Builder.CreateBitCast(Collection, - ConvertType(getContext().getObjCIdType()), - "tmp"); + ConvertType(getContext().getObjCIdType())); CallArgList Args2; Args2.add(RValue::get(V), getContext().getObjCIdType()); // FIXME: We shouldn't need to get the function info here, the runtime already @@ -1089,7 +1373,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ elementType = cast<Expr>(S.getElement())->getType(); elementIsVariable = false; } - const llvm::Type *convertedElementType = ConvertType(elementType); + llvm::Type *convertedElementType = ConvertType(elementType); // Fetch the buffer out of the enumeration state. // TODO: this pointer should actually be invariant between @@ -1179,10 +1463,12 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitStoreThroughLValue(RValue::get(null), elementLValue); } - if (DI) { - DI->setLocation(S.getSourceRange().getEnd()); - DI->EmitRegionEnd(Builder); - } + if (DI) + DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); + + // Leave the cleanup we entered in ARC. + if (getLangOptions().ObjCAutoRefCount) + PopCleanupBlock(); EmitBlock(LoopEnd.getBlock()); } @@ -1200,7 +1486,7 @@ void CodeGenFunction::EmitObjCAtSynchronizedStmt( CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S); } -/// Produce the code for a CK_ObjCProduceObject. Just does a +/// Produce the code for a CK_ARCProduceObject. Just does a /// primitive retain. llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type, llvm::Value *value) { @@ -1209,63 +1495,22 @@ llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type, namespace { struct CallObjCRelease : EHScopeStack::Cleanup { - CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition) - : type(type), ptr(ptr), condition(condition) {} - QualType type; - llvm::Value *ptr; - llvm::Value *condition; + CallObjCRelease(llvm::Value *object) : object(object) {} + llvm::Value *object; void Emit(CodeGenFunction &CGF, Flags flags) { - llvm::Value *object; - - // If we're in a conditional branch, we had to stash away in an - // alloca the pointer to be released. - llvm::BasicBlock *cont = 0; - if (condition) { - llvm::BasicBlock *release = CGF.createBasicBlock("release.yes"); - cont = CGF.createBasicBlock("release.cont"); - - llvm::Value *cond = CGF.Builder.CreateLoad(condition); - CGF.Builder.CreateCondBr(cond, release, cont); - CGF.EmitBlock(release); - object = CGF.Builder.CreateLoad(ptr); - } else { - object = ptr; - } - CGF.EmitARCRelease(object, /*precise*/ true); - - if (cont) CGF.EmitBlock(cont); } }; } -/// Produce the code for a CK_ObjCConsumeObject. Does a primitive +/// Produce the code for a CK_ARCConsumeObject. Does a primitive /// release at the end of the full-expression. llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type, llvm::Value *object) { // If we're in a conditional branch, we need to make the cleanup - // conditional. FIXME: this really needs to be supported by the - // environment. - llvm::AllocaInst *cond; - llvm::Value *ptr; - if (isInConditionalBranch()) { - cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond"); - ptr = CreateTempAlloca(object->getType(), "release.value"); - - // The alloca is false until we get here. - // FIXME: er. doesn't this need to be set at the start of the condition? - InitTempAlloca(cond, Builder.getFalse()); - - // Then it turns true. - Builder.CreateStore(Builder.getTrue(), cond); - Builder.CreateStore(object, ptr); - } else { - cond = 0; - ptr = object; - } - - EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond); + // conditional. + pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object); return object; } @@ -1276,8 +1521,8 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type, static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, - const llvm::FunctionType *type, - llvm::StringRef fnName) { + llvm::FunctionType *type, + StringRef fnName) { llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName); // In -fobjc-no-arc-runtime, emit weak references to the runtime @@ -1295,18 +1540,18 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF, llvm::Value *value, llvm::Constant *&fn, - llvm::StringRef fnName) { + StringRef fnName) { if (isa<llvm::ConstantPointerNull>(value)) return value; if (!fn) { std::vector<llvm::Type*> args(1, CGF.Int8PtrTy); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(CGF.Int8PtrTy, args, false); fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName); } // Cast the argument to 'id'. - const llvm::Type *origType = value->getType(); + llvm::Type *origType = value->getType(); value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy); // Call the function. @@ -1322,16 +1567,16 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF, static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, llvm::Value *addr, llvm::Constant *&fn, - llvm::StringRef fnName) { + StringRef fnName) { if (!fn) { std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(CGF.Int8PtrTy, args, false); fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName); } // Cast the argument to 'id*'. - const llvm::Type *origType = addr->getType(); + llvm::Type *origType = addr->getType(); addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy); // Call the function. @@ -1353,7 +1598,7 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, llvm::Value *addr, llvm::Value *value, llvm::Constant *&fn, - llvm::StringRef fnName, + StringRef fnName, bool ignored) { assert(cast<llvm::PointerType>(addr->getType())->getElementType() == value->getType()); @@ -1363,12 +1608,12 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, argTypes[0] = CGF.Int8PtrPtrTy; argTypes[1] = CGF.Int8PtrTy; - const llvm::FunctionType *fnType + llvm::FunctionType *fnType = llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false); fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName); } - const llvm::Type *origType = value->getType(); + llvm::Type *origType = value->getType(); addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy); value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy); @@ -1387,12 +1632,12 @@ static void emitARCCopyOperation(CodeGenFunction &CGF, llvm::Value *dst, llvm::Value *src, llvm::Constant *&fn, - llvm::StringRef fnName) { + StringRef fnName) { assert(dst->getType() == src->getType()); if (!fn) { std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy); - const llvm::FunctionType *fnType + llvm::FunctionType *fnType = llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false); fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName); } @@ -1409,7 +1654,7 @@ static void emitARCCopyOperation(CodeGenFunction &CGF, /// call i8* @objc_retainBlock(i8* %value) llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) { if (type->isBlockPointerType()) - return EmitARCRetainBlock(value); + return EmitARCRetainBlock(value, /*mandatory*/ false); else return EmitARCRetainNonBlock(value); } @@ -1424,10 +1669,32 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) { /// Retain the given block, with _Block_copy semantics. /// call i8* @objc_retainBlock(i8* %value) -llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) { - return emitARCValueOperation(*this, value, - CGM.getARCEntrypoints().objc_retainBlock, - "objc_retainBlock"); +/// +/// \param mandatory - If false, emit the call with metadata +/// indicating that it's okay for the optimizer to eliminate this call +/// if it can prove that the block never escapes except down the stack. +llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value, + bool mandatory) { + llvm::Value *result + = emitARCValueOperation(*this, value, + CGM.getARCEntrypoints().objc_retainBlock, + "objc_retainBlock"); + + // If the copy isn't mandatory, add !clang.arc.copy_on_escape to + // tell the optimizer that it doesn't need to do this copy if the + // block doesn't escape, where being passed as an argument doesn't + // count as escaping. + if (!mandatory && isa<llvm::Instruction>(result)) { + llvm::CallInst *call + = cast<llvm::CallInst>(result->stripPointerCasts()); + assert(call->getCalledValue() == CGM.getARCEntrypoints().objc_retainBlock); + + SmallVector<llvm::Value*,1> args; + call->setMetadata("clang.arc.copy_on_escape", + llvm::MDNode::get(Builder.getContext(), args)); + } + + return result; } /// Retain the given object which is the result of a function call. @@ -1442,7 +1709,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { llvm::InlineAsm *&marker = CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker; if (!marker) { - llvm::StringRef assembly + StringRef assembly = CGM.getTargetCodeGenInfo() .getARCRetainAutoreleasedReturnValueMarker(); @@ -1468,8 +1735,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { assert(metadata->getNumOperands() <= 1); if (metadata->getNumOperands() == 0) { llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly); - llvm::Value *args[] = { string }; - metadata->addOperand(llvm::MDNode::get(getLLVMContext(), args)); + metadata->addOperand(llvm::MDNode::get(getLLVMContext(), string)); } } } @@ -1490,7 +1756,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release; if (!fn) { std::vector<llvm::Type*> args(1, Int8PtrTy); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(Builder.getVoidTy(), args, false); fn = createARCRuntimeFunction(CGM, fnType, "objc_release"); } @@ -1503,7 +1769,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { call->setDoesNotThrow(); if (!precise) { - llvm::SmallVector<llvm::Value*,1> args; + SmallVector<llvm::Value*,1> args; call->setMetadata("clang.imprecise_release", llvm::MDNode::get(Builder.getContext(), args)); } @@ -1520,7 +1786,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr, llvm::Constant *&fn = CGM.getARCEntrypoints().objc_storeStrong; if (!fn) { llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy }; - const llvm::FunctionType *fnType + llvm::FunctionType *fnType = llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false); fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong"); } @@ -1607,9 +1873,9 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type, if (isa<llvm::ConstantPointerNull>(value)) return value; - const llvm::Type *origType = value->getType(); + llvm::Type *origType = value->getType(); value = Builder.CreateBitCast(value, Int8PtrTy); - value = EmitARCRetainBlock(value); + value = EmitARCRetainBlock(value, /*mandatory*/ true); value = EmitARCAutorelease(value); return Builder.CreateBitCast(value, origType); } @@ -1674,7 +1940,7 @@ void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) { llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak; if (!fn) { std::vector<llvm::Type*> args(1, Int8PtrPtrTy); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(Builder.getVoidTy(), args, false); fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak"); } @@ -1709,7 +1975,7 @@ void CodeGenFunction::EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src) { llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() { llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPush; if (!fn) { - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(Int8PtrTy, false); fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush"); } @@ -1728,7 +1994,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) { llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop; if (!fn) { std::vector<llvm::Type*> args(1, Int8PtrTy); - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = llvm::FunctionType::get(Builder.getVoidTy(), args, false); // We don't want to use a weak import here; instead we should not @@ -1851,6 +2117,24 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, e = e->IgnoreParens(); QualType type = e->getType(); + // If we're loading retained from a __strong xvalue, we can avoid + // an extra retain/release pair by zeroing out the source of this + // "move" operation. + if (e->isXValue() && + !type.isConstQualified() && + type.getObjCLifetime() == Qualifiers::OCL_Strong) { + // Emit the lvalue. + LValue lv = CGF.EmitLValue(e); + + // Load the object pointer. + llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal(); + + // Set the source pointer to NULL. + CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv); + + return TryEmitResult(result, true); + } + // As a very special optimization, in ARC++, if the l-value is the // result of a non-volatile assignment, do a simple retain of the // result of the call to objc_storeWeak instead of reloading. @@ -1913,35 +2197,53 @@ static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF, } } +/// Determine whether it might be important to emit a separate +/// objc_retain_block on the result of the given expression, or +/// whether it's okay to just emit it in a +1 context. +static bool shouldEmitSeparateBlockRetain(const Expr *e) { + assert(e->getType()->isBlockPointerType()); + e = e->IgnoreParens(); + + // For future goodness, emit block expressions directly in +1 + // contexts if we can. + if (isa<BlockExpr>(e)) + return false; + + if (const CastExpr *cast = dyn_cast<CastExpr>(e)) { + switch (cast->getCastKind()) { + // Emitting these operations in +1 contexts is goodness. + case CK_LValueToRValue: + case CK_ARCReclaimReturnedObject: + case CK_ARCConsumeObject: + case CK_ARCProduceObject: + return false; + + // These operations preserve a block type. + case CK_NoOp: + case CK_BitCast: + return shouldEmitSeparateBlockRetain(cast->getSubExpr()); + + // These operations are known to be bad (or haven't been considered). + case CK_AnyPointerToBlockPointerCast: + default: + return true; + } + } + + return true; +} + static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { + // Look through cleanups. + if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) { + CodeGenFunction::RunCleanupsScope scope(CGF); + return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr()); + } + // The desired result type, if it differs from the type of the // ultimate opaque expression. - const llvm::Type *resultType = 0; - - // If we're loading retained from a __strong xvalue, we can avoid - // an extra retain/release pair by zeroing out the source of this - // "move" operation. - if (e->isXValue() && !e->getType().isConstQualified() && - e->getType().getObjCLifetime() == Qualifiers::OCL_Strong) { - // Emit the lvalue - LValue lv = CGF.EmitLValue(e); - - // Load the object pointer and cast it to the appropriate type. - QualType exprType = e->getType(); - llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal(); - - if (resultType) - result = CGF.Builder.CreateBitCast(result, resultType); - - // Set the source pointer to NULL. - llvm::Value *null - = llvm::ConstantPointerNull::get( - cast<llvm::PointerType>(CGF.ConvertType(exprType))); - CGF.EmitStoreOfScalar(null, lv); - - return TryEmitResult(result, true); - } + llvm::Type *resultType = 0; while (true) { e = e->IgnoreParens(); @@ -1969,7 +2271,8 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { // These casts can change the type, so remember that and // soldier on. We only need to remember the outermost such // cast, though. - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: if (!resultType) @@ -1980,15 +2283,49 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { // For consumptions, just emit the subexpression and thus elide // the retain/release pair. - case CK_ObjCConsumeObject: { + case CK_ARCConsumeObject: { llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr()); if (resultType) result = CGF.Builder.CreateBitCast(result, resultType); return TryEmitResult(result, true); } + // Block extends are net +0. Naively, we could just recurse on + // the subexpression, but actually we need to ensure that the + // value is copied as a block, so there's a little filter here. + case CK_ARCExtendBlockObject: { + llvm::Value *result; // will be a +0 value + + // If we can't safely assume the sub-expression will produce a + // block-copied value, emit the sub-expression at +0. + if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) { + result = CGF.EmitScalarExpr(ce->getSubExpr()); + + // Otherwise, try to emit the sub-expression at +1 recursively. + } else { + TryEmitResult subresult + = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr()); + result = subresult.getPointer(); + + // If that produced a retained value, just use that, + // possibly casting down. + if (subresult.getInt()) { + if (resultType) + result = CGF.Builder.CreateBitCast(result, resultType); + return TryEmitResult(result, true); + } + + // Otherwise it's +0. + } + + // Retain the object as a block, then cast down. + result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true); + if (resultType) result = CGF.Builder.CreateBitCast(result, resultType); + return TryEmitResult(result, true); + } + // For reclaims, emit the subexpression as a retained call and // skip the consumption. - case CK_ObjCReclaimReturnedObject: { + case CK_ARCReclaimReturnedObject: { llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr()); if (resultType) result = CGF.Builder.CreateBitCast(result, resultType); return TryEmitResult(result, true); @@ -2067,6 +2404,48 @@ CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) { return value; } +llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) { + llvm::Value *result; + bool doRetain; + + if (shouldEmitSeparateBlockRetain(e)) { + result = EmitScalarExpr(e); + doRetain = true; + } else { + TryEmitResult subresult = tryEmitARCRetainScalarExpr(*this, e); + result = subresult.getPointer(); + doRetain = !subresult.getInt(); + } + + if (doRetain) + result = EmitARCRetainBlock(result, /*mandatory*/ true); + return EmitObjCConsumeObject(e->getType(), result); +} + +llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) { + // In ARC, retain and autorelease the expression. + if (getLangOptions().ObjCAutoRefCount) { + // Do so before running any cleanups for the full-expression. + // tryEmitARCRetainScalarExpr does make an effort to do things + // inside cleanups, but there are crazy cases like + // @throw A().foo; + // where a full retain+autorelease is required and would + // otherwise happen after the destructor for the temporary. + CodeGenFunction::RunCleanupsScope cleanups(*this); + if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr)) + expr = ewc->getSubExpr(); + + return EmitARCRetainAutoreleaseScalarExpr(expr); + } + + // Otherwise, use the normal scalar-expression emission. The + // exception machinery doesn't do anything special with the + // exception like retaining it, so there's no safety associated with + // only running cleanups after the throw has started, and when it + // matters it tends to be substantially inferior code. + return EmitScalarExpr(expr); +} + std::pair<LValue,llvm::Value*> CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e, bool ignored) { @@ -2074,10 +2453,20 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e, TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS()); llvm::Value *value = result.getPointer(); + bool hasImmediateRetain = result.getInt(); + + // If we didn't emit a retained object, and the l-value is of block + // type, then we need to emit the block-retain immediately in case + // it invalidates the l-value. + if (!hasImmediateRetain && e->getType()->isBlockPointerType()) { + value = EmitARCRetainBlock(value, /*mandatory*/ false); + hasImmediateRetain = true; + } + LValue lvalue = EmitLValue(e->getLHS()); // If the RHS was emitted retained, expand this. - if (result.getInt()) { + if (hasImmediateRetain) { llvm::Value *oldValue = EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(), lvalue.getAlignment(), e->getType(), @@ -2111,10 +2500,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt( const CompoundStmt &S = cast<CompoundStmt>(*subStmt); CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getLBracLoc()); - DI->EmitRegionStart(Builder); - } + if (DI) + DI->EmitLexicalBlockStart(Builder, S.getLBracLoc()); // Keep track of the current cleanup stack depth. RunCleanupsScope Scope(*this); @@ -2130,19 +2517,16 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt( E = S.body_end(); I != E; ++I) EmitStmt(*I); - if (DI) { - DI->setLocation(S.getRBracLoc()); - DI->EmitRegionEnd(Builder); - } + if (DI) + DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc()); } /// EmitExtendGCLifetime - Given a pointer to an Objective-C object, /// make sure it survives garbage collection until this point. void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) { // We just use an inline assembly. - llvm::Type *paramTypes[] = { VoidPtrTy }; llvm::FunctionType *extenderType - = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false); + = llvm::FunctionType::get(VoidTy, VoidPtrTy, /*variadic*/ false); llvm::Value *extender = llvm::InlineAsm::get(extenderType, /* assembly */ "", diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp index 61027fe..d3da649 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp @@ -36,12 +36,11 @@ #include "llvm/Support/Compiler.h" #include "llvm/Target/TargetData.h" -#include <stdarg.h> +#include <cstdarg> using namespace clang; using namespace CodeGen; -using llvm::dyn_cast; namespace { @@ -82,7 +81,7 @@ class LazyRuntimeFunction { if (!Function) { if (0 == FunctionName) return 0; // We put the return type on the end of the vector, so pop it back off - const llvm::Type *RetTy = ArgTys.back(); + llvm::Type *RetTy = ArgTys.back(); ArgTys.pop_back(); llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false); Function = @@ -111,17 +110,17 @@ protected: llvm::Module &TheModule; /// strut objc_super. Used for sending messages to super. This structure /// contains the receiver (object) and the expected class. - const llvm::StructType *ObjCSuperTy; + llvm::StructType *ObjCSuperTy; /// struct objc_super*. The type of the argument to the superclass message /// lookup functions. - const llvm::PointerType *PtrToObjCSuperTy; + llvm::PointerType *PtrToObjCSuperTy; /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring /// SEL is included in a header somewhere, in which case it will be whatever /// type is declared in that header, most likely {i8*, i8*}. llvm::PointerType *SelectorTy; /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the /// places where it's used - const llvm::IntegerType *Int8Ty; + llvm::IntegerType *Int8Ty; /// Pointer to i8 - LLVM type of char*, for all of the places where the /// runtime needs to deal with C strings. llvm::PointerType *PtrToInt8Ty; @@ -138,7 +137,7 @@ protected: llvm::PointerType *IdTy; /// Pointer to a pointer to an Objective-C object. Used in the new ABI /// message lookup function and some GC-related functions. - const llvm::PointerType *PtrToIdTy; + llvm::PointerType *PtrToIdTy; /// The clang type of id. Used when using the clang CGCall infrastructure to /// call Objective-C methods. CanQualType ASTIdTy; @@ -153,14 +152,20 @@ protected: /// compatibility with GCC... llvm::IntegerType *LongTy; /// LLVM type for C size_t. Used in various runtime data structures. - const llvm::IntegerType *SizeTy; + llvm::IntegerType *SizeTy; + /// LLVM type for C intptr_t. + llvm::IntegerType *IntPtrTy; /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions. - const llvm::IntegerType *PtrDiffTy; + llvm::IntegerType *PtrDiffTy; /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance /// variables. - const llvm::PointerType *PtrToIntTy; + llvm::PointerType *PtrToIntTy; /// LLVM type for Objective-C BOOL type. - const llvm::Type *BoolTy; + llvm::Type *BoolTy; + /// 32-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int32Ty; + /// 64-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int64Ty; /// Metadata kind used to tie method lookups to message sends. The GNUstep /// runtime provides some LLVM passes that can use this to do things like /// automatic IMP caching and speculative inlining. @@ -171,7 +176,7 @@ protected: llvm::Constant *MakeConstantString(const std::string &Str, const std::string &Name="") { llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); - return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); + return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros); } /// Emits a linkonce_odr string, whose name is the prefix followed by the /// string value. This allows the linker to combine the strings between @@ -186,14 +191,14 @@ protected: ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true, llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str); } - return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); + return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros); } /// Generates a global structure, initialized by the elements in the vector. /// The element types must match the types of the structure elements in the /// first argument. - llvm::GlobalVariable *MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, - llvm::StringRef Name="", + llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty, + llvm::ArrayRef<llvm::Constant*> V, + StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); @@ -203,9 +208,9 @@ protected: /// Generates a global array. The vector must contain the same number of /// elements that the array type declares, of the type specified as the array /// element type. - llvm::GlobalVariable *MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, - llvm::StringRef Name="", + llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty, + llvm::ArrayRef<llvm::Constant*> V, + StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::Constant *C = llvm::ConstantArray::get(Ty, V); @@ -214,9 +219,9 @@ protected: } /// Generates a global array, inferring the array type from the specified /// element type and the size of the initialiser. - llvm::GlobalVariable *MakeGlobalArray(const llvm::Type *Ty, - std::vector<llvm::Constant*> &V, - llvm::StringRef Name="", + llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty, + llvm::ArrayRef<llvm::Constant*> V, + StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size()); @@ -225,7 +230,7 @@ protected: /// Ensures that the value has the required type, by inserting a bitcast if /// required. This function lets us avoid inserting bitcasts that are /// redundant. - llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){ + llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, llvm::Type *Ty){ if (V->getType() == Ty) return V; return B.CreateBitCast(V, Ty); } @@ -268,7 +273,7 @@ private: /// Type of the selector map. This is roughly equivalent to the structure /// used in the GNUstep runtime, which maintains a list of all of the valid /// types for a selector in a table. - typedef llvm::DenseMap<Selector, llvm::SmallVector<TypedSelector, 2> > + typedef llvm::DenseMap<Selector, SmallVector<TypedSelector, 2> > SelectorMap; /// A map from selectors to selector types. This allows us to emit all /// selectors of the same name and type together. @@ -332,18 +337,18 @@ private: /// metadata. This is used purely for introspection in the fragile ABI. In /// the non-fragile ABI, it's used for instance variable fixup. llvm::Constant *GenerateIvarList( - const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames, - const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes, - const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets); + const SmallVectorImpl<llvm::Constant *> &IvarNames, + const SmallVectorImpl<llvm::Constant *> &IvarTypes, + const SmallVectorImpl<llvm::Constant *> &IvarOffsets); /// Generates a method list structure. This is a structure containing a size /// and an array of structures containing method metadata. /// /// This structure is used by both classes and categories, and contains a next /// pointer allowing them to be chained together in a linked list. - llvm::Constant *GenerateMethodList(const llvm::StringRef &ClassName, - const llvm::StringRef &CategoryName, - const llvm::SmallVectorImpl<Selector> &MethodSels, - const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes, + llvm::Constant *GenerateMethodList(const StringRef &ClassName, + const StringRef &CategoryName, + const SmallVectorImpl<Selector> &MethodSels, + const SmallVectorImpl<llvm::Constant *> &MethodTypes, bool isClassMethodList); /// Emits an empty protocol. This is used for @protocol() where no protocol /// is found. The runtime will (hopefully) fix up the pointer to refer to the @@ -352,12 +357,12 @@ private: /// Generates a list of property metadata structures. This follows the same /// pattern as method and instance variable metadata lists. llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID, - llvm::SmallVectorImpl<Selector> &InstanceMethodSels, - llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes); + SmallVectorImpl<Selector> &InstanceMethodSels, + SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes); /// Generates a list of referenced protocols. Classes, categories, and /// protocols all use this structure. llvm::Constant *GenerateProtocolList( - const llvm::SmallVectorImpl<std::string> &Protocols); + const SmallVectorImpl<std::string> &Protocols); /// To ensure that all protocols are seen by the runtime, we add a category on /// a class defined in the runtime, declaring no methods, but adopting the /// protocols. This is a horribly ugly hack, but it allows us to collect all @@ -376,12 +381,14 @@ private: llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, bool isMeta=false); /// Generates a method list. This is used by protocols to define the required /// and optional methods. llvm::Constant *GenerateProtocolMethodList( - const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames, - const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes); + const SmallVectorImpl<llvm::Constant *> &MethodNames, + const SmallVectorImpl<llvm::Constant *> &MethodTypes); /// Returns a selector with the specified type encoding. An empty string is /// used to return an untyped selector (with the types field set to NULL). llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel, @@ -403,12 +410,24 @@ protected: llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node) = 0; - /// Looks up the method for sending a message to a superclass. This mechanism - /// differs between the GCC and GNU runtimes, so this method must be - /// overridden in subclasses. + /// Looks up the method for sending a message to a superclass. This + /// mechanism differs between the GCC and GNU runtimes, so this method must + /// be overridden in subclasses. virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper, llvm::Value *cmd) = 0; + /// Libobjc2 uses a bitfield representation where small(ish) bitfields are + /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 + /// bits set to their values, LSB first, while larger ones are stored in a + /// structure of this / form: + /// + /// struct { int32_t length; int32_t values[length]; }; + /// + /// The values in the array are stored in host-endian format, with the least + /// significant bit being assumed to come first in the bitfield. Therefore, + /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, + /// while a bitfield / with the 63rd bit set will be 1<<64. + llvm::Constant *MakeBitField(llvm::SmallVectorImpl<bool> &bits); public: CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion); @@ -622,7 +641,7 @@ class CGObjCGNUstep : public CGObjCGNU { // void *__cxa_begin_catch(void *e) EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL); // void __cxa_end_catch(void) - EnterCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL); + ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL); // void _Unwind_Resume_or_Rethrow(void*) ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL); } @@ -650,13 +669,13 @@ void CGObjCGNU::EmitClassRef(const std::string &className) { llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } -static std::string SymbolNameForMethod(const llvm::StringRef &ClassName, - const llvm::StringRef &CategoryName, const Selector MethodName, +static std::string SymbolNameForMethod(const StringRef &ClassName, + const StringRef &CategoryName, const Selector MethodName, bool isClassMethod) { std::string MethodNameColonStripped = MethodName.getAsString(); std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), ':', '_'); - return (llvm::Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + + return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + CategoryName + "_" + MethodNameColonStripped).str(); } @@ -697,6 +716,12 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; + Int32Ty = llvm::Type::getInt32Ty(VMContext); + Int64Ty = llvm::Type::getInt64Ty(VMContext); + + IntPtrTy = + TheModule.getPointerSize() == llvm::Module::Pointer32 ? Int32Ty : Int64Ty; + // Object type QualType UnqualIdTy = CGM.getContext().getObjCIdType(); ASTIdTy = CanQualType(); @@ -744,11 +769,11 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, true)); const LangOptions &Opts = CGM.getLangOptions(); - if ((Opts.getGCMode() != LangOptions::NonGC) || Opts.ObjCAutoRefCount) + if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount) RuntimeVersion = 10; // Don't bother initialising the GC stuff unless we're compiling in GC mode - if (Opts.getGCMode() != LangOptions::NonGC) { + if (Opts.getGC() != LangOptions::NonGC) { // This is a bit of an hack. We should sort this out by having a proper // CGObjCGNUstep subclass for GC, but we may want to really support the old // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now @@ -793,9 +818,8 @@ llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder, EmitClassRef(Name); ClassName = Builder.CreateStructGEP(ClassName, 0); - llvm::Type *ArgTys[] = { PtrToInt8Ty }; llvm::Constant *ClassLookupFn = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, ArgTys, true), + CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true), "objc_lookup_class"); return Builder.CreateCall(ClassLookupFn, ClassName); } @@ -813,11 +837,11 @@ llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) { llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel, const std::string &TypeEncoding, bool lval) { - llvm::SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel]; + SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel]; llvm::GlobalAlias *SelValue = 0; - for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), + for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), e = Types.end() ; i!=e ; i++) { if (i->first == TypeEncoding) { SelValue = i->second; @@ -918,7 +942,7 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) { llvm::GlobalValue::ExternalLinkage, 0, vtableName); } llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2); - Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, &Two, 1); + Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, Two); Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty); llvm::Constant *typeName = @@ -972,7 +996,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { CGBuilderTy &Builder = CGF.Builder; - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) { + if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); @@ -999,13 +1023,11 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, if (isCategoryImpl) { llvm::Constant *classLookupFunction = 0; if (IsClassMessage) { - llvm::Type *ArgTys[] = { PtrTy }; classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - IdTy, ArgTys, true), "objc_get_meta_class"); + IdTy, PtrTy, true), "objc_get_meta_class"); } else { - llvm::Type *ArgTys[] = { PtrTy }; classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - IdTy, ArgTys, true), "objc_get_class"); + IdTy, PtrTy, true), "objc_get_class"); } ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); @@ -1048,7 +1070,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy); - const llvm::FunctionType *impType = + llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); // Get the IMP @@ -1082,7 +1104,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, CGBuilderTy &Builder = CGF.Builder; // Strip out message sends to retain / release in GC mode - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) { + if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); @@ -1148,7 +1170,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); - const llvm::FunctionType *impType = + llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType)); @@ -1175,7 +1197,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, } else if (msgRet.isAggregate()) { llvm::Value *v = msgRet.getAggregateAddr(); llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); - const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType()); + llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType()); llvm::AllocaInst *NullVal = CGF.CreateTempAlloca(RetTy->getElementType(), "null"); CGF.InitTempAlloca(NullVal, @@ -1201,10 +1223,10 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, /// Generates a MethodList. Used in construction of a objc_class and /// objc_category structures. -llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName, - const llvm::StringRef &CategoryName, - const llvm::SmallVectorImpl<Selector> &MethodSels, - const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes, +llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName, + const StringRef &CategoryName, + const SmallVectorImpl<Selector> &MethodSels, + const SmallVectorImpl<llvm::Constant *> &MethodTypes, bool isClassMethodList) { if (MethodSels.empty()) return NULLPtr; @@ -1239,8 +1261,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName, Methods); // Structure containing list pointer, array and array count - llvm::StructType *ObjCMethodListTy = - llvm::StructType::createNamed(VMContext, ""); + llvm::StructType *ObjCMethodListTy = llvm::StructType::create(VMContext); llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(ObjCMethodListTy); ObjCMethodListTy->setBody( NextPtrTy, @@ -1251,8 +1272,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName, Methods.clear(); Methods.push_back(llvm::ConstantPointerNull::get( llvm::PointerType::getUnqual(ObjCMethodListTy))); - Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - MethodTypes.size())); + Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size())); Methods.push_back(MethodArray); // Create an instance of the structure @@ -1261,9 +1281,9 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName, /// Generates an IvarList. Used in construction of a objc_class. llvm::Constant *CGObjCGNU::GenerateIvarList( - const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames, - const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes, - const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) { + const SmallVectorImpl<llvm::Constant *> &IvarNames, + const SmallVectorImpl<llvm::Constant *> &IvarTypes, + const SmallVectorImpl<llvm::Constant *> &IvarOffsets) { if (IvarNames.size() == 0) return NULLPtr; // Get the method structure type. @@ -1312,6 +1332,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is @@ -1339,6 +1361,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( LongTy, // abi_version IvarOffsets->getType(), // ivar_offsets Properties->getType(), // properties + Int64Ty, // strong_pointers + Int64Ty, // weak_pointers NULL); llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0); // Fill in the structure @@ -1363,9 +1387,11 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); Elements.push_back(NULLPtr); - Elements.push_back(Zero); + Elements.push_back(llvm::ConstantInt::get(LongTy, 1)); Elements.push_back(IvarOffsets); Elements.push_back(Properties); + Elements.push_back(StrongIvarBitmap); + Elements.push_back(WeakIvarBitmap); // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. @@ -1374,8 +1400,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( - const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames, - const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes) { + const SmallVectorImpl<llvm::Constant *> &MethodNames, + const SmallVectorImpl<llvm::Constant *> &MethodTypes) { // Get the method structure type. llvm::StructType *ObjCMethodDescTy = llvm::StructType::get( PtrToInt8Ty, // Really a selector, but the runtime does the casting for us. @@ -1403,7 +1429,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( // Create the protocol list structure used in classes, categories and so on llvm::Constant *CGObjCGNU::GenerateProtocolList( - const llvm::SmallVectorImpl<std::string> &Protocols) { + const SmallVectorImpl<std::string> &Protocols) { llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty, Protocols.size()); llvm::StructType *ProtocolListTy = llvm::StructType::get( @@ -1438,15 +1464,15 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList( llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()]; - const llvm::Type *T = + llvm::Type *T = CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( const std::string &ProtocolName) { - llvm::SmallVector<std::string, 0> EmptyStringVector; - llvm::SmallVector<llvm::Constant*, 0> EmptyConstantVector; + SmallVector<std::string, 0> EmptyStringVector; + SmallVector<llvm::Constant*, 0> EmptyConstantVector; llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector); llvm::Constant *MethodList = @@ -1465,8 +1491,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - ProtocolVersion), IdTy)); + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(MethodList); @@ -1479,14 +1504,14 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { ASTContext &Context = CGM.getContext(); std::string ProtocolName = PD->getNameAsString(); - llvm::SmallVector<std::string, 16> Protocols; + SmallVector<std::string, 16> Protocols; for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(), E = PD->protocol_end(); PI != E; ++PI) Protocols.push_back((*PI)->getNameAsString()); - llvm::SmallVector<llvm::Constant*, 16> InstanceMethodNames; - llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes; - llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames; - llvm::SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes; + SmallVector<llvm::Constant*, 16> InstanceMethodNames; + SmallVector<llvm::Constant*, 16> InstanceMethodTypes; + SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames; + SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes; for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(), E = PD->instmeth_end(); iter != E; iter++) { std::string TypeStr; @@ -1502,10 +1527,10 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { } } // Collect information about class methods: - llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames; - llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes; - llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodNames; - llvm::SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes; + SmallVector<llvm::Constant*, 16> ClassMethodNames; + SmallVector<llvm::Constant*, 16> ClassMethodTypes; + SmallVector<llvm::Constant*, 16> OptionalClassMethodNames; + SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes; for (ObjCProtocolDecl::classmeth_iterator iter = PD->classmeth_begin(), endIter = PD->classmeth_end(); iter != endIter ; iter++) { @@ -1626,8 +1651,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - ProtocolVersion), IdTy)); + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(InstanceMethodList); @@ -1642,8 +1666,8 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { } void CGObjCGNU::GenerateProtocolHolderCategory(void) { // Collect information about instance methods - llvm::SmallVector<Selector, 1> MethodSels; - llvm::SmallVector<llvm::Constant*, 1> MethodTypes; + SmallVector<Selector, 1> MethodSels; + SmallVector<llvm::Constant*, 1> MethodTypes; std::vector<llvm::Constant*> Elements; const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; @@ -1686,12 +1710,55 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) { PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); } +/// Libobjc2 uses a bitfield representation where small(ish) bitfields are +/// stored in a 64-bit value with the low bit set to 1 and the remaining 63 +/// bits set to their values, LSB first, while larger ones are stored in a +/// structure of this / form: +/// +/// struct { int32_t length; int32_t values[length]; }; +/// +/// The values in the array are stored in host-endian format, with the least +/// significant bit being assumed to come first in the bitfield. Therefore, a +/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a +/// bitfield / with the 63rd bit set will be 1<<64. +llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl<bool> &bits) { + int bitCount = bits.size(); + if (bitCount < 64) { + uint64_t val = 1; + for (int i=0 ; i<bitCount ; ++i) { + if (bits[i]) val |= 1ULL<<(i+1); + } + return llvm::ConstantInt::get(Int64Ty, val); + } + llvm::SmallVector<llvm::Constant*, 8> values; + int v=0; + while (v < bitCount) { + int32_t word = 0; + for (int i=0 ; (i<32) && (v<bitCount) ; ++i) { + if (bits[v]) word |= 1<<i; + v++; + } + values.push_back(llvm::ConstantInt::get(Int32Ty, word)); + } + llvm::ArrayType *arrayTy = llvm::ArrayType::get(Int32Ty, values.size()); + llvm::Constant *array = llvm::ConstantArray::get(arrayTy, values); + llvm::Constant *fields[2] = { + llvm::ConstantInt::get(Int32Ty, values.size()), + array }; + llvm::Constant *GS = MakeGlobal(llvm::StructType::get(Int32Ty, arrayTy, + NULL), fields); + llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy); + if (IntPtrTy != Int64Ty) + ptr = llvm::ConstantExpr::getZExt(ptr, Int64Ty); + return ptr; +} + void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { std::string ClassName = OCD->getClassInterface()->getNameAsString(); std::string CategoryName = OCD->getNameAsString(); // Collect information about instance methods - llvm::SmallVector<Selector, 16> InstanceMethodSels; - llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes; + SmallVector<Selector, 16> InstanceMethodSels; + SmallVector<llvm::Constant*, 16> InstanceMethodTypes; for (ObjCCategoryImplDecl::instmeth_iterator iter = OCD->instmeth_begin(), endIter = OCD->instmeth_end(); iter != endIter ; iter++) { @@ -1702,8 +1769,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } // Collect information about class methods - llvm::SmallVector<Selector, 16> ClassMethodSels; - llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes; + SmallVector<Selector, 16> ClassMethodSels; + SmallVector<llvm::Constant*, 16> ClassMethodTypes; for (ObjCCategoryImplDecl::classmeth_iterator iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end(); iter != endIter ; iter++) { @@ -1714,7 +1781,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } // Collect the names of referenced protocols - llvm::SmallVector<std::string, 16> Protocols; + SmallVector<std::string, 16> Protocols; const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl(); const ObjCList<ObjCProtocolDecl> &Protos = CatDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(), @@ -1741,8 +1808,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID, - llvm::SmallVectorImpl<Selector> &InstanceMethodSels, - llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) { + SmallVectorImpl<Selector> &InstanceMethodSels, + SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) { ASTContext &Context = CGM.getContext(); // // Property metadata: name, attributes, isSynthesized, setter name, setter @@ -1845,11 +1912,13 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { Context.getASTObjCImplementationLayout(OID).getSize().getQuantity(); // Collect information about instance variables. - llvm::SmallVector<llvm::Constant*, 16> IvarNames; - llvm::SmallVector<llvm::Constant*, 16> IvarTypes; - llvm::SmallVector<llvm::Constant*, 16> IvarOffsets; + SmallVector<llvm::Constant*, 16> IvarNames; + SmallVector<llvm::Constant*, 16> IvarTypes; + SmallVector<llvm::Constant*, 16> IvarOffsets; std::vector<llvm::Constant*> IvarOffsetValues; + SmallVector<bool, 16> WeakIvars; + SmallVector<bool, 16> StrongIvars; int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); @@ -1859,12 +1928,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { instanceSize = 0 - (instanceSize - superInstanceSize); } - // Collect declared and synthesized ivars. - llvm::SmallVector<ObjCIvarDecl*, 16> OIvars; - CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars); - - for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { - ObjCIvarDecl *IVD = OIvars[i]; + for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { // Store the name IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar @@ -1896,14 +1961,30 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { IVD->getNameAsString()); IvarOffsets.push_back(OffsetValue); IvarOffsetValues.push_back(OffsetVar); + Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); + switch (lt) { + case Qualifiers::OCL_Strong: + StrongIvars.push_back(true); + WeakIvars.push_back(false); + break; + case Qualifiers::OCL_Weak: + StrongIvars.push_back(false); + WeakIvars.push_back(true); + break; + default: + StrongIvars.push_back(false); + WeakIvars.push_back(false); + } } + llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); + llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); llvm::GlobalVariable *IvarOffsetArray = MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets"); // Collect information about instance methods - llvm::SmallVector<Selector, 16> InstanceMethodSels; - llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes; + SmallVector<Selector, 16> InstanceMethodSels; + SmallVector<llvm::Constant*, 16> InstanceMethodTypes; for (ObjCImplementationDecl::instmeth_iterator iter = OID->instmeth_begin(), endIter = OID->instmeth_end(); iter != endIter ; iter++) { @@ -1918,8 +1999,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // Collect information about class methods - llvm::SmallVector<Selector, 16> ClassMethodSels; - llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes; + SmallVector<Selector, 16> ClassMethodSels; + SmallVector<llvm::Constant*, 16> ClassMethodTypes; for (ObjCImplementationDecl::classmeth_iterator iter = OID->classmeth_begin(), endIter = OID->classmeth_end(); iter != endIter ; iter++) { @@ -1929,7 +2010,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect the names of referenced protocols - llvm::SmallVector<std::string, 16> Protocols; + SmallVector<std::string, 16> Protocols; const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(), E = Protos.end(); I != E; ++I) @@ -1945,7 +2026,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty); } // Empty vector used to construct empty method lists - llvm::SmallVector<llvm::Constant*, 1> empty; + SmallVector<llvm::Constant*, 1> empty; // Generate the method and instance variable lists llvm::Constant *MethodList = GenerateMethodList(ClassName, "", InstanceMethodSels, InstanceMethodTypes, false); @@ -1963,20 +2044,20 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // setting up the alias. These are: The base address for the global, the // ivar array (second field), the ivar in this list (set for each ivar), and // the offset (third field in ivar structure) - const llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext); + llvm::Type *IndexTy = Int32Ty; llvm::Constant *offsetPointerIndexes[] = {Zeros[0], llvm::ConstantInt::get(IndexTy, 1), 0, llvm::ConstantInt::get(IndexTy, 2) }; - - for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { - ObjCIvarDecl *IVD = OIvars[i]; + unsigned ivarIndex = 0; + for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { const std::string Name = "__objc_ivar_offset_" + ClassName + '.' + IVD->getNameAsString(); - offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, i); + offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex); // Get the correct ivar field llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr( - IvarList, offsetPointerIndexes, 4); + IvarList, offsetPointerIndexes); // Get the existing variable, if one exists. llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name); if (offset) { @@ -1990,11 +2071,14 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(), false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name); } + ++ivarIndex; } + llvm::Constant *Zero64 = llvm::ConstantInt::get(Int64Ty, 0); //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true); + empty, empty, empty), ClassMethodList, NULLPtr, + NULLPtr, NULLPtr, Zero64, Zero64, true); // Generate the class structure llvm::Constant *ClassStruct = @@ -2002,7 +2086,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ClassName.c_str(), 0, llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList, GenerateProtocolList(Protocols), IvarOffsetArray, - Properties); + Properties, StrongIvarBitmap, WeakIvarBitmap); // Resolve the class aliases, if they exist. if (ClassPtrAlias) { @@ -2033,7 +2117,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // Add all referenced protocols to a category. GenerateProtocolHolderCategory(); - const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>( + llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>( SelectorTy->getElementType()); llvm::Type *SelStructPtrTy = SelectorTy; if (SelStructTy == 0) { @@ -2049,7 +2133,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { ConstantStrings.size() + 1); ConstantStrings.push_back(NULLPtr); - llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass; + StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass; if (StringClass.empty()) StringClass = "NXConstantString"; @@ -2088,8 +2172,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { std::string SelNameStr = iter->first.getAsString(); llvm::Constant *SelName = ExportUniqueString(SelNameStr, ".objc_sel_name"); - llvm::SmallVectorImpl<TypedSelector> &Types = iter->second; - for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), + SmallVectorImpl<TypedSelector> &Types = iter->second; + for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), e = Types.end() ; i!=e ; i++) { llvm::Constant *SelectorTypeEncoding = NULLPtr; @@ -2126,10 +2210,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { for (unsigned int i=0 ; i<SelectorCount ; i++) { llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]}; + llvm::ConstantInt::get(Int32Ty, i), Zeros[0]}; // FIXME: We're generating redundant loads and stores here! llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList, - Idxs, 2); + makeArrayRef(Idxs, 2)); // If selectors are defined as an opaque type, cast the pointer to this // type. SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy); @@ -2177,7 +2261,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Elements.push_back(SymTab); if (RuntimeVersion >= 10) - switch (CGM.getLangOptions().getGCMode()) { + switch (CGM.getLangOptions().getGC()) { case LangOptions::GCOnly: Elements.push_back(llvm::ConstantInt::get(IntTy, 2)); break; @@ -2205,9 +2289,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { CGBuilderTy Builder(VMContext); Builder.SetInsertPoint(EntryBB); - llvm::Type *ArgTys[] = { llvm::PointerType::getUnqual(ModuleTy) }; llvm::FunctionType *FT = - llvm::FunctionType::get(Builder.getVoidTy(), ArgTys, true); + llvm::FunctionType::get(Builder.getVoidTy(), + llvm::PointerType::getUnqual(ModuleTy), true); llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class"); Builder.CreateCall(Register, Module); Builder.CreateRetVoid(); @@ -2219,13 +2303,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { const ObjCCategoryImplDecl *OCD = dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext()); - llvm::StringRef CategoryName = OCD ? OCD->getName() : ""; - llvm::StringRef ClassName = CD->getName(); + StringRef CategoryName = OCD ? OCD->getName() : ""; + StringRef ClassName = CD->getName(); Selector MethodName = OMD->getSelector(); bool isClassMethod = !OMD->isInstanceMethod(); CodeGenTypes &Types = CGM.getTypes(); - const llvm::FunctionType *MethodTy = + llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic()); std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName, MethodName, isClassMethod); @@ -2285,15 +2369,14 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, llvm::Value *ExceptionAsObject; if (const Expr *ThrowExpr = S.getThrowExpr()) { - llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); + llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); ExceptionAsObject = Exception; } else { assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); ExceptionAsObject = CGF.ObjCEHValueStack.back(); } - ExceptionAsObject = - CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy, "tmp"); + ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); // Note: This may have to be an invoke, if we want to support constructs like: // @try { @@ -2341,7 +2424,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, B.CreateCall2(GlobalAssignFn, src, dst); else // FIXME. Add threadloca assign API - assert(false && "EmitObjCGlobalAssign - Threal Local API NYI"); + llvm_unreachable("EmitObjCGlobalAssign - Threal Local API NYI"); } void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, @@ -2396,15 +2479,15 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( const_cast<ObjCInterfaceDecl *>(ID))) Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); - llvm::ConstantInt *OffsetGuess = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar"); + llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(Int32Ty, Offset, + /*isSigned*/true); // Don't emit the guess in non-PIC code because the linker will not be able // to replace it with the real version for a library. In non-PIC code you // must compile with the fragile ABI if you want to use ivars from a // GCC-compiled class. if (CGM.getLangOptions().PICLevel) { llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule, - llvm::Type::getInt32Ty(VMContext), false, + Int32Ty, false, llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess"); IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage, @@ -2432,10 +2515,9 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF, static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *OIVD) { - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - Context.ShallowCollectObjCIvars(OID, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { - if (OIVD == Ivars[k]) + for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next; + next = next->getNextIvar()) { + if (OIVD == next) return OID; } @@ -2461,12 +2543,12 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, llvm::Value *Offset = TheModule.getGlobalVariable(name); if (!Offset) Offset = new llvm::GlobalVariable(TheModule, IntTy, - false, llvm::GlobalValue::CommonLinkage, - 0, name); + false, llvm::GlobalValue::LinkOnceAnyLinkage, + llvm::Constant::getNullValue(IntTy), name); return CGF.Builder.CreateLoad(Offset); } uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); - return llvm::ConstantInt::get(PtrDiffTy, Offset, "ivar"); + return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true); } CGObjCRuntime * diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 010b9e1..308e0c7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -205,14 +205,14 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // id objc_getProperty (id, SEL, ptrdiff_t, bool) - llvm::SmallVector<CanQualType,4> Params; + SmallVector<CanQualType,4> Params; CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); Params.push_back(Ctx.BoolTy); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(IdType, Params, FunctionType::ExtInfo()), false); @@ -223,7 +223,7 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) - llvm::SmallVector<CanQualType,6> Params; + SmallVector<CanQualType,6> Params; CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); @@ -232,7 +232,7 @@ public: Params.push_back(IdType); Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, FunctionType::ExtInfo()), false); @@ -244,13 +244,13 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_copyStruct (void *, const void *, size_t, bool, bool) - llvm::SmallVector<CanQualType,5> Params; + SmallVector<CanQualType,5> Params; Params.push_back(Ctx.VoidPtrTy); Params.push_back(Ctx.VoidPtrTy); Params.push_back(Ctx.LongTy); Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, FunctionType::ExtInfo()), false); @@ -261,9 +261,9 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - llvm::SmallVector<CanQualType,1> Params; + SmallVector<CanQualType,1> Params; Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, FunctionType::ExtInfo()), false); @@ -669,8 +669,8 @@ protected: unsigned ObjCABI; // gc ivar layout bitmap calculation helper caches. - llvm::SmallVector<GC_IVAR, 16> SkipIvars; - llvm::SmallVector<GC_IVAR, 16> IvarsInfo; + SmallVector<GC_IVAR, 16> SkipIvars; + SmallVector<GC_IVAR, 16> IvarsInfo; /// LazySymbols - Symbols to generate a lazy reference for. See /// DefinedSymbols and FinishModule(). @@ -733,7 +733,7 @@ protected: /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD, - llvm::SmallVectorImpl<char> &NameOut); + SmallVectorImpl<char> &NameOut); /// GetMethodVarName - Return a unique constant for the given /// selector's name. The return value has type char *. @@ -775,7 +775,7 @@ protected: void BuildAggrIvarLayout(const ObjCImplementationDecl *OI, const llvm::StructLayout *Layout, const RecordDecl *RD, - const llvm::SmallVectorImpl<FieldDecl*> &RecFields, + const SmallVectorImpl<const FieldDecl*> &RecFields, unsigned int BytePos, bool ForStrongLayout, bool &HasUnion); @@ -786,7 +786,7 @@ protected: /// EmitPropertyList - Emit the given property list. The return /// value has type PropertyListPtrTy. - llvm::Constant *EmitPropertyList(llvm::Twine Name, + llvm::Constant *EmitPropertyList(Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); @@ -817,7 +817,7 @@ protected: /// \param Align - The alignment for the variable, or 0. /// \param AddToUsed - Whether the variable should be added to /// "llvm.used". - llvm::GlobalVariable *CreateMetadataVar(llvm::Twine Name, + llvm::GlobalVariable *CreateMetadataVar(Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, @@ -923,7 +923,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListPtrTy. - llvm::Constant *EmitMethodList(llvm::Twine Name, + llvm::Constant *EmitMethodList(Twine Name, const char *Section, const ConstantVector &Methods); @@ -938,7 +938,7 @@ private: /// - begin, end: The method list to output. /// /// The return value has type MethodDescriptionListPtrTy. - llvm::Constant *EmitMethodDescList(llvm::Twine Name, + llvm::Constant *EmitMethodDescList(Twine Name, const char *Section, const ConstantVector &Methods); @@ -964,7 +964,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(llvm::Twine Name, + llvm::Constant *EmitProtocolList(Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1060,8 +1060,7 @@ public: /// GetClassGlobal - Return the global variable for the Objective-C /// class of the given name. virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { - assert(false && "CGObjCMac::GetClassGlobal"); - return 0; + llvm_unreachable("CGObjCMac::GetClassGlobal"); } }; @@ -1117,7 +1116,7 @@ private: /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListnfABITy. - llvm::Constant *EmitMethodList(llvm::Twine Name, + llvm::Constant *EmitMethodList(Twine Name, const char *Section, const ConstantVector &Methods); /// EmitIvarList - Emit the ivar list for the given @@ -1144,7 +1143,7 @@ private: /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(llvm::Twine Name, + llvm::Constant *EmitProtocolList(Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); @@ -1375,7 +1374,7 @@ static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0), llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1) }; - return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2); + return llvm::ConstantExpr::getGetElementPtr(C, Idxs); } /// hasObjCExceptionAttribute - Return true if this class or any super @@ -1418,12 +1417,12 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) { if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { return CGM.GetAddrOfRTTIDescriptor( - CGM.getContext().ObjCIdRedefinitionType, /*ForEH=*/true); + CGM.getContext().getObjCIdRedefinitionType(), /*ForEH=*/true); } if (T->isObjCClassType() || T->isObjCQualifiedClassType()) { return CGM.GetAddrOfRTTIDescriptor( - CGM.getContext().ObjCClassRedefinitionType, /*ForEH=*/true); + CGM.getContext().getObjCClassRedefinitionType(), /*ForEH=*/true); } if (T->isObjCObjectPointerType()) return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true); @@ -1510,7 +1509,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } // FIXME: We shouldn't need to do this cast, rectify the ASTContext and // ObjCTypes types. - const llvm::Type *ClassTy = + llvm::Type *ClassTy = CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType()); Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, @@ -1549,7 +1548,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCCommonTypesHelper &ObjCTypes) { CallArgList ActualArgs; if (!IsSuper) - Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); + Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy); ActualArgs.add(RValue::get(Arg0), Arg0Ty); ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); @@ -1557,7 +1556,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); if (Method) @@ -1605,15 +1604,15 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, llvm::Constant *nullPtr = llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); - if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC && + if (CGM.getLangOptions().getGC() == LangOptions::NonGC && !CGM.getLangOptions().ObjCAutoRefCount) return nullPtr; bool hasUnion = false; SkipIvars.clear(); IvarsInfo.clear(); - unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth(); + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); // __isa is the first field in block descriptor and must assume by runtime's // convention that it is GC'able. @@ -1878,7 +1877,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, }; */ llvm::Constant * -CGObjCMac::EmitProtocolList(llvm::Twine Name, +CGObjCMac::EmitProtocolList(Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; @@ -1942,7 +1941,7 @@ void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierI struct _objc_property[prop_count]; }; */ -llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, +llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { @@ -2014,7 +2013,7 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { Desc); } -llvm::Constant *CGObjCMac::EmitMethodDescList(llvm::Twine Name, +llvm::Constant *CGObjCMac::EmitMethodDescList(Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -2407,10 +2406,9 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, if (ForClass) return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy); - ObjCInterfaceDecl *OID = - const_cast<ObjCInterfaceDecl*>(ID->getClassInterface()); + const ObjCInterfaceDecl *OID = ID->getClassInterface(); - for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin(); + for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { // Ignore unnamed bit-fields. if (!IVD->getDeclName()) @@ -2476,7 +2474,7 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); } -llvm::Constant *CGObjCMac::EmitMethodList(llvm::Twine Name, +llvm::Constant *CGObjCMac::EmitMethodList(Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -2501,7 +2499,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, GetNameForMethod(OMD, CD, Name); CodeGenTypes &Types = CGM.getTypes(); - const llvm::FunctionType *MethodTy = + llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic()); llvm::Function *Method = llvm::Function::Create(MethodTy, @@ -2514,12 +2512,12 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, } llvm::GlobalVariable * -CGObjCCommonMac::CreateMetadataVar(llvm::Twine Name, +CGObjCCommonMac::CreateMetadataVar(Twine Name, llvm::Constant *Init, const char *Section, unsigned Align, bool AddToUsed) { - const llvm::Type *Ty = Init->getType(); + llvm::Type *Ty = Init->getType(); llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), Ty, false, llvm::GlobalValue::InternalLinkage, Init, Name); @@ -2627,7 +2625,7 @@ namespace { class FragileHazards { CodeGenFunction &CGF; - llvm::SmallVector<llvm::Value*, 20> Locals; + SmallVector<llvm::Value*, 20> Locals; llvm::DenseSet<llvm::BasicBlock*> BlocksBeforeTry; llvm::InlineAsm *ReadHazard; @@ -2754,7 +2752,6 @@ void FragileHazards::collectLocals() { llvm::DenseSet<llvm::Value*> AllocasToIgnore; addIfPresent(AllocasToIgnore, CGF.ReturnValue); addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest); - addIfPresent(AllocasToIgnore, CGF.EHCleanupDest); // Collect all the allocas currently in the function. This is // probably way too aggressive. @@ -2766,7 +2763,7 @@ void FragileHazards::collectLocals() { } llvm::FunctionType *FragileHazards::GetAsmFnType() { - llvm::SmallVector<llvm::Type *, 16> tys(Locals.size()); + SmallVector<llvm::Type *, 16> tys(Locals.size()); for (unsigned i = 0, e = Locals.size(); i != e; ++i) tys[i] = Locals[i]->getType(); return llvm::FunctionType::get(CGF.VoidTy, tys, false); @@ -2958,7 +2955,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0); llvm::Value *GEPIndexes[] = { Zero, Zero, Zero }; llvm::Value *SetJmpBuffer = - CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, GEPIndexes+3, "setjmp_buffer"); + CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer"); llvm::CallInst *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result"); SetJmpResult->setDoesNotThrow(); @@ -3119,8 +3116,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Initialize the catch variable. llvm::Value *Tmp = CGF.Builder.CreateBitCast(Caught, - CGF.ConvertType(CatchParam->getType()), - "tmp"); + CGF.ConvertType(CatchParam->getType())); CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam)); CGF.EmitStmt(CatchStmt->getCatchBody()); @@ -3208,9 +3204,9 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *ExceptionAsObject; if (const Expr *ThrowExpr = S.getThrowExpr()) { - llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); + llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); ExceptionAsObject = - CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp"); + CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy); } else { assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); @@ -3230,7 +3226,7 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, /// llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { - const llvm::Type* DestTy = + llvm::Type* DestTy = cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType(); AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); @@ -3245,7 +3241,7 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, /// void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -3266,7 +3262,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, bool threadlocal) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -3292,7 +3288,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL"); - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -3312,7 +3308,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, /// void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -3386,15 +3382,15 @@ void CGObjCCommonMac::EmitImageInfo() { unsigned flags = 0; // FIXME: Fix and continue? - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) + if (CGM.getLangOptions().getGC() != LangOptions::NonGC) flags |= eImageInfo_GarbageCollected; - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) + if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) flags |= eImageInfo_GCOnly; // We never allow @synthesize of a superclass property. flags |= eImageInfo_CorrectedSynthesize; - const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); // Emitted as int[2]; llvm::Constant *values[2] = { @@ -3498,7 +3494,7 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder, 4, true); } - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder, @@ -3527,7 +3523,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel, if (lvalue) return Entry; - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { @@ -3551,13 +3547,6 @@ llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) { if (I != MethodDefinitions.end()) return I->second; - if (MD->hasBody() && MD->getPCHLevel() > 0) { - // MD isn't emitted yet because it comes from PCH. - CGM.EmitTopLevelDecl(const_cast<ObjCMethodDecl*>(MD)); - assert(MethodDefinitions[MD] && "EmitTopLevelDecl didn't emit the method!"); - return MethodDefinitions[MD]; - } - return NULL; } @@ -3574,8 +3563,8 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, bool &HasUnion) { const RecordDecl *RD = RT->getDecl(); // FIXME - Use iterator. - llvm::SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end()); - const llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); + SmallVector<const FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end()); + llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); const llvm::StructLayout *RecLayout = CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty)); @@ -3586,15 +3575,15 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, const llvm::StructLayout *Layout, const RecordDecl *RD, - const llvm::SmallVectorImpl<FieldDecl*> &RecFields, + const SmallVectorImpl<const FieldDecl*> &RecFields, unsigned int BytePos, bool ForStrongLayout, bool &HasUnion) { bool IsUnion = (RD && RD->isUnion()); uint64_t MaxUnionIvarSize = 0; uint64_t MaxSkippedUnionIvarSize = 0; - FieldDecl *MaxField = 0; - FieldDecl *MaxSkippedField = 0; - FieldDecl *LastFieldBitfieldOrUnnamed = 0; + const FieldDecl *MaxField = 0; + const FieldDecl *MaxSkippedField = 0; + const FieldDecl *LastFieldBitfieldOrUnnamed = 0; uint64_t MaxFieldOffset = 0; uint64_t MaxSkippedFieldOffset = 0; uint64_t LastBitfieldOrUnnamedOffset = 0; @@ -3602,16 +3591,16 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (RecFields.empty()) return; - unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth(); + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); if (!RD && CGM.getLangOptions().ObjCAutoRefCount) { - FieldDecl *FirstField = RecFields[0]; + const FieldDecl *FirstField = RecFields[0]; FirstFieldDelta = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField)); } for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { - FieldDecl *Field = RecFields[i]; + const FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; if (RD) { // Note that 'i' here is actually the field index inside RD of Field, @@ -3721,9 +3710,8 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (LastFieldBitfieldOrUnnamed) { if (LastFieldBitfieldOrUnnamed->isBitField()) { // Last field was a bitfield. Must update skip info. - Expr *BitWidth = LastFieldBitfieldOrUnnamed->getBitWidth(); - uint64_t BitFieldSize = - BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); + uint64_t BitFieldSize + = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext()); GC_IVAR skivar; skivar.ivar_bytepos = BytePos + LastBitfieldOrUnnamedOffset; skivar.ivar_size = (BitFieldSize / ByteSizeInBits) @@ -3754,10 +3742,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, /// filled already by the caller. llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) { unsigned int WordsToScan, WordsToSkip; - const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); // Build the string of skip/scan nibbles - llvm::SmallVector<SKIP_SCAN, 32> SkipScanIvars; + SmallVector<SKIP_SCAN, 32> SkipScanIvars; unsigned int WordSize = CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy); if (IvarsInfo[0].ivar_bytepos == 0) { @@ -3898,25 +3886,24 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( bool ForStrongLayout) { bool hasUnion = false; - const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); - if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC && + llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + if (CGM.getLangOptions().getGC() == LangOptions::NonGC && !CGM.getLangOptions().ObjCAutoRefCount) return llvm::Constant::getNullValue(PtrTy); - ObjCInterfaceDecl *OI = - const_cast<ObjCInterfaceDecl*>(OMD->getClassInterface()); - llvm::SmallVector<FieldDecl*, 32> RecFields; + const ObjCInterfaceDecl *OI = OMD->getClassInterface(); + SmallVector<const FieldDecl*, 32> RecFields; if (CGM.getLangOptions().ObjCAutoRefCount) { - for (ObjCIvarDecl *IVD = OI->all_declared_ivar_begin(); + for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) RecFields.push_back(cast<FieldDecl>(IVD)); } else { - llvm::SmallVector<ObjCIvarDecl*, 32> Ivars; + SmallVector<const ObjCIvarDecl*, 32> Ivars; CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - RecFields.push_back(cast<FieldDecl>(Ivars[k])); + // FIXME: This is not ideal; we shouldn't have to do this copy. + RecFields.append(Ivars.begin(), Ivars.end()); } if (RecFields.empty()) @@ -4036,7 +4023,7 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, const ObjCContainerDecl *CD, - llvm::SmallVectorImpl<char> &Name) { + SmallVectorImpl<char> &Name) { llvm::raw_svector_ostream OS(Name); assert (CD && "Missing container decl in GetNameForMethod"); OS << '\01' << (D->isInstanceMethod() ? '-' : '+') @@ -4125,7 +4112,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // FIXME: It would be nice to unify this with the opaque type, so that the IR // comes out a bit cleaner. - const llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType()); + llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType()); ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T); // I'm not sure I like this. The implicit coordination is a bit @@ -4160,8 +4147,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // char *name; // char *attributes; // } - PropertyTy = llvm::StructType::createNamed("struct._prop_t", - Int8PtrTy, Int8PtrTy, NULL); + PropertyTy = llvm::StructType::create("struct._prop_t", + Int8PtrTy, Int8PtrTy, NULL); // struct _prop_list_t { // uint32_t entsize; // sizeof(struct _prop_t) @@ -4169,10 +4156,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // struct _prop_t prop_list[count_of_properties]; // } PropertyListTy = - llvm::StructType::createNamed("struct._prop_list_t", - IntTy, IntTy, - llvm::ArrayType::get(PropertyTy, 0), - NULL); + llvm::StructType::create("struct._prop_list_t", IntTy, IntTy, + llvm::ArrayType::get(PropertyTy, 0), NULL); // struct _prop_list_t * PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy); @@ -4181,12 +4166,12 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // char *method_type; // char *_imp; // } - MethodTy = llvm::StructType::createNamed("struct._objc_method", - SelectorPtrTy, Int8PtrTy, Int8PtrTy, - NULL); + MethodTy = llvm::StructType::create("struct._objc_method", + SelectorPtrTy, Int8PtrTy, Int8PtrTy, + NULL); // struct _objc_cache * - CacheTy = llvm::StructType::createNamed(VMContext, "struct._objc_cache"); + CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache"); CachePtrTy = llvm::PointerType::getUnqual(CacheTy); } @@ -4198,18 +4183,17 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *types; // } MethodDescriptionTy = - llvm::StructType::createNamed("struct._objc_method_description", - SelectorPtrTy, Int8PtrTy, NULL); + llvm::StructType::create("struct._objc_method_description", + SelectorPtrTy, Int8PtrTy, NULL); // struct _objc_method_description_list { // int count; // struct _objc_method_description[1]; // } MethodDescriptionListTy = - llvm::StructType::createNamed("struct._objc_method_description_list", - IntTy, - llvm::ArrayType::get(MethodDescriptionTy, 0), - NULL); + llvm::StructType::create("struct._objc_method_description_list", + IntTy, + llvm::ArrayType::get(MethodDescriptionTy, 0),NULL); // struct _objc_method_description_list * MethodDescriptionListPtrTy = @@ -4224,12 +4208,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_property_list *instance_properties; // } ProtocolExtensionTy = - llvm::StructType::createNamed("struct._objc_protocol_extension", - IntTy, - MethodDescriptionListPtrTy, - MethodDescriptionListPtrTy, - PropertyListPtrTy, - NULL); + llvm::StructType::create("struct._objc_protocol_extension", + IntTy, MethodDescriptionListPtrTy, + MethodDescriptionListPtrTy, PropertyListPtrTy, + NULL); // struct _objc_protocol_extension * ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy); @@ -4237,10 +4219,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // Handle recursive construction of Protocol and ProtocolList types ProtocolTy = - llvm::StructType::createNamed(VMContext, "struct._objc_protocol"); + llvm::StructType::create(VMContext, "struct._objc_protocol"); ProtocolListTy = - llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list"); + llvm::StructType::create(VMContext, "struct._objc_protocol_list"); ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy, llvm::ArrayType::get(ProtocolTy, 0), @@ -4271,26 +4253,26 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *ivar_type; // int ivar_offset; // } - IvarTy = llvm::StructType::createNamed("struct._objc_ivar", - Int8PtrTy, Int8PtrTy, IntTy, NULL); + IvarTy = llvm::StructType::create("struct._objc_ivar", + Int8PtrTy, Int8PtrTy, IntTy, NULL); // struct _objc_ivar_list * IvarListTy = - llvm::StructType::createNamed(VMContext, "struct._objc_ivar_list"); + llvm::StructType::create(VMContext, "struct._objc_ivar_list"); IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy); // struct _objc_method_list * MethodListTy = - llvm::StructType::createNamed(VMContext, "struct._objc_method_list"); + llvm::StructType::create(VMContext, "struct._objc_method_list"); MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy); // struct _objc_class_extension * ClassExtensionTy = - llvm::StructType::createNamed("struct._objc_class_extension", - IntTy, Int8PtrTy, PropertyListPtrTy, NULL); + llvm::StructType::create("struct._objc_class_extension", + IntTy, Int8PtrTy, PropertyListPtrTy, NULL); ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy); - ClassTy = llvm::StructType::createNamed(VMContext, "struct._objc_class"); + ClassTy = llvm::StructType::create(VMContext, "struct._objc_class"); // struct _objc_class { // Class isa; @@ -4331,10 +4313,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_property_list *instance_properties;// category's @property // } CategoryTy = - llvm::StructType::createNamed("struct._objc_category", - Int8PtrTy, Int8PtrTy, MethodListPtrTy, - MethodListPtrTy, ProtocolListPtrTy, - IntTy, PropertyListPtrTy, NULL); + llvm::StructType::create("struct._objc_category", + Int8PtrTy, Int8PtrTy, MethodListPtrTy, + MethodListPtrTy, ProtocolListPtrTy, + IntTy, PropertyListPtrTy, NULL); // Global metadata structures @@ -4346,9 +4328,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *defs[cls_def_cnt + cat_def_cnt]; // } SymtabTy = - llvm::StructType::createNamed("struct._objc_symtab", - LongTy, SelectorPtrTy, ShortTy, ShortTy, - llvm::ArrayType::get(Int8PtrTy, 0), NULL); + llvm::StructType::create("struct._objc_symtab", + LongTy, SelectorPtrTy, ShortTy, ShortTy, + llvm::ArrayType::get(Int8PtrTy, 0), NULL); SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy); // struct _objc_module { @@ -4358,8 +4340,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_symtab* symtab; // } ModuleTy = - llvm::StructType::createNamed("struct._objc_module", - LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL); + llvm::StructType::create("struct._objc_module", + LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL); // FIXME: This is the size of the setjmp buffer and should be target @@ -4371,7 +4353,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) llvm::Type::getInt8PtrTy(VMContext), 4); ExceptionDataTy = - llvm::StructType::createNamed("struct._objc_exception_data", + llvm::StructType::create("struct._objc_exception_data", llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext), SetJmpBufferSize), StackPtrTy, NULL); @@ -4386,10 +4368,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // struct _objc_method method_list[method_count]; // } MethodListnfABITy = - llvm::StructType::createNamed("struct.__method_list_t", - IntTy, IntTy, - llvm::ArrayType::get(MethodTy, 0), - NULL); + llvm::StructType::create("struct.__method_list_t", IntTy, IntTy, + llvm::ArrayType::get(MethodTy, 0), NULL); // struct method_list_t * MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy); @@ -4408,20 +4388,14 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // Holder for struct _protocol_list_t * ProtocolListnfABITy = - llvm::StructType::createNamed(VMContext, "struct._objc_protocol_list"); + llvm::StructType::create(VMContext, "struct._objc_protocol_list"); ProtocolnfABITy = - llvm::StructType::createNamed("struct._protocol_t", - ObjectPtrTy, Int8PtrTy, - llvm::PointerType::getUnqual(ProtocolListnfABITy), - MethodListnfABIPtrTy, - MethodListnfABIPtrTy, - MethodListnfABIPtrTy, - MethodListnfABIPtrTy, - PropertyListPtrTy, - IntTy, - IntTy, - NULL); + llvm::StructType::create("struct._protocol_t", ObjectPtrTy, Int8PtrTy, + llvm::PointerType::getUnqual(ProtocolListnfABITy), + MethodListnfABIPtrTy, MethodListnfABIPtrTy, + MethodListnfABIPtrTy, MethodListnfABIPtrTy, + PropertyListPtrTy, IntTy, IntTy, NULL); // struct _protocol_t* ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy); @@ -4445,13 +4419,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // uint32_t size; // } IvarnfABITy = - llvm::StructType::createNamed("struct._ivar_t", - llvm::PointerType::getUnqual(LongTy), - Int8PtrTy, - Int8PtrTy, - IntTy, - IntTy, - NULL); + llvm::StructType::create("struct._ivar_t", + llvm::PointerType::getUnqual(LongTy), + Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL); // struct _ivar_list_t { // uint32 entsize; // sizeof(struct _ivar_t) @@ -4459,10 +4429,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // struct _iver_t list[count]; // } IvarListnfABITy = - llvm::StructType::createNamed("struct._ivar_list_t", - IntTy, IntTy, - llvm::ArrayType::get(IvarnfABITy, 0), - NULL); + llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy, + llvm::ArrayType::get(IvarnfABITy, 0), NULL); IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy); @@ -4481,18 +4449,12 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // } // FIXME. Add 'reserved' field in 64bit abi mode! - ClassRonfABITy = llvm::StructType::createNamed("struct._class_ro_t", - IntTy, - IntTy, - IntTy, - Int8PtrTy, - Int8PtrTy, - MethodListnfABIPtrTy, - ProtocolListnfABIPtrTy, - IvarListnfABIPtrTy, - Int8PtrTy, - PropertyListPtrTy, - NULL); + ClassRonfABITy = llvm::StructType::create("struct._class_ro_t", + IntTy, IntTy, IntTy, Int8PtrTy, + Int8PtrTy, MethodListnfABIPtrTy, + ProtocolListnfABIPtrTy, + IvarListnfABIPtrTy, + Int8PtrTy, PropertyListPtrTy, NULL); // ImpnfABITy - LLVM for id (*)(id, SEL, ...) llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy }; @@ -4507,7 +4469,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // struct class_ro_t *ro; // } - ClassnfABITy = llvm::StructType::createNamed(VMContext, "struct._class_t"); + ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t"); ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy), llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy, @@ -4526,14 +4488,13 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // const struct _protocol_list_t * const protocols; // const struct _prop_list_t * const properties; // } - CategorynfABITy = llvm::StructType::createNamed("struct._category_t", - Int8PtrTy, - ClassnfABIPtrTy, - MethodListnfABIPtrTy, - MethodListnfABIPtrTy, - ProtocolListnfABIPtrTy, - PropertyListPtrTy, - NULL); + CategorynfABITy = llvm::StructType::create("struct._category_t", + Int8PtrTy, ClassnfABIPtrTy, + MethodListnfABIPtrTy, + MethodListnfABIPtrTy, + ProtocolListnfABIPtrTy, + PropertyListPtrTy, + NULL); // New types for nonfragile abi messaging. CodeGen::CodeGenTypes &Types = CGM.getTypes(); @@ -4569,8 +4530,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // SEL name; // }; SuperMessageRefTy = - llvm::StructType::createNamed("struct._super_message_ref_t", - ImpnfABITy, SelectorPtrTy, NULL); + llvm::StructType::create("struct._super_message_ref_t", + ImpnfABITy, SelectorPtrTy, NULL); // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t* SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy); @@ -4582,11 +4543,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // Class cls; // }; EHTypeTy = - llvm::StructType::createNamed("struct._objc_typeinfo", - llvm::PointerType::getUnqual(Int8PtrTy), - Int8PtrTy, - ClassnfABIPtrTy, - NULL); + llvm::StructType::create("struct._objc_typeinfo", + llvm::PointerType::getUnqual(Int8PtrTy), + Int8PtrTy, ClassnfABIPtrTy, NULL); EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy); } @@ -4694,7 +4653,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { // These are vtable-based if GC is disabled. // Optimistically use vtable dispatch for hybrid compiles. - if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { + if (CGM.getLangOptions().getGC() != LangOptions::GCOnly) { VTableDispatchMethods.insert(GetNullarySelector("retain")); VTableDispatchMethods.insert(GetNullarySelector("release")); VTableDispatchMethods.insert(GetNullarySelector("autorelease")); @@ -4710,7 +4669,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { // These are vtable-based if GC is enabled. // Optimistically use vtable dispatch for hybrid compiles. - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (CGM.getLangOptions().getGC() != LangOptions::NonGC) { VTableDispatchMethods.insert(GetNullarySelector("hash")); VTableDispatchMethods.insert(GetUnarySelector("addObject")); @@ -5035,7 +4994,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName); if (PTGV) - return Builder.CreateLoad(PTGV, "tmp"); + return Builder.CreateLoad(PTGV); PTGV = new llvm::GlobalVariable( CGM.getModule(), Init->getType(), false, @@ -5045,7 +5004,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); - return Builder.CreateLoad(PTGV, "tmp"); + return Builder.CreateLoad(PTGV); } /// GenerateCategory - Build metadata for a category implementation. @@ -5167,7 +5126,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( /// struct _objc_method method_list[method_count]; /// } /// -llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, +llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(Twine Name, const char *Section, const ConstantVector &Methods) { // Return null for empty list. @@ -5258,13 +5217,12 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( std::vector<llvm::Constant*> Ivars, Ivar(5); - ObjCInterfaceDecl *OID = - const_cast<ObjCInterfaceDecl*>(ID->getClassInterface()); + const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface"); // FIXME. Consolidate this with similar code in GenerateClass. - for (ObjCIvarDecl *IVD = OID->all_declared_ivar_begin(); + for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { // Ignore unnamed bit-fields. if (!IVD->getDeclName()) @@ -5273,7 +5231,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( ComputeIvarBaseOffset(CGM, ID, IVD)); Ivar[1] = GetMethodVarName(IVD->getIdentifier()); Ivar[2] = GetMethodVarType(IVD); - const llvm::Type *FieldTy = + llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(IVD->getType()); unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy); unsigned Align = CGM.getContext().getPreferredTypeAlign( @@ -5461,7 +5419,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( /// @endcode /// llvm::Constant * -CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, +CGObjCNonFragileABIMac::EmitProtocolList(Twine Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { std::vector<llvm::Constant*> ProtocolRefs; @@ -5669,7 +5627,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, callee = CGF.Builder.CreateLoad(callee, "msgSend_fn"); bool variadic = method ? method->isVariadic() : false; - const llvm::FunctionType *fnType = + llvm::FunctionType *fnType = CGF.getTypes().GetFunctionType(fnInfo, variadic); callee = CGF.Builder.CreateBitCast(callee, llvm::PointerType::getUnqual(fnType)); @@ -5730,7 +5688,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder, CGM.AddUsedGlobal(Entry); } - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, @@ -5764,7 +5722,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, CGM.AddUsedGlobal(Entry); } - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } /// EmitMetaClassRef - Return a Value * of the address of _class_t @@ -5774,7 +5732,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()]; if (Entry) - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName); @@ -5790,7 +5748,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } /// GetClass - Return a reference to the class for the given interface @@ -5847,7 +5805,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // FIXME: We shouldn't need to do this cast, rectify the ASTContext and // ObjCTypes types. - const llvm::Type *ClassTy = + llvm::Type *ClassTy = CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType()); Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, @@ -5881,7 +5839,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, if (lval) return Entry; - return Builder.CreateLoad(Entry, "tmp"); + return Builder.CreateLoad(Entry); } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. /// objc_assign_ivar (id src, id *dst, ptrdiff_t) @@ -5890,7 +5848,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -5911,7 +5869,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -5944,7 +5902,7 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable( llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( CodeGen::CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { - const llvm::Type* DestTy = + llvm::Type* DestTy = cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType(); AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(), @@ -5958,7 +5916,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( /// void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -5979,7 +5937,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, bool threadlocal) { - const llvm::Type * SrcTy = src->getType(); + llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); @@ -6043,9 +6001,8 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { if (const Expr *ThrowExpr = S.getThrowExpr()) { - llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); - Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, - "tmp"); + llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); + Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy); CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception) .setDoesNotReturn(); } else { @@ -6096,7 +6053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 2); std::vector<llvm::Constant*> Values(3); - Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, &VTableIdx, 1); + Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx); Values[1] = GetClassName(ID->getIdentifier()); Values[2] = GetClassGlobal(ClassName); llvm::Constant *Init = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp index 09c8d0b..ef426ce 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -52,9 +52,8 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, // implemented. This should be fixed to get the information from the layout // directly. unsigned Index = 0; - ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl*>(Container); - for (ObjCIvarDecl *IVD = IDecl->all_declared_ivar_begin(); + for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { if (Ivar == IVD) break; @@ -86,9 +85,9 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, unsigned CVRQualifiers, llvm::Value *Offset) { // Compute (type*) ( (char *) BaseValue + Offset) - const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); QualType IvarTy = Ivar->getType(); - const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); + llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr); V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); @@ -118,10 +117,9 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize()); uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); - uint64_t ContainingTypeAlign = CGF.CGM.getContext().Target.getCharAlign(); + uint64_t ContainingTypeAlign = CGF.CGM.getContext().getTargetInfo().getCharAlign(); uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset); - uint64_t BitFieldSize = - Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); + uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); // Allocate a new CGBitFieldInfo object to describe this access. // @@ -178,7 +176,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, FinallyInfo.enter(CGF, Finally->getFinallyBody(), beginCatchFn, endCatchFn, exceptionRethrowFn); - llvm::SmallVector<CatchHandler, 8> Handlers; + SmallVector<CatchHandler, 8> Handlers; // Enter the catch, if there is one. if (S.getNumCatchStmts()) { @@ -212,7 +210,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, // Leave the try. if (S.getNumCatchStmts()) - CGF.EHStack.popCatch(); + CGF.popCatchScope(); // Remember where we were. CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); @@ -222,7 +220,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, CatchHandler &Handler = Handlers[I]; CGF.EmitBlock(Handler.Block); - llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); + llvm::Value *RawExn = CGF.getExceptionFromSlot(); // Enter the catch. llvm::Value *Exn = RawExn; @@ -244,7 +242,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, // Bind the catch parameter if it exists. if (const VarDecl *CatchParam = Handler.Variable) { - const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); + llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); CGF.EmitAutoVarDecl(*CatchParam); @@ -289,21 +287,26 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S, llvm::Function *syncEnterFn, llvm::Function *syncExitFn) { - // Evaluate the lock operand. This should dominate the cleanup. - llvm::Value *SyncArg = - CGF.EmitScalarExpr(S.getSynchExpr()); + CodeGenFunction::RunCleanupsScope cleanups(CGF); + + // Evaluate the lock operand. This is guaranteed to dominate the + // ARC release and lock-release cleanups. + const Expr *lockExpr = S.getSynchExpr(); + llvm::Value *lock; + if (CGF.getLangOptions().ObjCAutoRefCount) { + lock = CGF.EmitARCRetainScalarExpr(lockExpr); + lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock); + } else { + lock = CGF.EmitScalarExpr(lockExpr); + } + lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy); // Acquire the lock. - SyncArg = CGF.Builder.CreateBitCast(SyncArg, syncEnterFn->getFunctionType()->getParamType(0)); - CGF.Builder.CreateCall(syncEnterFn, SyncArg); + CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow(); // Register an all-paths cleanup to release the lock. - CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, - SyncArg); + CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock); // Emit the body of the statement. CGF.EmitStmt(S.getSynchBody()); - - // Pop the lock-release cleanup. - CGF.PopCleanupBlock(); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h index 7accc70..4fa47a7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h @@ -208,8 +208,7 @@ public: virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) { - assert(false &&"autoreleasepool unsupported in this ABI"); - return 0; + llvm_unreachable("autoreleasepool unsupported in this ABI"); } /// EnumerationMutationFunction - Return the function that's called by the diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp new file mode 100644 index 0000000..3a0e116 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -0,0 +1,28 @@ +//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for OpenCL code generation. Concrete +// subclasses of this implement code generation for specific OpenCL +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#include "CGOpenCLRuntime.h" +#include "CodeGenFunction.h" +#include "llvm/GlobalValue.h" + +using namespace clang; +using namespace CodeGen; + +CGOpenCLRuntime::~CGOpenCLRuntime() {} + +void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, + const VarDecl &D) { + return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h new file mode 100644 index 0000000..9a8430f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.h @@ -0,0 +1,46 @@ +//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for OpenCL code generation. Concrete +// subclasses of this implement code generation for specific OpenCL +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H +#define CLANG_CODEGEN_OPENCLRUNTIME_H + +namespace clang { + +class VarDecl; + +namespace CodeGen { + +class CodeGenFunction; +class CodeGenModule; + +class CGOpenCLRuntime { +protected: + CodeGenModule &CGM; + +public: + CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {} + virtual ~CGOpenCLRuntime(); + + /// Emit the IR required for a work-group-local variable declaration, and add + /// an entry to CGF's LocalDeclMap for D. The base class does this using + /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D. + virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, + const VarDecl &D); +}; + +} +} + +#endif diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp index e564c70..fbdb298 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp @@ -26,10 +26,10 @@ class RTTIBuilder { CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; - const llvm::Type *Int8PtrTy; + llvm::Type *Int8PtrTy; /// Fields - The fields of the RTTI descriptor currently being built. - llvm::SmallVector<llvm::Constant *, 16> Fields; + SmallVector<llvm::Constant *, 16> Fields; /// GetAddrOfTypeName - Returns the mangled type name of the given type. llvm::GlobalVariable * @@ -120,7 +120,7 @@ RTTIBuilder::GetAddrOfTypeName(QualType Ty, llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); // We know that the mangled name of the type starts at index 4 of the // mangled name of the typename, so we can just index into it in order to @@ -141,7 +141,7 @@ llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); // Look for an existing global. llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name); @@ -185,6 +185,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: @@ -203,7 +204,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: - assert(false && "FIXME: Objective-C types are unsupported!"); + llvm_unreachable("FIXME: Objective-C types are unsupported!"); } // Silent gcc. @@ -267,7 +268,7 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { /// IsIncompleteClassType - Returns whether the given record type is incomplete. static bool IsIncompleteClassType(const RecordType *RecordTy) { - return !RecordTy->getDecl()->isDefinition(); + return !RecordTy->getDecl()->isCompleteDefinition(); } /// ContainsIncompleteClassType - Returns whether the given type contains an @@ -393,17 +394,18 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Non-canonical and dependent types shouldn't get here"); + llvm_unreachable("Non-canonical and dependent types shouldn't get here"); case Type::LValueReference: case Type::RValueReference: - assert(false && "References shouldn't get here"); + llvm_unreachable("References shouldn't get here"); case Type::Builtin: // GCC treats vector and complex types as fundamental types. case Type::Vector: case Type::ExtVector: case Type::Complex: + case Type::Atomic: // FIXME: GCC treats block pointers as fundamental types?! case Type::BlockPointer: // abi::__fundamental_type_info. @@ -479,12 +481,12 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { llvm::Constant *VTable = CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy); - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); // The vtable address point is 2. llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1); + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two); VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy); Fields.push_back(VTable); @@ -533,7 +535,7 @@ maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV, llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name); @@ -553,7 +555,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); if (OldGV && !OldGV->isDeclaration()) { @@ -580,7 +582,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { // And the name. llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy)); switch (Ty->getTypeClass()) { @@ -590,7 +592,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Non-canonical and dependent types shouldn't get here"); + llvm_unreachable("Non-canonical and dependent types shouldn't get here"); // GCC treats vector types as fundamental types. case Type::Builtin: @@ -604,7 +606,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::LValueReference: case Type::RValueReference: - assert(false && "References shouldn't get here"); + llvm_unreachable("References shouldn't get here"); case Type::ConstantArray: case Type::IncompleteArray: @@ -656,6 +658,10 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::MemberPointer: BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty)); break; + + case Type::Atomic: + // No fields, at least for the moment. + break; } llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields); @@ -822,7 +828,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) { /// classes with bases that do not satisfy the abi::__si_class_type_info /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { - const llvm::Type *UnsignedIntLTy = + llvm::Type *UnsignedIntLTy = CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); // Itanium C++ ABI 2.9.5p6c: @@ -840,7 +846,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { if (!RD->getNumBases()) return; - const llvm::Type *LongLTy = + llvm::Type *LongLTy = CGM.getTypes().ConvertType(CGM.getContext().LongTy); // Now add the base class descriptions. @@ -879,7 +885,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { CharUnits Offset; if (Base->isVirtual()) Offset = - CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl); + CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); Offset = Layout.getBaseClassOffset(BaseDecl); @@ -916,7 +922,7 @@ void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { if (ContainsIncompleteClassType(UnqualifiedPointeeTy)) Flags |= PTI_Incomplete; - const llvm::Type *UnsignedIntLTy = + llvm::Type *UnsignedIntLTy = CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); @@ -953,7 +959,7 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { if (IsIncompleteClassType(ClassType)) Flags |= PTI_ContainingClassIncomplete; - const llvm::Type *UnsignedIntLTy = + llvm::Type *UnsignedIntLTy = CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); @@ -977,12 +983,12 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, // FIXME: should we even be calling this method if RTTI is disabled // and it's not for EH? if (!ForEH && !getContext().getLangOptions().RTTI) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); return llvm::Constant::getNullValue(Int8PtrTy); } if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) { - return Runtime->GetEHType(Ty); + return ObjCRuntime->GetEHType(Ty); } return RTTIBuilder(*this).BuildTypeInfo(Ty); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h index 8a45029..25a0a50 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h @@ -10,12 +10,13 @@ #ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H #define CLANG_CODEGEN_CGRECORDLAYOUT_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/DerivedTypes.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/DerivedTypes.h" + namespace llvm { - class raw_ostream; class StructType; } @@ -144,7 +145,7 @@ public: /// @} - void print(llvm::raw_ostream &OS) const; + void print(raw_ostream &OS) const; void dump() const; /// \brief Given a bit-field decl, build an appropriate helper object for @@ -270,7 +271,7 @@ public: return it->second; } - void print(llvm::raw_ostream &OS) const; + void print(raw_ostream &OS) const; void dump() const; }; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 2b07baf..6475cca 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -35,7 +35,7 @@ class CGRecordLayoutBuilder { public: /// FieldTypes - Holds the LLVM types that the struct is created from. /// - llvm::SmallVector<llvm::Type *, 16> FieldTypes; + SmallVector<llvm::Type *, 16> FieldTypes; /// BaseSubobjectType - Holds the LLVM type for the non-virtual part /// of the struct. For example, consider: @@ -174,7 +174,7 @@ private: /// the passed size. void AppendTailPadding(CharUnits RecordSize); - CharUnits getTypeAlignment(const llvm::Type *Ty) const; + CharUnits getTypeAlignment(llvm::Type *Ty) const; /// getAlignmentAsLLVMStruct - Returns the maximum alignment of all the /// LLVM element types. @@ -230,7 +230,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, uint64_t FieldSize, uint64_t ContainingTypeSizeInBits, unsigned ContainingTypeAlign) { - const llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType()); + llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType()); CharUnits TypeSizeInBytes = CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty)); uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes); @@ -363,15 +363,14 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, uint64_t fieldOffset) { - uint64_t fieldSize = - D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + uint64_t fieldSize = D->getBitWidthValue(Types.getContext()); if (fieldSize == 0) return; uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset); CharUnits numBytesToAppend; - unsigned charAlign = Types.getContext().Target.getCharAlign(); + unsigned charAlign = Types.getContext().getTargetInfo().getCharAlign(); if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) { assert(fieldOffset % charAlign == 0 && @@ -492,8 +491,7 @@ llvm::Type * CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, const ASTRecordLayout &Layout) { if (Field->isBitField()) { - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + uint64_t FieldSize = Field->getBitWidthValue(Types.getContext()); // Ignore zero sized bit fields. if (FieldSize == 0) @@ -502,7 +500,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext()); CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits( llvm::RoundUpToAlignment(FieldSize, - Types.getContext().Target.getCharAlign())); + Types.getContext().getTargetInfo().getCharAlign())); if (NumBytesToAppend > CharUnits::One()) FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity()); @@ -672,10 +670,10 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, // Check if we need to add a vtable pointer. if (RD->isDynamicClass()) { if (!PrimaryBase) { - const llvm::Type *FunctionType = + llvm::Type *FunctionType = llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()), /*isVarArg=*/true); - const llvm::Type *VTableTy = FunctionType->getPointerTo(); + llvm::Type *VTableTy = FunctionType->getPointerTo(); assert(NextFieldOffset.isZero() && "VTable pointer must come first!"); @@ -735,8 +733,8 @@ CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { } - BaseSubobjectType = llvm::StructType::createNamed(Types.getLLVMContext(), "", - FieldTypes, Packed); + BaseSubobjectType = llvm::StructType::create(Types.getLLVMContext(), + FieldTypes, "", Packed); Types.addRecordTypeName(RD, BaseSubobjectType, ".base"); // Pull the padding back off. @@ -882,7 +880,7 @@ void CGRecordLayoutBuilder::AppendBytes(CharUnits numBytes) { AppendField(NextFieldOffset, getByteArrayType(numBytes)); } -CharUnits CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { +CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const { if (Packed) return CharUnits::One(); @@ -983,7 +981,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, } // Verify that the LLVM and AST field offsets agree. - const llvm::StructType *ST = + llvm::StructType *ST = dyn_cast<llvm::StructType>(RL->getLLVMType()); const llvm::StructLayout *SL = getTargetData().getStructLayout(ST); @@ -1037,7 +1035,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, return RL; } -void CGRecordLayout::print(llvm::raw_ostream &OS) const { +void CGRecordLayout::print(raw_ostream &OS) const { OS << "<CGRecordLayout\n"; OS << " LLVMType:" << *CompleteObjectType << "\n"; if (BaseSubobjectType) @@ -1071,7 +1069,7 @@ void CGRecordLayout::dump() const { print(llvm::errs()); } -void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { +void CGBitFieldInfo::print(raw_ostream &OS) const { OS << "<CGBitFieldInfo"; OS << " Size:" << Size; OS << " IsSigned:" << IsSigned << "\n"; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp index 07bddb7..c56931b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp @@ -31,20 +31,19 @@ using namespace CodeGen; void CodeGenFunction::EmitStopPoint(const Stmt *S) { if (CGDebugInfo *DI = getDebugInfo()) { + SourceLocation Loc; if (isa<DeclStmt>(S)) - DI->setLocation(S->getLocEnd()); + Loc = S->getLocEnd(); else - DI->setLocation(S->getLocStart()); - DI->UpdateLineDirectiveRegion(Builder); - DI->EmitStopPoint(Builder); + Loc = S->getLocStart(); + DI->EmitLocation(Builder, Loc); } } void CodeGenFunction::EmitStmt(const Stmt *S) { assert(S && "Null statement?"); - // Check if we can handle this without bothering to generate an - // insert point or debug info. + // These statements have their own debug info handling. if (EmitSimpleStmt(S)) return; @@ -137,11 +136,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S)); break; case Stmt::ObjCAtCatchStmtClass: - assert(0 && "@catch statements should be handled by EmitObjCAtTryStmt"); - break; + llvm_unreachable( + "@catch statements should be handled by EmitObjCAtTryStmt"); case Stmt::ObjCAtFinallyStmtClass: - assert(0 && "@finally statements should be handled by EmitObjCAtTryStmt"); - break; + llvm_unreachable( + "@finally statements should be handled by EmitObjCAtTryStmt"); case Stmt::ObjCAtThrowStmtClass: EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S)); break; @@ -192,10 +191,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, "LLVM IR generation of compound statement ('{}')"); CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getLBracLoc()); - DI->EmitRegionStart(Builder); - } + if (DI) + DI->EmitLexicalBlockStart(Builder, S.getLBracLoc()); // Keep track of the current cleanup stack depth. RunCleanupsScope Scope(*this); @@ -204,10 +201,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, E = S.body_end()-GetLast; I != E; ++I) EmitStmt(*I); - if (DI) { - DI->setLocation(S.getRBracLoc()); - DI->EmitRegionEnd(Builder); - } + if (DI) + DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc()); RValue RV; if (!GetLast) @@ -286,6 +281,23 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) { Builder.ClearInsertionPoint(); } +void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) { + bool inserted = false; + for (llvm::BasicBlock::use_iterator + i = block->use_begin(), e = block->use_end(); i != e; ++i) { + if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(*i)) { + CurFn->getBasicBlockList().insertAfter(insn->getParent(), block); + inserted = true; + break; + } + } + + if (!inserted) + CurFn->getBasicBlockList().push_back(block); + + Builder.SetInsertPoint(block); +} + CodeGenFunction::JumpDest CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) { JumpDest &Dest = LabelMap[D]; @@ -555,10 +567,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { RunCleanupsScope ForScope(*this); CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getSourceRange().getBegin()); - DI->EmitRegionStart(Builder); - } + if (DI) + DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); // Evaluate the first part before the loop. if (S.getInit()) @@ -637,10 +647,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { ForScope.ForceCleanup(); - if (DI) { - DI->setLocation(S.getSourceRange().getEnd()); - DI->EmitRegionEnd(Builder); - } + if (DI) + DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); @@ -652,10 +660,8 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) { RunCleanupsScope ForScope(*this); CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getSourceRange().getBegin()); - DI->EmitRegionStart(Builder); - } + if (DI) + DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); // Evaluate the first pieces before the loop. EmitStmt(S.getRangeStmt()); @@ -711,10 +717,8 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) { ForScope.ForceCleanup(); - if (DI) { - DI->setLocation(S.getSourceRange().getEnd()); - DI->EmitRegionEnd(Builder); - } + if (DI) + DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); @@ -767,7 +771,10 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } else if (RV->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(RV, ReturnValue, false); } else { - EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), true)); + EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } EmitBranchThroughCleanup(ReturnBlock); @@ -816,8 +823,8 @@ void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) { void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { assert(S.getRHS() && "Expected RHS value in CaseStmt"); - llvm::APSInt LHS = S.getLHS()->EvaluateAsInt(getContext()); - llvm::APSInt RHS = S.getRHS()->EvaluateAsInt(getContext()); + llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext()); + llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext()); // Emit the code for this case. We do this first to make sure it is // properly chained from our predecessor before generating the @@ -856,7 +863,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { // Emit range check. llvm::Value *Diff = - Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS), "tmp"); + Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS)); llvm::Value *Cond = Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds"); Builder.CreateCondBr(Cond, CaseDest, FalseDest); @@ -876,7 +883,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { } llvm::ConstantInt *CaseVal = - Builder.getInt(S.getLHS()->EvaluateAsInt(getContext())); + Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext())); // If the body of the case is just a 'break', and if there was no fallthrough, // try to not emit an empty block. @@ -917,7 +924,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { while (NextCase && NextCase->getRHS() == 0) { CurCase = NextCase; llvm::ConstantInt *CaseVal = - Builder.getInt(CurCase->getLHS()->EvaluateAsInt(getContext())); + Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext())); SwitchInsn->addCase(CaseVal, CaseDest); NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt()); } @@ -961,7 +968,7 @@ enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success }; static CSFC_Result CollectStatementsForCase(const Stmt *S, const SwitchCase *Case, bool &FoundCase, - llvm::SmallVectorImpl<const Stmt*> &ResultStmts) { + SmallVectorImpl<const Stmt*> &ResultStmts) { // If this is a null statement, just succeed. if (S == 0) return Case ? CSFC_Success : CSFC_FallThrough; @@ -1086,7 +1093,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S, /// for more details. static bool FindCaseStatementsForValue(const SwitchStmt &S, const llvm::APInt &ConstantCondValue, - llvm::SmallVectorImpl<const Stmt*> &ResultStmts, + SmallVectorImpl<const Stmt*> &ResultStmts, ASTContext &C) { // First step, find the switch case that is being branched to. We can do this // efficiently by scanning the SwitchCase list. @@ -1107,7 +1114,7 @@ static bool FindCaseStatementsForValue(const SwitchStmt &S, if (CS->getRHS()) return false; // If we found our case, remember it as 'case'. - if (CS->getLHS()->EvaluateAsInt(C) == ConstantCondValue) + if (CS->getLHS()->EvaluateKnownConstInt(C) == ConstantCondValue) break; } @@ -1147,7 +1154,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { // emit the live case statement (if any) of the switch. llvm::APInt ConstantCondValue; if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) { - llvm::SmallVector<const Stmt*, 4> CaseStmts; + SmallVector<const Stmt*, 4> CaseStmts; if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts, getContext())) { RunCleanupsScope ExecutedScope(*this); @@ -1219,7 +1226,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { static std::string SimplifyConstraint(const char *Constraint, const TargetInfo &Target, - llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) { + SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) { std::string Result; while (*Constraint) { @@ -1276,7 +1283,7 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>(); if (!Attr) return Constraint; - llvm::StringRef Register = Attr->getLabel(); + StringRef Register = Attr->getLabel(); assert(Target.isValidGCCRegisterName(Register)); // We're using validateOutputConstraint here because we only care if // this is a register constraint. @@ -1301,7 +1308,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S, if (!CodeGenFunction::hasAggregateLLVMType(InputType)) { Arg = EmitLoadOfLValue(InputValue).getScalarVal(); } else { - const llvm::Type *Ty = ConvertType(InputType); + llvm::Type *Ty = ConvertType(InputType); uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty); if (Size <= 64 && llvm::isPowerOf2_64(Size)) { Ty = llvm::IntegerType::get(getLLVMContext(), Size); @@ -1341,11 +1348,11 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, /// asm. static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, CodeGenFunction &CGF) { - llvm::SmallVector<llvm::Value *, 8> Locs; + SmallVector<llvm::Value *, 8> Locs; // Add the location of the first line to the MDNode. Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, Str->getLocStart().getRawEncoding())); - llvm::StringRef StrVal = Str->getString(); + StringRef StrVal = Str->getString(); if (!StrVal.empty()) { const SourceManager &SM = CGF.CGM.getContext().getSourceManager(); const LangOptions &LangOpts = CGF.CGM.getLangOptions(); @@ -1367,7 +1374,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Analyze the asm string to decompose it into its pieces. We know that Sema // has already done this, so it is guaranteed to be successful. - llvm::SmallVector<AsmStmt::AsmStringPiece, 4> Pieces; + SmallVector<AsmStmt::AsmStringPiece, 4> Pieces; unsigned DiagOffs; S.AnalyzeAsmString(Pieces, getContext(), DiagOffs); @@ -1384,8 +1391,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { } // Get all the output and input constraints together. - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), @@ -1530,14 +1537,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Use ptrtoint as appropriate so that we can do our extension. if (isa<llvm::PointerType>(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, IntPtrTy); - const llvm::Type *OutputTy = ConvertType(OutputType); + llvm::Type *OutputTy = ConvertType(OutputType); if (isa<llvm::IntegerType>(OutputTy)) Arg = Builder.CreateZExt(Arg, OutputTy); - else + else if (isa<llvm::PointerType>(OutputTy)) + Arg = Builder.CreateZExt(Arg, IntPtrTy); + else { + assert(OutputTy->isFloatingPointTy() && "Unexpected output type"); Arg = Builder.CreateFPExt(Arg, OutputTy); + } } } - if (const llvm::Type* AdjTy = + if (llvm::Type* AdjTy = getTargetHooks().adjustInlineAsmType(*this, InputConstraint, Arg->getType())) Arg = Builder.CreateBitCast(Arg, AdjTy); @@ -1556,7 +1567,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { - llvm::StringRef Clobber = S.getClobber(i)->getString(); + StringRef Clobber = S.getClobber(i)->getString(); if (Clobber != "memory" && Clobber != "cc") Clobber = Target.getNormalizedGCCRegisterName(Clobber); @@ -1577,7 +1588,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Constraints += MachineClobbers; } - const llvm::Type *ResultType; + llvm::Type *ResultType; if (ResultRegTypes.empty()) ResultType = llvm::Type::getVoidTy(getLLVMContext()); else if (ResultRegTypes.size() == 1) @@ -1585,7 +1596,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { else ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(ResultType, ArgTypes, false); llvm::InlineAsm *IA = @@ -1615,7 +1626,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // If the result type of the LLVM IR asm doesn't match the result type of // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { - const llvm::Type *TruncTy = ResultTruncRegTypes[i]; + llvm::Type *TruncTy = ResultTruncRegTypes[i]; // Truncate the integer result to the right size, note that TruncTy can be // a pointer. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp index cec02cd..ea7b8cb 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp @@ -14,383 +14,81 @@ #include "CodeGenModule.h" #include "CGCXXABI.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/VTTBuilder.h" using namespace clang; using namespace CodeGen; #define D1(x) -namespace { - -/// VTT builder - Class for building VTT layout information. -class VTTBuilder { - - CodeGenModule &CGM; - - /// MostDerivedClass - The most derived class for which we're building this - /// vtable. - const CXXRecordDecl *MostDerivedClass; - - typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy; - - /// VTTComponents - The VTT components. - VTTComponentsVectorTy VTTComponents; - - /// MostDerivedClassLayout - the AST record layout of the most derived class. - const ASTRecordLayout &MostDerivedClassLayout; - - typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - - typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; - - /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived - /// class. - llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; - - /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of - /// all subobjects of the most derived class. - llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices; - - /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for - /// the VTT. - bool GenerateDefinition; - - /// The linkage to use for any construction vtables required by this VTT. - /// Only required if we're building a definition. - llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables; - - /// GetAddrOfVTable - Returns the address of the vtable for the base class in - /// the given vtable class. - /// - /// \param AddressPoints - If the returned vtable is a construction vtable, - /// this will hold the address points for it. - llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, - AddressPointsMapTy& AddressPoints); - - /// AddVTablePointer - Add a vtable pointer to the VTT currently being built. - /// - /// \param AddressPoints - If the vtable is a construction vtable, this has - /// the address points for it. - void AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, - const CXXRecordDecl *VTableClass, - const AddressPointsMapTy& AddressPoints); - - /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base - /// subobject. - void LayoutSecondaryVTTs(BaseSubobject Base); - - /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers - /// for the given base subobject. - /// - /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - /// - /// \param AddressPoints - If the vtable is a construction vtable, this has - /// the address points for it. - void LayoutSecondaryVirtualPointers(BaseSubobject Base, - bool BaseIsMorallyVirtual, - llvm::Constant *VTable, - const CXXRecordDecl *VTableClass, - const AddressPointsMapTy& AddressPoints, - VisitedVirtualBasesSetTy &VBases); - - /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers - /// for the given base subobject. - /// - /// \param AddressPoints - If the vtable is a construction vtable, this has - /// the address points for it. - void LayoutSecondaryVirtualPointers(BaseSubobject Base, - llvm::Constant *VTable, - const AddressPointsMapTy& AddressPoints); - - /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the - /// given record decl. - void LayoutVirtualVTTs(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases); - - /// LayoutVTT - Will lay out the VTT for the given subobject, including any - /// secondary VTTs, secondary virtual pointers and virtual VTTs. - void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual); - -public: - VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass, - bool GenerateDefinition, - llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables - = (llvm::GlobalVariable::LinkageTypes) -1); - - // getVTTComponents - Returns a reference to the VTT components. - const VTTComponentsVectorTy &getVTTComponents() const { - return VTTComponents; - } - - /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. - const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const { - return SubVTTIndicies; - } - - /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary - /// virtual pointer indices. - const llvm::DenseMap<BaseSubobject, uint64_t> & - getSecondaryVirtualPointerIndices() const { - return SecondaryVirtualPointerIndices; - } - -}; - -VTTBuilder::VTTBuilder(CodeGenModule &CGM, - const CXXRecordDecl *MostDerivedClass, - bool GenerateDefinition, - llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables) - : CGM(CGM), MostDerivedClass(MostDerivedClass), - MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)), - GenerateDefinition(GenerateDefinition), - LinkageForConstructionVTables(LinkageForConstructionVTables) { - assert(!GenerateDefinition || - LinkageForConstructionVTables - != (llvm::GlobalVariable::LinkageTypes) -1); - - // Lay out this VTT. - LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), - /*BaseIsVirtual=*/false); -} - -llvm::Constant * -VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, - AddressPointsMapTy& AddressPoints) { - if (!GenerateDefinition) - return 0; - - if (Base.getBase() == MostDerivedClass) { - assert(Base.getBaseOffset().isZero() && +llvm::Constant *GetAddrOfVTTVTable(CodeGenVTables &CGVT, + const CXXRecordDecl *MostDerivedClass, + const VTTVTable &VTable, + llvm::GlobalVariable::LinkageTypes Linkage, + llvm::DenseMap<BaseSubobject, uint64_t> &AddressPoints) { + if (VTable.getBase() == MostDerivedClass) { + assert(VTable.getBaseOffset().isZero() && "Most derived class vtable must have a zero offset!"); // This is a regular vtable. - return CGM.getVTables().GetAddrOfVTable(MostDerivedClass); + return CGVT.GetAddrOfVTable(MostDerivedClass); } - return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass, - Base, BaseIsVirtual, - LinkageForConstructionVTables, - AddressPoints); + return CGVT.GenerateConstructionVTable(MostDerivedClass, + VTable.getBaseSubobject(), + VTable.isVirtual(), + Linkage, + AddressPoints); } -void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, - const CXXRecordDecl *VTableClass, - const AddressPointsMapTy& AddressPoints) { - // Store the vtable pointer index if we're generating the primary VTT. - if (VTableClass == MostDerivedClass) { - assert(!SecondaryVirtualPointerIndices.count(Base) && - "A virtual pointer index already exists for this base subobject!"); - SecondaryVirtualPointerIndices[Base] = VTTComponents.size(); - } - - if (!GenerateDefinition) { - VTTComponents.push_back(0); - return; - } - - uint64_t AddressPoint; - if (VTableClass != MostDerivedClass) { - // The vtable is a construction vtable, look in the construction vtable - // address points. - AddressPoint = AddressPoints.lookup(Base); - assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); - } else { - // Just get the address point for the regular vtable. - AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); - assert(AddressPoint != 0 && "Did not find vtable address point!"); - } +void +CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true); - if (!AddressPoint) AddressPoint = 0; - - llvm::Value *Idxs[] = { - llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), - llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), - AddressPoint) - }; - - llvm::Constant *Init = - llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()), + *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); - VTTComponents.push_back(Init); -} - -void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { - const CXXRecordDecl *RD = Base.getBase(); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - - // Don't layout virtual bases. - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - CharUnits BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - // Layout the VTT for this base. - LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); + SmallVector<llvm::Constant *, 8> VTables; + SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints; + for (const VTTVTable *i = Builder.getVTTVTables().begin(), + *e = Builder.getVTTVTables().end(); i != e; ++i) { + VTableAddressPoints.push_back(VTableAddressPointsMapTy()); + VTables.push_back(GetAddrOfVTTVTable(*this, RD, *i, Linkage, + VTableAddressPoints.back())); } -} - -void -VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, - bool BaseIsMorallyVirtual, - llvm::Constant *VTable, - const CXXRecordDecl *VTableClass, - const AddressPointsMapTy& AddressPoints, - VisitedVirtualBasesSetTy &VBases) { - const CXXRecordDecl *RD = Base.getBase(); - - // We're not interested in bases that don't have virtual bases, and not - // morally virtual bases. - if (!RD->getNumVBases() && !BaseIsMorallyVirtual) - return; - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Itanium C++ ABI 2.6.2: - // Secondary virtual pointers are present for all bases with either - // virtual bases or virtual function declarations overridden along a - // virtual path. - // - // If the base class is not dynamic, we don't want to add it, nor any - // of its base classes. - if (!BaseDecl->isDynamicClass()) - continue; - - bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; - bool BaseDeclIsNonVirtualPrimaryBase = false; - CharUnits BaseOffset; - if (I->isVirtual()) { - // Ignore virtual bases that we've already visited. - if (!VBases.insert(BaseDecl)) - continue; - - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - BaseDeclIsMorallyVirtual = true; + SmallVector<llvm::Constant *, 8> VTTComponents; + for (const VTTComponent *i = Builder.getVTTComponents().begin(), + *e = Builder.getVTTComponents().end(); i != e; ++i) { + const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex]; + llvm::Constant *VTable = VTables[i->VTableIndex]; + uint64_t AddressPoint; + if (VTTVT.getBase() == RD) { + // Just get the address point for the regular vtable. + AddressPoint = VTContext.getVTableLayout(RD) + .getAddressPoint(i->VTableBase); + assert(AddressPoint != 0 && "Did not find vtable address point!"); } else { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - - BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - if (!Layout.isPrimaryBaseVirtual() && - Layout.getPrimaryBase() == BaseDecl) - BaseDeclIsNonVirtualPrimaryBase = true; + AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase); + assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); } - // Itanium C++ ABI 2.6.2: - // Secondary virtual pointers: for each base class X which (a) has virtual - // bases or is reachable along a virtual path from D, and (b) is not a - // non-virtual primary base, the address of the virtual table for X-in-D - // or an appropriate construction virtual table. - if (!BaseDeclIsNonVirtualPrimaryBase && - (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { - // Add the vtable pointer. - AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, - VTableClass, AddressPoints); - } + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(Int64Ty, 0), + llvm::ConstantInt::get(Int64Ty, AddressPoint) + }; - // And lay out the secondary virtual pointers for the base class. - LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), - BaseDeclIsMorallyVirtual, VTable, - VTableClass, AddressPoints, VBases); - } -} + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs); -void -VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, - llvm::Constant *VTable, - const AddressPointsMapTy& AddressPoints) { - VisitedVirtualBasesSetTy VBases; - LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false, - VTable, Base.getBase(), AddressPoints, VBases); -} + Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); -void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases) { - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Check if this is a virtual base. - if (I->isVirtual()) { - // Check if we've seen this base before. - if (!VBases.insert(BaseDecl)) - continue; - - CharUnits BaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); - } - - // We only need to layout virtual VTTs for this base if it actually has - // virtual bases. - if (BaseDecl->getNumVBases()) - LayoutVirtualVTTs(BaseDecl, VBases); + VTTComponents.push_back(Init); } -} -void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { - const CXXRecordDecl *RD = Base.getBase(); - - // Itanium C++ ABI 2.6.2: - // An array of virtual table addresses, called the VTT, is declared for - // each class type that has indirect or direct virtual base classes. - if (RD->getNumVBases() == 0) - return; - - bool IsPrimaryVTT = Base.getBase() == MostDerivedClass; - - if (!IsPrimaryVTT) { - // Remember the sub-VTT index. - SubVTTIndicies[Base] = VTTComponents.size(); - } - - AddressPointsMapTy AddressPoints; - llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints); - - // Add the primary vtable pointer. - AddVTablePointer(Base, VTable, RD, AddressPoints); - - // Add the secondary VTTs. - LayoutSecondaryVTTs(Base); - - // Add the secondary virtual pointers. - LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints); - - // If this is the primary VTT, we want to lay out virtual VTTs as well. - if (IsPrimaryVTT) { - VisitedVirtualBasesSetTy VBases; - LayoutVirtualVTTs(Base.getBase(), VBases); - } -} - -} - -void -CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { - VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true, Linkage); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - const llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); - - llvm::Constant *Init = - llvm::ConstantArray::get(ArrayType, Builder.getVTTComponents()); + llvm::Constant *Init = llvm::ConstantArray::get(ArrayType, VTTComponents); VTT->setInitializer(Init); @@ -408,15 +106,16 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) { llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); - ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true); + // This will also defer the definition of the VTT. + (void) GetAddrOfVTable(RD); - VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false); - const llvm::Type *Int8PtrTy = + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - const llvm::ArrayType *ArrayType = + llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size()); llvm::GlobalVariable *GV = @@ -452,7 +151,7 @@ uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, if (I != SubVTTIndicies.end()) return I->second; - VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false); for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = Builder.getSubVTTIndicies().begin(), @@ -478,7 +177,7 @@ CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, if (I != SecondaryVirtualPointerIndices.end()) return I->second; - VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); + VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false); // Insert all secondary vpointer indices. for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp index c161b79..a306c85 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp @@ -28,2399 +28,8 @@ using namespace clang; using namespace CodeGen; -namespace { - -/// BaseOffset - Represents an offset from a derived class to a direct or -/// indirect base class. -struct BaseOffset { - /// DerivedClass - The derived class. - const CXXRecordDecl *DerivedClass; - - /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. - const CXXRecordDecl *VirtualBase; - - /// NonVirtualOffset - The offset from the derived class to the base class. - /// (Or the offset from the virtual base class to the base class, if the - /// path from the derived class to the base class involves a virtual base - /// class. - CharUnits NonVirtualOffset; - - BaseOffset() : DerivedClass(0), VirtualBase(0), - NonVirtualOffset(CharUnits::Zero()) { } - BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset) - : DerivedClass(DerivedClass), VirtualBase(VirtualBase), - NonVirtualOffset(NonVirtualOffset) { } - - bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; } -}; - -/// FinalOverriders - Contains the final overrider member functions for all -/// member functions in the base subobjects of a class. -class FinalOverriders { -public: - /// OverriderInfo - Information about a final overrider. - struct OverriderInfo { - /// Method - The method decl of the overrider. - const CXXMethodDecl *Method; - - /// Offset - the base offset of the overrider in the layout class. - CharUnits Offset; - - OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { } - }; - -private: - /// MostDerivedClass - The most derived class for which the final overriders - /// are stored. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building final overriders for a - /// construction vtable, this holds the offset from the layout class to the - /// most derived class. - const CharUnits MostDerivedClassOffset; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if the final overriders are for a - /// construction vtable. - const CXXRecordDecl *LayoutClass; - - ASTContext &Context; - - /// MostDerivedClassLayout - the AST record layout of the most derived class. - const ASTRecordLayout &MostDerivedClassLayout; - - /// MethodBaseOffsetPairTy - Uniquely identifies a member function - /// in a base subobject. - typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy; - - typedef llvm::DenseMap<MethodBaseOffsetPairTy, - OverriderInfo> OverridersMapTy; - - /// OverridersMap - The final overriders for all virtual member functions of - /// all the base subobjects of the most derived class. - OverridersMapTy OverridersMap; - - /// SubobjectsToOffsetsMapTy - A mapping from a base subobject (represented - /// as a record decl and a subobject number) and its offsets in the most - /// derived class as well as the layout class. - typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>, - CharUnits> SubobjectOffsetMapTy; - - typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy; - - /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the - /// given base. - void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, - CharUnits OffsetInLayoutClass, - SubobjectOffsetMapTy &SubobjectOffsets, - SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, - SubobjectCountMapTy &SubobjectCounts); - - typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - - /// dump - dump the final overriders for a base subobject, and all its direct - /// and indirect base subobjects. - void dump(llvm::raw_ostream &Out, BaseSubobject Base, - VisitedVirtualBasesSetTy& VisitedVirtualBases); - -public: - FinalOverriders(const CXXRecordDecl *MostDerivedClass, - CharUnits MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass); - - /// getOverrider - Get the final overrider for the given method declaration in - /// the subobject with the given base offset. - OverriderInfo getOverrider(const CXXMethodDecl *MD, - CharUnits BaseOffset) const { - assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) && - "Did not find overrider!"); - - return OverridersMap.lookup(std::make_pair(MD, BaseOffset)); - } - - /// dump - dump the final overriders. - void dump() { - VisitedVirtualBasesSetTy VisitedVirtualBases; - dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()), - VisitedVirtualBases); - } - -}; - -#define DUMP_OVERRIDERS 0 - -FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, - CharUnits MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass) - : MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), - MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { - - // Compute base offsets. - SubobjectOffsetMapTy SubobjectOffsets; - SubobjectOffsetMapTy SubobjectLayoutClassOffsets; - SubobjectCountMapTy SubobjectCounts; - ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()), - /*IsVirtual=*/false, - MostDerivedClassOffset, - SubobjectOffsets, SubobjectLayoutClassOffsets, - SubobjectCounts); - - // Get the the final overriders. - CXXFinalOverriderMap FinalOverriders; - MostDerivedClass->getFinalOverriders(FinalOverriders); - - for (CXXFinalOverriderMap::const_iterator I = FinalOverriders.begin(), - E = FinalOverriders.end(); I != E; ++I) { - const CXXMethodDecl *MD = I->first; - const OverridingMethods& Methods = I->second; - - for (OverridingMethods::const_iterator I = Methods.begin(), - E = Methods.end(); I != E; ++I) { - unsigned SubobjectNumber = I->first; - assert(SubobjectOffsets.count(std::make_pair(MD->getParent(), - SubobjectNumber)) && - "Did not find subobject offset!"); - - CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), - SubobjectNumber)]; - - assert(I->second.size() == 1 && "Final overrider is not unique!"); - const UniqueVirtualMethod &Method = I->second.front(); - - const CXXRecordDecl *OverriderRD = Method.Method->getParent(); - assert(SubobjectLayoutClassOffsets.count( - std::make_pair(OverriderRD, Method.Subobject)) - && "Did not find subobject offset!"); - CharUnits OverriderOffset = - SubobjectLayoutClassOffsets[std::make_pair(OverriderRD, - Method.Subobject)]; - - OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)]; - assert(!Overrider.Method && "Overrider should not exist yet!"); - - Overrider.Offset = OverriderOffset; - Overrider.Method = Method.Method; - } - } - -#if DUMP_OVERRIDERS - // And dump them (for now). - dump(); -#endif -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { - CharUnits NonVirtualOffset = CharUnits::Zero(); - - unsigned NonVirtualStart = 0; - const CXXRecordDecl *VirtualBase = 0; - - // First, look for the virtual base class. - for (unsigned I = 0, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - if (Element.Base->isVirtual()) { - // FIXME: Can we break when we find the first virtual base? - // (If we can't, can't we just iterate over the path in reverse order?) - NonVirtualStart = I + 1; - QualType VBaseType = Element.Base->getType(); - VirtualBase = - cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); - } - } - - // Now compute the non-virtual offset. - for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - // Check the base class offset. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - - const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); - const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - - NonVirtualOffset += Layout.getBaseClassOffset(Base); - } - - // FIXME: This should probably use CharUnits or something. Maybe we should - // even change the base offsets in ASTRecordLayout to be specified in - // CharUnits. - return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset); - -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *BaseRD, - const CXXRecordDecl *DerivedRD) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - - if (!const_cast<CXXRecordDecl *>(DerivedRD)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - return ComputeBaseOffset(Context, DerivedRD, Paths.front()); -} - -static BaseOffset -ComputeReturnAdjustmentBaseOffset(ASTContext &Context, - const CXXMethodDecl *DerivedMD, - const CXXMethodDecl *BaseMD) { - const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>(); - const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>(); - - // Canonicalize the return types. - CanQualType CanDerivedReturnType = - Context.getCanonicalType(DerivedFT->getResultType()); - CanQualType CanBaseReturnType = - Context.getCanonicalType(BaseFT->getResultType()); - - assert(CanDerivedReturnType->getTypeClass() == - CanBaseReturnType->getTypeClass() && - "Types must have same type class!"); - - if (CanDerivedReturnType == CanBaseReturnType) { - // No adjustment needed. - return BaseOffset(); - } - - if (isa<ReferenceType>(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs<ReferenceType>()->getPointeeType(); - } else if (isa<PointerType>(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs<PointerType>()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs<PointerType>()->getPointeeType(); - } else { - assert(false && "Unexpected return type!"); - } - - // We need to compare unqualified types here; consider - // const T *Base::foo(); - // T *Derived::foo(); - if (CanDerivedReturnType.getUnqualifiedType() == - CanBaseReturnType.getUnqualifiedType()) { - // No adjustment needed. - return BaseOffset(); - } - - const CXXRecordDecl *DerivedRD = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); - - const CXXRecordDecl *BaseRD = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); - - return ComputeBaseOffset(Context, BaseRD, DerivedRD); -} - -void -FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, - CharUnits OffsetInLayoutClass, - SubobjectOffsetMapTy &SubobjectOffsets, - SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, - SubobjectCountMapTy &SubobjectCounts) { - const CXXRecordDecl *RD = Base.getBase(); - - unsigned SubobjectNumber = 0; - if (!IsVirtual) - SubobjectNumber = ++SubobjectCounts[RD]; - - // Set up the subobject to offset mapping. - assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber)) - && "Subobject offset already exists!"); - assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber)) - && "Subobject offset already exists!"); - - SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset(); - SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] = - OffsetInLayoutClass; - - // Traverse our bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - CharUnits BaseOffset; - CharUnits BaseOffsetInLayoutClass; - if (I->isVirtual()) { - // Check if we've visited this virtual base before. - if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0))) - continue; - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - CharUnits Offset = Layout.getBaseClassOffset(BaseDecl); - - BaseOffset = Base.getBaseOffset() + Offset; - BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset; - } - - ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), - I->isVirtual(), BaseOffsetInLayoutClass, - SubobjectOffsets, SubobjectLayoutClassOffsets, - SubobjectCounts); - } -} - -void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base, - VisitedVirtualBasesSetTy &VisitedVirtualBases) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Ignore bases that don't have any virtual member functions. - if (!BaseDecl->isPolymorphic()) - continue; - - CharUnits BaseOffset; - if (I->isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) { - // We've visited this base before. - continue; - } - - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); - } - - dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases); - } - - Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; - Out << Base.getBaseOffset().getQuantity() << ")\n"; - - // Now dump the overriders for this base subobject. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset()); - - Out << " " << MD->getQualifiedNameAsString() << " - ("; - Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << ", " << Overrider.Offset.getQuantity() << ')'; - - BaseOffset Offset; - if (!Overrider.Method->isPure()) - Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); - - if (!Offset.isEmpty()) { - Out << " [ret-adj: "; - if (Offset.VirtualBase) - Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - - Out << Offset.NonVirtualOffset.getQuantity() << " nv]"; - } - - Out << "\n"; - } -} - -/// VTableComponent - Represents a single component in a vtable. -class VTableComponent { -public: - enum Kind { - CK_VCallOffset, - CK_VBaseOffset, - CK_OffsetToTop, - CK_RTTI, - CK_FunctionPointer, - - /// CK_CompleteDtorPointer - A pointer to the complete destructor. - CK_CompleteDtorPointer, - - /// CK_DeletingDtorPointer - A pointer to the deleting destructor. - CK_DeletingDtorPointer, - - /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer - /// will end up never being called. Such vtable function pointers are - /// represented as a CK_UnusedFunctionPointer. - CK_UnusedFunctionPointer - }; - - static VTableComponent MakeVCallOffset(CharUnits Offset) { - return VTableComponent(CK_VCallOffset, Offset); - } - - static VTableComponent MakeVBaseOffset(CharUnits Offset) { - return VTableComponent(CK_VBaseOffset, Offset); - } - - static VTableComponent MakeOffsetToTop(CharUnits Offset) { - return VTableComponent(CK_OffsetToTop, Offset); - } - - static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { - return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); - } - - static VTableComponent MakeFunction(const CXXMethodDecl *MD) { - assert(!isa<CXXDestructorDecl>(MD) && - "Don't use MakeFunction with destructors!"); - - return VTableComponent(CK_FunctionPointer, - reinterpret_cast<uintptr_t>(MD)); - } - - static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { - return VTableComponent(CK_CompleteDtorPointer, - reinterpret_cast<uintptr_t>(DD)); - } - - static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { - return VTableComponent(CK_DeletingDtorPointer, - reinterpret_cast<uintptr_t>(DD)); - } - - static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { - assert(!isa<CXXDestructorDecl>(MD) && - "Don't use MakeUnusedFunction with destructors!"); - return VTableComponent(CK_UnusedFunctionPointer, - reinterpret_cast<uintptr_t>(MD)); - } - - static VTableComponent getFromOpaqueInteger(uint64_t I) { - return VTableComponent(I); - } - - /// getKind - Get the kind of this vtable component. - Kind getKind() const { - return (Kind)(Value & 0x7); - } - - CharUnits getVCallOffset() const { - assert(getKind() == CK_VCallOffset && "Invalid component kind!"); - - return getOffset(); - } - - CharUnits getVBaseOffset() const { - assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); - - return getOffset(); - } - - CharUnits getOffsetToTop() const { - assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); - - return getOffset(); - } - - const CXXRecordDecl *getRTTIDecl() const { - assert(getKind() == CK_RTTI && "Invalid component kind!"); - - return reinterpret_cast<CXXRecordDecl *>(getPointer()); - } - - const CXXMethodDecl *getFunctionDecl() const { - assert(getKind() == CK_FunctionPointer); - - return reinterpret_cast<CXXMethodDecl *>(getPointer()); - } - - const CXXDestructorDecl *getDestructorDecl() const { - assert((getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); - - return reinterpret_cast<CXXDestructorDecl *>(getPointer()); - } - - const CXXMethodDecl *getUnusedFunctionDecl() const { - assert(getKind() == CK_UnusedFunctionPointer); - - return reinterpret_cast<CXXMethodDecl *>(getPointer()); - } - -private: - VTableComponent(Kind ComponentKind, CharUnits Offset) { - assert((ComponentKind == CK_VCallOffset || - ComponentKind == CK_VBaseOffset || - ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); - assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!"); - - Value = ((Offset.getQuantity() << 3) | ComponentKind); - } - - VTableComponent(Kind ComponentKind, uintptr_t Ptr) { - assert((ComponentKind == CK_RTTI || - ComponentKind == CK_FunctionPointer || - ComponentKind == CK_CompleteDtorPointer || - ComponentKind == CK_DeletingDtorPointer || - ComponentKind == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); - - Value = Ptr | ComponentKind; - } - - CharUnits getOffset() const { - assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || - getKind() == CK_OffsetToTop) && "Invalid component kind!"); - - return CharUnits::fromQuantity(Value >> 3); - } - - uintptr_t getPointer() const { - assert((getKind() == CK_RTTI || - getKind() == CK_FunctionPointer || - getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer || - getKind() == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - return static_cast<uintptr_t>(Value & ~7ULL); - } - - explicit VTableComponent(uint64_t Value) - : Value(Value) { } - - /// The kind is stored in the lower 3 bits of the value. For offsets, we - /// make use of the facts that classes can't be larger than 2^55 bytes, - /// so we store the offset in the lower part of the 61 bytes that remain. - /// (The reason that we're not simply using a PointerIntPair here is that we - /// need the offsets to be 64-bit, even when on a 32-bit machine). - int64_t Value; -}; - -/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. -struct VCallOffsetMap { - - typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy; - - /// Offsets - Keeps track of methods and their offsets. - // FIXME: This should be a real map and not a vector. - llvm::SmallVector<MethodAndOffsetPairTy, 16> Offsets; - - /// MethodsCanShareVCallOffset - Returns whether two virtual member functions - /// can share the same vcall offset. - static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS); - -public: - /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the - /// add was successful, or false if there was already a member function with - /// the same signature in the map. - bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset); - - /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the - /// vtable address point) for the given virtual member function. - CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD); - - // empty - Return whether the offset map is empty or not. - bool empty() const { return Offsets.empty(); } -}; - -static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - ASTContext &C = LHS->getASTContext(); // TODO: thread this down - CanQual<FunctionProtoType> - LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(), - RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>(); - - // Fast-path matches in the canonical types. - if (LT == RT) return true; - - // Force the signatures to match. We can't rely on the overrides - // list here because there isn't necessarily an inheritance - // relationship between the two methods. - if (LT.getQualifiers() != RT.getQualifiers() || - LT->getNumArgs() != RT->getNumArgs()) - return false; - for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) - if (LT->getArgType(I) != RT->getArgType(I)) - return false; - return true; -} - -bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - assert(LHS->isVirtual() && "LHS must be virtual!"); - assert(RHS->isVirtual() && "LHS must be virtual!"); - - // A destructor can share a vcall offset with another destructor. - if (isa<CXXDestructorDecl>(LHS)) - return isa<CXXDestructorDecl>(RHS); - - // FIXME: We need to check more things here. - - // The methods must have the same name. - DeclarationName LHSName = LHS->getDeclName(); - DeclarationName RHSName = RHS->getDeclName(); - if (LHSName != RHSName) - return false; - - // And the same signatures. - return HasSameVirtualSignature(LHS, RHS); -} - -bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, - CharUnits OffsetOffset) { - // Check if we can reuse an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return false; - } - - // Add the offset. - Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); - return true; -} - -CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { - // Look for an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return Offsets[I].second; - } - - assert(false && "Should always find a vcall offset offset!"); - return CharUnits::Zero(); -} - -/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. -class VCallAndVBaseOffsetBuilder { -public: - typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> - VBaseOffsetOffsetsMapTy; - -private: - /// MostDerivedClass - The most derived class for which we're building vcall - /// and vbase offsets. - const CXXRecordDecl *MostDerivedClass; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// Components - vcall and vbase offset components - typedef llvm::SmallVector<VTableComponent, 64> VTableComponentVectorTy; - VTableComponentVectorTy Components; - - /// VisitedVirtualBases - Visited virtual bases. - llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; - - /// VCallOffsets - Keeps track of vcall offsets. - VCallOffsetMap VCallOffsets; - - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, - /// relative to the address point. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// FinalOverriders - The final overriders of the most derived class. - /// (Can be null when we're not building a vtable of the most derived class). - const FinalOverriders *Overriders; - - /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the - /// given base subobject. - void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - CharUnits RealBaseOffset); - - /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset); - - /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *Base, - CharUnits OffsetInLayoutClass); - - /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in - /// chars, relative to the vtable address point. - CharUnits getCurrentOffsetOffset() const; - -public: - VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, - const CXXRecordDecl *LayoutClass, - const FinalOverriders *Overriders, - BaseSubobject Base, bool BaseIsVirtual, - CharUnits OffsetInLayoutClass) - : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { - - // Add vcall and vbase offsets. - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); - } - - /// Methods for iterating over the components. - typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; - const_iterator components_begin() const { return Components.rbegin(); } - const_iterator components_end() const { return Components.rend(); } - - const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } - const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { - return VBaseOffsetOffsets; - } -}; - -void -VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, - bool BaseIsVirtual, - CharUnits RealBaseOffset) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); - - // Itanium C++ ABI 2.5.2: - // ..in classes sharing a virtual table with a primary base class, the vcall - // and vbase offsets added by the derived class all come before the vcall - // and vbase offsets required by the base class, so that the latter may be - // laid out as required by the base class without regard to additions from - // the derived class(es). - - // (Since we're emitting the vcall and vbase offsets in reverse order, we'll - // emit them for the primary base first). - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); - - CharUnits PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (PrimaryBaseIsVirtual) { - assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallAndVBaseOffsets( - BaseSubobject(PrimaryBase,PrimaryBaseOffset), - PrimaryBaseIsVirtual, RealBaseOffset); - } - - AddVBaseOffsets(Base.getBase(), RealBaseOffset); - - // We only want to add vcall offsets for virtual bases. - if (BaseIsVirtual) - AddVCallOffsets(Base, RealBaseOffset); -} - -CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { - // OffsetIndex is the index of this vcall or vbase offset, relative to the - // vtable address point. (We subtract 3 to account for the information just - // above the address point, the RTTI info, the offset to top, and the - // vcall offset itself). - int64_t OffsetIndex = -(int64_t)(3 + Components.size()); - - CharUnits PointerWidth = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); - CharUnits OffsetOffset = PointerWidth * OffsetIndex; - return OffsetOffset; -} - -void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, - CharUnits VBaseOffset) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - // Handle the primary base first. - // We only want to add vcall offsets if the base is non-virtual; a virtual - // primary base will have its vcall and vbase offsets emitted already. - if (PrimaryBase && !Layout.isPrimaryBaseVirtual()) { - // Get the base offset of the primary base. - assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), - VBaseOffset); - } - - // Add the vcall offsets. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - CharUnits OffsetOffset = getCurrentOffsetOffset(); - - // Don't add a vcall offset if we already have one for this member function - // signature. - if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) - continue; - - CharUnits Offset = CharUnits::Zero(); - - if (Overriders) { - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders->getOverrider(MD, Base.getBaseOffset()); - - /// The vcall offset is the offset from the virtual base to the object - /// where the function was overridden. - Offset = Overrider.Offset - VBaseOffset; - } - - Components.push_back( - VTableComponent::MakeVCallOffset(Offset)); - } - - // And iterate over all non-virtual bases (ignoring the primary base). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - if (BaseDecl == PrimaryBase) - continue; - - // Get the base offset of this base. - CharUnits BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), - VBaseOffset); - } -} - -void -VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - CharUnits OffsetInLayoutClass) { - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Add vbase offsets. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Check if this is a virtual base that we haven't visited before. - if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { - CharUnits Offset = - LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; - - // Add the vbase offset offset. - assert(!VBaseOffsetOffsets.count(BaseDecl) && - "vbase offset offset already exists!"); - - CharUnits VBaseOffsetOffset = getCurrentOffsetOffset(); - VBaseOffsetOffsets.insert( - std::make_pair(BaseDecl, VBaseOffsetOffset)); - - Components.push_back( - VTableComponent::MakeVBaseOffset(Offset)); - } - - // Check the base class looking for more vbase offsets. - AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); - } -} - -/// VTableBuilder - Class for building vtable layout information. -class VTableBuilder { -public: - /// PrimaryBasesSetVectorTy - A set vector of direct and indirect - /// primary bases. - typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> - PrimaryBasesSetVectorTy; - - typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> - VBaseOffsetOffsetsMapTy; - - typedef llvm::DenseMap<BaseSubobject, uint64_t> - AddressPointsMapTy; - -private: - /// VTables - Global vtable information. - CodeGenVTables &VTables; - - /// MostDerivedClass - The most derived class for which we're building this - /// vtable. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building a construction vtable, this - /// holds the offset from the layout class to the most derived class. - const CharUnits MostDerivedClassOffset; - - /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual - /// base. (This only makes sense when building a construction vtable). - bool MostDerivedClassIsVirtual; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// FinalOverriders - The final overriders of the most derived class. - const FinalOverriders Overriders; - - /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual - /// bases in this vtable. - llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for - /// the most derived class. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// Components - The components of the vtable being built. - llvm::SmallVector<VTableComponent, 64> Components; - - /// AddressPoints - Address points for the vtable being built. - AddressPointsMapTy AddressPoints; - - /// MethodInfo - Contains information about a method in a vtable. - /// (Used for computing 'this' pointer adjustment thunks. - struct MethodInfo { - /// BaseOffset - The base offset of this method. - const CharUnits BaseOffset; - - /// BaseOffsetInLayoutClass - The base offset in the layout class of this - /// method. - const CharUnits BaseOffsetInLayoutClass; - - /// VTableIndex - The index in the vtable that this method has. - /// (For destructors, this is the index of the complete destructor). - const uint64_t VTableIndex; - - MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass, - uint64_t VTableIndex) - : BaseOffset(BaseOffset), - BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), - VTableIndex(VTableIndex) { } - - MethodInfo() - : BaseOffset(CharUnits::Zero()), - BaseOffsetInLayoutClass(CharUnits::Zero()), - VTableIndex(0) { } - }; - - typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; - - /// MethodInfoMap - The information for all methods in the vtable we're - /// currently building. - MethodInfoMapTy MethodInfoMap; - - typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; - - /// VTableThunks - The thunks by vtable index in the vtable currently being - /// built. - VTableThunksMapTy VTableThunks; - - typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; - typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; - - /// Thunks - A map that contains all the thunks needed for all methods in the - /// most derived class for which the vtable is currently being built. - ThunksMapTy Thunks; - - /// AddThunk - Add a thunk for the given method. - void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); - - /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the - /// part of the vtable we're currently building. - void ComputeThisAdjustments(); - - typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - - /// PrimaryVirtualBases - All known virtual bases who are a primary base of - /// some other base. - VisitedVirtualBasesSetTy PrimaryVirtualBases; - - /// ComputeReturnAdjustment - Compute the return adjustment given a return - /// adjustment base offset. - ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); - - /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting - /// the 'this' pointer from the base subobject to the derived subobject. - BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const; - - /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the - /// given virtual member function, its offset in the layout class and its - /// final overrider. - ThisAdjustment - ComputeThisAdjustment(const CXXMethodDecl *MD, - CharUnits BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider); - - /// AddMethod - Add a single virtual member function to the vtable - /// components vector. - void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); - - /// IsOverriderUsed - Returns whether the overrider will ever be used in this - /// part of the vtable. - /// - /// Itanium C++ ABI 2.5.2: - /// - /// struct A { virtual void f(); }; - /// struct B : virtual public A { int i; }; - /// struct C : virtual public A { int j; }; - /// struct D : public B, public C {}; - /// - /// When B and C are declared, A is a primary base in each case, so although - /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this - /// adjustment is required and no thunk is generated. However, inside D - /// objects, A is no longer a primary base of C, so if we allowed calls to - /// C::f() to use the copy of A's vtable in the C subobject, we would need - /// to adjust this from C* to B::A*, which would require a third-party - /// thunk. Since we require that a call to C::f() first convert to A*, - /// C-in-D's copy of A's vtable is never referenced, so this is not - /// necessary. - bool IsOverriderUsed(const CXXMethodDecl *Overrider, - CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass) const; - - - /// AddMethods - Add the methods of this base subobject and all its - /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases); - - // LayoutVTable - Layout the vtable for the given base class, including its - // secondary vtables and any vtables for virtual bases. - void LayoutVTable(); - - /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the - /// given base subobject, as well as all its secondary vtables. - /// - /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - /// - /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual - /// in the layout class. - void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - bool BaseIsVirtualInLayoutClass, - CharUnits OffsetInLayoutClass); - - /// LayoutSecondaryVTables - Layout the secondary vtables for the given base - /// subobject. - /// - /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, - CharUnits OffsetInLayoutClass); - - /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this - /// class hierarchy. - void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - CharUnits OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases); - - /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the - /// given base (excluding any primary bases). - void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases); - - /// isBuildingConstructionVTable - Return whether this vtable builder is - /// building a construction vtable. - bool isBuildingConstructorVTable() const { - return MostDerivedClass != LayoutClass; - } - -public: - VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, - CharUnits MostDerivedClassOffset, - bool MostDerivedClassIsVirtual, const - CXXRecordDecl *LayoutClass) - : VTables(VTables), MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), - MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), - LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), - Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { - - LayoutVTable(); - } - - ThunksMapTy::const_iterator thunks_begin() const { - return Thunks.begin(); - } - - ThunksMapTy::const_iterator thunks_end() const { - return Thunks.end(); - } - - const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { - return VBaseOffsetOffsets; - } - - /// getNumVTableComponents - Return the number of components in the vtable - /// currently built. - uint64_t getNumVTableComponents() const { - return Components.size(); - } - - const uint64_t *vtable_components_data_begin() const { - return reinterpret_cast<const uint64_t *>(Components.begin()); - } - - const uint64_t *vtable_components_data_end() const { - return reinterpret_cast<const uint64_t *>(Components.end()); - } - - AddressPointsMapTy::const_iterator address_points_begin() const { - return AddressPoints.begin(); - } - - AddressPointsMapTy::const_iterator address_points_end() const { - return AddressPoints.end(); - } - - VTableThunksMapTy::const_iterator vtable_thunks_begin() const { - return VTableThunks.begin(); - } - - VTableThunksMapTy::const_iterator vtable_thunks_end() const { - return VTableThunks.end(); - } - - /// dumpLayout - Dump the vtable layout. - void dumpLayout(llvm::raw_ostream&); -}; - -void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { - assert(!isBuildingConstructorVTable() && - "Can't add thunks for construction vtable"); - - llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; - - // Check if we have this thunk already. - if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != - ThunksVector.end()) - return; - - ThunksVector.push_back(Thunk); -} - -typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; - -/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all -/// the overridden methods that the function decl overrides. -static void -ComputeAllOverriddenMethods(const CXXMethodDecl *MD, - OverriddenMethodsSetTy& OverriddenMethods) { - assert(MD->isVirtual() && "Method is not virtual!"); - - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - - OverriddenMethods.insert(OverriddenMD); - - ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); - } -} - -void VTableBuilder::ComputeThisAdjustments() { - // Now go through the method info map and see if any of the methods need - // 'this' pointer adjustments. - for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), - E = MethodInfoMap.end(); I != E; ++I) { - const CXXMethodDecl *MD = I->first; - const MethodInfo &MethodInfo = I->second; - - // Ignore adjustments for unused function pointers. - uint64_t VTableIndex = MethodInfo.VTableIndex; - if (Components[VTableIndex].getKind() == - VTableComponent::CK_UnusedFunctionPointer) - continue; - - // Get the final overrider for this method. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(MD, MethodInfo.BaseOffset); - - // Check if we need an adjustment at all. - if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { - // When a return thunk is needed by a derived class that overrides a - // virtual base, gcc uses a virtual 'this' adjustment as well. - // While the thunk itself might be needed by vtables in subclasses or - // in construction vtables, there doesn't seem to be a reason for using - // the thunk in this vtable. Still, we do so to match gcc. - if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) - continue; - } - - ThisAdjustment ThisAdjustment = - ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); - - if (ThisAdjustment.isEmpty()) - continue; - - // Add it. - VTableThunks[VTableIndex].This = ThisAdjustment; - - if (isa<CXXDestructorDecl>(MD)) { - // Add an adjustment for the deleting destructor as well. - VTableThunks[VTableIndex + 1].This = ThisAdjustment; - } - } - - /// Clear the method info map. - MethodInfoMap.clear(); - - if (isBuildingConstructorVTable()) { - // We don't need to store thunk information for construction vtables. - return; - } - - for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(), - E = VTableThunks.end(); I != E; ++I) { - const VTableComponent &Component = Components[I->first]; - const ThunkInfo &Thunk = I->second; - const CXXMethodDecl *MD; - - switch (Component.getKind()) { - default: - llvm_unreachable("Unexpected vtable component kind!"); - case VTableComponent::CK_FunctionPointer: - MD = Component.getFunctionDecl(); - break; - case VTableComponent::CK_CompleteDtorPointer: - MD = Component.getDestructorDecl(); - break; - case VTableComponent::CK_DeletingDtorPointer: - // We've already added the thunk when we saw the complete dtor pointer. - continue; - } - - if (MD->getParent() == MostDerivedClass) - AddThunk(MD, Thunk); - } -} - -ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { - ReturnAdjustment Adjustment; - - if (!Offset.isEmpty()) { - if (Offset.VirtualBase) { - // Get the virtual base offset offset. - if (Offset.DerivedClass == MostDerivedClass) { - // We can get the offset offset directly from our map. - Adjustment.VBaseOffsetOffset = - VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); - } else { - Adjustment.VBaseOffsetOffset = - VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, - Offset.VirtualBase).getQuantity(); - } - } - - Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); - } - - return Adjustment; -} - -BaseOffset -VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const { - const CXXRecordDecl *BaseRD = Base.getBase(); - const CXXRecordDecl *DerivedRD = Derived.getBase(); - - CXXBasePaths Paths(/*FindAmbiguities=*/true, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - - if (!const_cast<CXXRecordDecl *>(DerivedRD)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - // We have to go through all the paths, and see which one leads us to the - // right base subobject. - for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); - I != E; ++I) { - BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); - - CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset; - - if (Offset.VirtualBase) { - // If we have a virtual base class, the non-virtual offset is relative - // to the virtual base class offset. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - /// Get the virtual base offset, relative to the most derived class - /// layout. - OffsetToBaseSubobject += - LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); - } else { - // Otherwise, the non-virtual offset is relative to the derived class - // offset. - OffsetToBaseSubobject += Derived.getBaseOffset(); - } - - // Check if this path gives us the right base subobject. - if (OffsetToBaseSubobject == Base.getBaseOffset()) { - // Since we're going from the base class _to_ the derived class, we'll - // invert the non-virtual offset here. - Offset.NonVirtualOffset = -Offset.NonVirtualOffset; - return Offset; - } - } - - return BaseOffset(); -} - -ThisAdjustment -VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - CharUnits BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider) { - // Ignore adjustments for pure virtual member functions. - if (Overrider.Method->isPure()) - return ThisAdjustment(); - - BaseSubobject OverriddenBaseSubobject(MD->getParent(), - BaseOffsetInLayoutClass); - - BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), - Overrider.Offset); - - // Compute the adjustment offset. - BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, - OverriderBaseSubobject); - if (Offset.isEmpty()) - return ThisAdjustment(); - - ThisAdjustment Adjustment; - - if (Offset.VirtualBase) { - // Get the vcall offset map for this virtual base. - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; - - if (VCallOffsets.empty()) { - // We don't have vcall offsets for this virtual base, go ahead and - // build them. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, - /*FinalOverriders=*/0, - BaseSubobject(Offset.VirtualBase, - CharUnits::Zero()), - /*BaseIsVirtual=*/true, - /*OffsetInLayoutClass=*/ - CharUnits::Zero()); - - VCallOffsets = Builder.getVCallOffsets(); - } - - Adjustment.VCallOffsetOffset = - VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); - } - - // Set the non-virtual part of the adjustment. - Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); - - return Adjustment; -} - -void -VTableBuilder::AddMethod(const CXXMethodDecl *MD, - ReturnAdjustment ReturnAdjustment) { - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - assert(ReturnAdjustment.isEmpty() && - "Destructor can't have return adjustment!"); - - // Add both the complete destructor and the deleting destructor. - Components.push_back(VTableComponent::MakeCompleteDtor(DD)); - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); - } else { - // Add the return adjustment if necessary. - if (!ReturnAdjustment.isEmpty()) - VTableThunks[Components.size()].Return = ReturnAdjustment; - - // Add the function. - Components.push_back(VTableComponent::MakeFunction(MD)); - } -} - -/// OverridesIndirectMethodInBase - Return whether the given member function -/// overrides any methods in the set of given bases. -/// Unlike OverridesMethodInBase, this checks "overriders of overriders". -/// For example, if we have: -/// -/// struct A { virtual void f(); } -/// struct B : A { virtual void f(); } -/// struct C : B { virtual void f(); } -/// -/// OverridesIndirectMethodInBase will return true if given C::f as the method -/// and { A } as the set of bases. -static bool -OverridesIndirectMethodInBases(const CXXMethodDecl *MD, - VTableBuilder::PrimaryBasesSetVectorTy &Bases) { - if (Bases.count(MD->getParent())) - return true; - - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - - // Check "indirect overriders". - if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) - return true; - } - - return false; -} - -bool -VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, - CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass) const { - // If the base and the first base in the primary base chain have the same - // offsets, then this overrider will be used. - if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) - return true; - - // We know now that Base (or a direct or indirect base of it) is a primary - // base in part of the class hierarchy, but not a primary base in the most - // derived class. - - // If the overrider is the first base in the primary base chain, we know - // that the overrider will be used. - if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) - return true; - - VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - - const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; - PrimaryBases.insert(RD); - - // Now traverse the base chain, starting with the first base, until we find - // the base that is no longer a primary base. - while (true) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - break; - - if (Layout.isPrimaryBaseVirtual()) { - assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Now check if this is the primary base that is not a primary base in the - // most derived class. - if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != - FirstBaseOffsetInLayoutClass) { - // We found it, stop walking the chain. - break; - } - } else { - assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - } - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - - RD = PrimaryBase; - } - - // If the final overrider is an override of one of the primary bases, - // then we know that it will be used. - return OverridesIndirectMethodInBases(Overrider, PrimaryBases); -} - -/// FindNearestOverriddenMethod - Given a method, returns the overridden method -/// from the nearest base. Returns null if no method was found. -static const CXXMethodDecl * -FindNearestOverriddenMethod(const CXXMethodDecl *MD, - VTableBuilder::PrimaryBasesSetVectorTy &Bases) { - OverriddenMethodsSetTy OverriddenMethods; - ComputeAllOverriddenMethods(MD, OverriddenMethods); - - for (int I = Bases.size(), E = 0; I != E; --I) { - const CXXRecordDecl *PrimaryBase = Bases[I - 1]; - - // Now check the overriden methods. - for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), - E = OverriddenMethods.end(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - - // We found our overridden method. - if (OverriddenMD->getParent() == PrimaryBase) - return OverriddenMD; - } - } - - return 0; -} - -void -VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - CharUnits PrimaryBaseOffset; - CharUnits PrimaryBaseOffsetInLayoutClass; - if (Layout.isPrimaryBaseVirtual()) { - assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; - } - - AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - } - - // Now go through all virtual member functions and add them. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(MD, Base.getBaseOffset()); - - // Check if this virtual member function overrides a method in a primary - // base. If this is the case, and the return type doesn't require adjustment - // then we can just use the member function from the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) { - // Replace the method info of the overridden method with our own - // method. - assert(MethodInfoMap.count(OverriddenMD) && - "Did not find the overridden method!"); - MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; - - MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, - OverriddenMethodInfo.VTableIndex); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - - MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); - MethodInfoMap.erase(OverriddenMD); - - // If the overridden method exists in a virtual base class or a direct - // or indirect base class of a virtual base class, we need to emit a - // thunk if we ever have a class hierarchy where the base class is not - // a primary base in the complete object. - if (!isBuildingConstructorVTable() && OverriddenMD != MD) { - // Compute the this adjustment. - ThisAdjustment ThisAdjustment = - ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, - Overrider); - - if (ThisAdjustment.VCallOffsetOffset && - Overrider.Method->getParent() == MostDerivedClass) { - - // There's no return adjustment from OverriddenMD and MD, - // but that doesn't mean there isn't one between MD and - // the final overrider. - BaseOffset ReturnAdjustmentOffset = - ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD); - ReturnAdjustment ReturnAdjustment = - ComputeReturnAdjustment(ReturnAdjustmentOffset); - - // This is a virtual thunk for the most derived class, add it. - AddThunk(Overrider.Method, - ThunkInfo(ThisAdjustment, ReturnAdjustment)); - } - } - - continue; - } - } - - // Insert the method info for this method. - MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, - Components.size()); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); - - // Check if this overrider is going to be used. - const CXXMethodDecl *OverriderMD = Overrider.Method; - if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, - FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass)) { - Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); - continue; - } - - // Check if this overrider needs a return adjustment. - // We don't want to do this for pure virtual member functions. - BaseOffset ReturnAdjustmentOffset; - if (!OverriderMD->isPure()) { - ReturnAdjustmentOffset = - ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); - } - - ReturnAdjustment ReturnAdjustment = - ComputeReturnAdjustment(ReturnAdjustmentOffset); - - AddMethod(Overrider.Method, ReturnAdjustment); - } -} - -void VTableBuilder::LayoutVTable() { - LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, - CharUnits::Zero()), - /*BaseIsMorallyVirtual=*/false, - MostDerivedClassIsVirtual, - MostDerivedClassOffset); - - VisitedVirtualBasesSetTy VBases; - - // Determine the primary virtual bases. - DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, - VBases); - VBases.clear(); - - LayoutVTablesForVirtualBases(MostDerivedClass, VBases); -} - -void -VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - bool BaseIsVirtualInLayoutClass, - CharUnits OffsetInLayoutClass) { - assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); - - // Add vcall and vbase offsets for this vtable. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, - Base, BaseIsVirtualInLayoutClass, - OffsetInLayoutClass); - Components.append(Builder.components_begin(), Builder.components_end()); - - // Check if we need to add these vcall offsets. - if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; - - if (VCallOffsets.empty()) - VCallOffsets = Builder.getVCallOffsets(); - } - - // If we're laying out the most derived class we want to keep track of the - // virtual base class offset offsets. - if (Base.getBase() == MostDerivedClass) - VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - - // Add the offset to top. - CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; - Components.push_back( - VTableComponent::MakeOffsetToTop(OffsetToTop)); - - // Next, add the RTTI. - Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); - - uint64_t AddressPoint = Components.size(); - - // Now go through all virtual member functions and add them. - PrimaryBasesSetVectorTy PrimaryBases; - AddMethods(Base, OffsetInLayoutClass, - Base.getBase(), OffsetInLayoutClass, - PrimaryBases); - - // Compute 'this' pointer adjustments. - ComputeThisAdjustments(); - - // Add all address points. - const CXXRecordDecl *RD = Base.getBase(); - while (true) { - AddressPoints.insert(std::make_pair( - BaseSubobject(RD, OffsetInLayoutClass), - AddressPoint)); - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - break; - - if (Layout.isPrimaryBaseVirtual()) { - // Check if this virtual primary base is a primary base in the layout - // class. If it's not, we don't want to add it. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != - OffsetInLayoutClass) { - // We don't want to add this class (or any of its primary bases). - break; - } - } - - RD = PrimaryBase; - } - - // Layout secondary vtables. - LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); -} - -void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - CharUnits OffsetInLayoutClass) { - // Itanium C++ ABI 2.5.2: - // Following the primary virtual table of a derived class are secondary - // virtual tables for each of its proper base classes, except any primary - // base(s) with which it shares its primary virtual table. - - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - // Ignore virtual bases, we'll emit them later. - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Ignore bases that don't have a vtable. - if (!BaseDecl->isDynamicClass()) - continue; - - if (isBuildingConstructorVTable()) { - // Itanium C++ ABI 2.6.4: - // Some of the base class subobjects may not need construction virtual - // tables, which will therefore not be present in the construction - // virtual table group, even though the subobject virtual tables are - // present in the main virtual table group for the complete object. - if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) - continue; - } - - // Get the base offset of this base. - CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); - CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; - - CharUnits BaseOffsetInLayoutClass = - OffsetInLayoutClass + RelativeBaseOffset; - - // Don't emit a secondary vtable for a primary base. We might however want - // to emit secondary vtables for other bases of this base. - if (BaseDecl == PrimaryBase) { - LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), - BaseIsMorallyVirtual, BaseOffsetInLayoutClass); - continue; - } - - // Layout the primary vtable (and any secondary vtables) for this base. - LayoutPrimaryAndSecondaryVTables( - BaseSubobject(BaseDecl, BaseOffset), - BaseIsMorallyVirtual, - /*BaseIsVirtualInLayoutClass=*/false, - BaseOffsetInLayoutClass); - } -} - -void -VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - CharUnits OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Check if this base has a primary base. - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - - // Check if it's virtual. - if (Layout.isPrimaryBaseVirtual()) { - bool IsPrimaryVirtualBase = true; - - if (isBuildingConstructorVTable()) { - // Check if the base is actually a primary base in the class we use for - // layout. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - CharUnits PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - - // We know that the base is not a primary base in the layout class if - // the base offsets are different. - if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) - IsPrimaryVirtualBase = false; - } - - if (IsPrimaryVirtualBase) - PrimaryVirtualBases.insert(PrimaryBase); - } - } - - // Traverse bases, looking for more primary virtual bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - CharUnits BaseOffsetInLayoutClass; - - if (I->isVirtual()) { - if (!VBases.insert(BaseDecl)) - continue; - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffsetInLayoutClass = - OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); - } - - DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); - } -} - -void -VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases) { - // Itanium C++ ABI 2.5.2: - // Then come the virtual base virtual tables, also in inheritance graph - // order, and again excluding primary bases (which share virtual tables with - // the classes for which they are primary). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Check if this base needs a vtable. (If it's virtual, not a primary base - // of some other class, and we haven't visited it before). - if (I->isVirtual() && BaseDecl->isDynamicClass() && - !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - CharUnits BaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - CharUnits BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - - LayoutPrimaryAndSecondaryVTables( - BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsMorallyVirtual=*/true, - /*BaseIsVirtualInLayoutClass=*/true, - BaseOffsetInLayoutClass); - } - - // We only need to check the base for virtual base vtables if it actually - // has virtual bases. - if (BaseDecl->getNumVBases()) - LayoutVTablesForVirtualBases(BaseDecl, VBases); - } -} - -/// dumpLayout - Dump the vtable layout. -void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { - - if (isBuildingConstructorVTable()) { - Out << "Construction vtable for ('"; - Out << MostDerivedClass->getQualifiedNameAsString() << "', "; - Out << MostDerivedClassOffset.getQuantity() << ") in '"; - Out << LayoutClass->getQualifiedNameAsString(); - } else { - Out << "Vtable for '"; - Out << MostDerivedClass->getQualifiedNameAsString(); - } - Out << "' (" << Components.size() << " entries).\n"; - - // Iterate through the address points and insert them into a new map where - // they are keyed by the index and not the base object. - // Since an address point can be shared by multiple subobjects, we use an - // STL multimap. - std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex; - for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), - E = AddressPoints.end(); I != E; ++I) { - const BaseSubobject& Base = I->first; - uint64_t Index = I->second; - - AddressPointsByIndex.insert(std::make_pair(Index, Base)); - } - - for (unsigned I = 0, E = Components.size(); I != E; ++I) { - uint64_t Index = I; - - Out << llvm::format("%4d | ", I); - - const VTableComponent &Component = Components[I]; - - // Dump the component. - switch (Component.getKind()) { - - case VTableComponent::CK_VCallOffset: - Out << "vcall_offset (" - << Component.getVCallOffset().getQuantity() - << ")"; - break; - - case VTableComponent::CK_VBaseOffset: - Out << "vbase_offset (" - << Component.getVBaseOffset().getQuantity() - << ")"; - break; - - case VTableComponent::CK_OffsetToTop: - Out << "offset_to_top (" - << Component.getOffsetToTop().getQuantity() - << ")"; - break; - - case VTableComponent::CK_RTTI: - Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; - break; - - case VTableComponent::CK_FunctionPointer: { - const CXXMethodDecl *MD = Component.getFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << Str; - if (MD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this function pointer has a return adjustment, dump it. - if (!Thunk.Return.isEmpty()) { - Out << "\n [return adjustment: "; - Out << Thunk.Return.NonVirtual << " non-virtual"; - - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; - Out << " vbase offset offset"; - } - - Out << ']'; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VTableComponent::CK_CompleteDtorPointer: - case VTableComponent::CK_DeletingDtorPointer: { - bool IsComplete = - Component.getKind() == VTableComponent::CK_CompleteDtorPointer; - - const CXXDestructorDecl *DD = Component.getDestructorDecl(); - - Out << DD->getQualifiedNameAsString(); - if (IsComplete) - Out << "() [complete]"; - else - Out << "() [deleting]"; - - if (DD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this destructor has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VTableComponent::CK_UnusedFunctionPointer: { - const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << "[unused] " << Str; - if (MD->isPure()) - Out << " [pure]"; - } - - } - - Out << '\n'; - - // Dump the next address point. - uint64_t NextIndex = Index + 1; - if (AddressPointsByIndex.count(NextIndex)) { - if (AddressPointsByIndex.count(NextIndex) == 1) { - const BaseSubobject &Base = - AddressPointsByIndex.find(NextIndex)->second; - - Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); - Out << ", " << Base.getBaseOffset().getQuantity(); - Out << ") vtable address --\n"; - } else { - CharUnits BaseOffset = - AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); - - // We store the class names in a set to get a stable order. - std::set<std::string> ClassNames; - for (std::multimap<uint64_t, BaseSubobject>::const_iterator I = - AddressPointsByIndex.lower_bound(NextIndex), E = - AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { - assert(I->second.getBaseOffset() == BaseOffset && - "Invalid base offset!"); - const CXXRecordDecl *RD = I->second.getBase(); - ClassNames.insert(RD->getQualifiedNameAsString()); - } - - for (std::set<std::string>::const_iterator I = ClassNames.begin(), - E = ClassNames.end(); I != E; ++I) { - Out << " -- (" << *I; - Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n"; - } - } - } - } - - Out << '\n'; - - if (isBuildingConstructorVTable()) - return; - - if (MostDerivedClass->getNumVBases()) { - // We store the virtual base class names and their offsets in a map to get - // a stable order. - - std::map<std::string, CharUnits> ClassNamesAndOffsets; - for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), - E = VBaseOffsetOffsets.end(); I != E; ++I) { - std::string ClassName = I->first->getQualifiedNameAsString(); - CharUnits OffsetOffset = I->second; - ClassNamesAndOffsets.insert( - std::make_pair(ClassName, OffsetOffset)); - } - - Out << "Virtual base offset offsets for '"; - Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; - Out << ClassNamesAndOffsets.size(); - Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; - - for (std::map<std::string, CharUnits>::const_iterator I = - ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); - I != E; ++I) - Out << " " << I->first << " | " << I->second.getQuantity() << '\n'; - - Out << "\n"; - } - - if (!Thunks.empty()) { - // We store the method names in a map to get a stable order. - std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; - - for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); - I != E; ++I) { - const CXXMethodDecl *MD = I->first; - std::string MethodName = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - - MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); - } - - for (std::map<std::string, const CXXMethodDecl *>::const_iterator I = - MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); - I != E; ++I) { - const std::string &MethodName = I->first; - const CXXMethodDecl *MD = I->second; - - ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); - - Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); - Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; - - for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { - const ThunkInfo &Thunk = ThunksVector[I]; - - Out << llvm::format("%4d | ", I); - - // If this function pointer has a return pointer adjustment, dump it. - if (!Thunk.Return.isEmpty()) { - Out << "return adjustment: " << Thunk.This.NonVirtual; - Out << " non-virtual"; - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; - Out << " vbase offset offset"; - } - - if (!Thunk.This.isEmpty()) - Out << "\n "; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - } - - Out << '\n'; - } - - Out << '\n'; - } - } - - // Compute the vtable indices for all the member functions. - // Store them in a map keyed by the index so we'll get a sorted table. - std::map<uint64_t, std::string> IndicesMap; - - for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(), - e = MostDerivedClass->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - - // We only want virtual member functions. - if (!MD->isVirtual()) - continue; - - std::string MethodName = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] = - MethodName + " [complete]"; - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] = - MethodName + " [deleting]"; - } else { - IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; - } - } - - // Print the vtable indices for all the member functions. - if (!IndicesMap.empty()) { - Out << "VTable indices for '"; - Out << MostDerivedClass->getQualifiedNameAsString(); - Out << "' (" << IndicesMap.size() << " entries).\n"; - - for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(), - E = IndicesMap.end(); I != E; ++I) { - uint64_t VTableIndex = I->first; - const std::string &MethodName = I->second; - - Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n'; - } - } - - Out << '\n'; -} - -} - -static void -CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, - VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - return; - - CollectPrimaryBases(PrimaryBase, Context, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); -} - -void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { - - // Itanium C++ ABI 2.5.2: - // The order of the virtual function pointers in a virtual table is the - // order of declaration of the corresponding member functions in the class. - // - // There is an entry for any virtual function declared in a class, - // whether it is a new function or overrides a base class function, - // unless it overrides a function from the primary base, and conversion - // between their return types does not require an adjustment. - - int64_t CurrentIndex = 0; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (PrimaryBase) { - assert(PrimaryBase->isDefinition() && - "Should have the definition decl of the primary base!"); - - // Since the record decl shares its vtable pointer with the primary base - // we need to start counting at the end of the primary base's vtable. - CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); - } - - // Collect all the primary bases, so we can check whether methods override - // a method from the base. - VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - CollectPrimaryBases(RD, CGM.getContext(), PrimaryBases); - - const CXXDestructorDecl *ImplicitVirtualDtor = 0; - - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - - // We only want virtual methods. - if (!MD->isVirtual()) - continue; - - // Check if this method overrides a method in the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, - OverriddenMD).isEmpty()) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast<CXXDestructorDecl>(OverriddenMD); - - // Add both the complete and deleting entries. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } else { - MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); - } - - // We don't need to add an entry for this method. - continue; - } - } - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - if (MD->isImplicit()) { - assert(!ImplicitVirtualDtor && - "Did already see an implicit virtual dtor!"); - ImplicitVirtualDtor = DD; - continue; - } - - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } else { - // Add the entry. - MethodVTableIndices[MD] = CurrentIndex++; - } - } - - if (ImplicitVirtualDtor) { - // Itanium C++ ABI 2.5.2: - // If a class has an implicitly-defined virtual destructor, - // its entries come after the declared virtual function pointers. - - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = - CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = - CurrentIndex++; - } - - NumVirtualFunctionPointers[RD] = CurrentIndex; -} +CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) + : CGM(CGM), VTContext(CGM.getContext()) { } bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) { assert(RD->isDynamicClass() && "Non dynamic classes have no VTable."); @@ -2449,75 +58,6 @@ bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) { return KeyFunction->hasBody(); } -uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { - llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = - NumVirtualFunctionPointers.find(RD); - if (I != NumVirtualFunctionPointers.end()) - return I->second; - - ComputeMethodVTableIndices(RD); - - I = NumVirtualFunctionPointers.find(RD); - assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); - return I->second; -} - -uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) { - MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); - if (I != MethodVTableIndices.end()) - return I->second; - - const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - - ComputeMethodVTableIndices(RD); - - I = MethodVTableIndices.find(GD); - assert(I != MethodVTableIndices.end() && "Did not find index!"); - return I->second; -} - -CharUnits -CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { - ClassPairTy ClassPair(RD, VBase); - - VirtualBaseClassOffsetOffsetsMapTy::iterator I = - VirtualBaseClassOffsetOffsets.find(ClassPair); - if (I != VirtualBaseClassOffsetOffsets.end()) - return I->second; - - VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, - BaseSubobject(RD, CharUnits::Zero()), - /*BaseIsVirtual=*/false, - /*OffsetInLayoutClass=*/CharUnits::Zero()); - - for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = - Builder.getVBaseOffsetOffsets().begin(), - E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { - // Insert all types. - ClassPairTy ClassPair(RD, I->first); - - VirtualBaseClassOffsetOffsets.insert( - std::make_pair(ClassPair, I->second)); - } - - I = VirtualBaseClassOffsetOffsets.find(ClassPair); - assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); - - return I->second; -} - -uint64_t -CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { - assert(AddressPoints.count(std::make_pair(RD, Base)) && - "Did not find address point!"); - - uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); - assert(AddressPoint && "Address point must not be zero!"); - - return AddressPoint; -} - llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); @@ -2532,7 +72,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Out); Out.flush(); - const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); + llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true); } @@ -2543,7 +83,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, if (!NonVirtualAdjustment && !VirtualAdjustment) return Ptr; - const llvm::Type *Int8PtrTy = + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); @@ -2554,7 +94,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, } if (VirtualAdjustment) { - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); // Do the virtual adjustment. @@ -2704,7 +244,7 @@ void CodeGenFunction::GenerateVarArgsThunk( QualType ResultType = FPT->getResultType(); // Get the original function - const llvm::Type *Ty = + llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true); llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); llvm::Function *BaseFn = cast<llvm::Function>(Callee); @@ -2811,7 +351,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, } // Get our callee. - const llvm::Type *Ty = + llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD), FPT->isVariadic()); llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); @@ -2881,7 +421,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, "Shouldn't replace non-declaration"); // Remove the name from the old thunk function and get a new thunk. - OldThunkFn->setName(llvm::StringRef()); + OldThunkFn->setName(StringRef()); Entry = CGM.GetAddrOfThunk(GD, Thunk); // If needed, replace the old thunk with a bitcast. @@ -2953,122 +493,27 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) return; - const CXXRecordDecl *RD = MD->getParent(); - - // Compute VTable related info for this class. - ComputeVTableRelatedInformation(RD, false); - - ThunksMapTy::const_iterator I = Thunks.find(MD); - if (I == Thunks.end()) { - // We did not find a thunk for this method. + const VTableContext::ThunkInfoVectorTy *ThunkInfoVector = + VTContext.getThunkInfo(MD); + if (!ThunkInfoVector) return; - } - const ThunkInfoVectorTy &ThunkInfoVector = I->second; - for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I) - EmitThunk(GD, ThunkInfoVector[I], /*UseAvailableExternallyLinkage=*/false); -} - -void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD, - bool RequireVTable) { - VTableLayoutData &Entry = VTableLayoutMap[RD]; - - // We may need to generate a definition for this vtable. - if (RequireVTable && !Entry.getInt()) { - if (ShouldEmitVTableInThisTU(RD)) - CGM.DeferredVTables.push_back(RD); - - Entry.setInt(true); - } - - // Check if we've computed this information before. - if (Entry.getPointer()) - return; - - VTableBuilder Builder(*this, RD, CharUnits::Zero(), - /*MostDerivedClassIsVirtual=*/0, RD); - - // Add the VTable layout. - uint64_t NumVTableComponents = Builder.getNumVTableComponents(); - // -fapple-kext adds an extra entry at end of vtbl. - bool IsAppleKext = CGM.getContext().getLangOptions().AppleKext; - if (IsAppleKext) - NumVTableComponents += 1; - - uint64_t *LayoutData = new uint64_t[NumVTableComponents + 1]; - if (IsAppleKext) - LayoutData[NumVTableComponents] = 0; - Entry.setPointer(LayoutData); - - // Store the number of components. - LayoutData[0] = NumVTableComponents; - - // Store the components. - std::copy(Builder.vtable_components_data_begin(), - Builder.vtable_components_data_end(), - &LayoutData[1]); - - // Add the known thunks. - Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); - - // Add the thunks needed in this vtable. - assert(!VTableThunksMap.count(RD) && - "Thunks already exists for this vtable!"); - - VTableThunksTy &VTableThunks = VTableThunksMap[RD]; - VTableThunks.append(Builder.vtable_thunks_begin(), - Builder.vtable_thunks_end()); - - // Sort them. - std::sort(VTableThunks.begin(), VTableThunks.end()); - - // Add the address points. - for (VTableBuilder::AddressPointsMapTy::const_iterator I = - Builder.address_points_begin(), E = Builder.address_points_end(); - I != E; ++I) { - - uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)]; - - // Check if we already have the address points for this base. - assert(!AddressPoint && "Address point already exists for this base!"); - - AddressPoint = I->second; - } - - // If we don't have the vbase information for this class, insert it. - // getVirtualBaseOffsetOffset will compute it separately without computing - // the rest of the vtable related information. - if (!RD->getNumVBases()) - return; - - const RecordType *VBaseRT = - RD->vbases_begin()->getType()->getAs<RecordType>(); - const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl()); - - if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) - return; - - for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = - Builder.getVBaseOffsetOffsets().begin(), - E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { - // Insert all types. - ClassPairTy ClassPair(RD, I->first); - - VirtualBaseClassOffsetOffsets.insert( - std::make_pair(ClassPair, I->second)); - } + for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I) + EmitThunk(GD, (*ThunkInfoVector)[I], + /*UseAvailableExternallyLinkage=*/false); } llvm::Constant * CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, - const uint64_t *Components, + const VTableComponent *Components, unsigned NumComponents, - const VTableThunksTy &VTableThunks) { - llvm::SmallVector<llvm::Constant *, 64> Inits; + const VTableLayout::VTableThunkTy *VTableThunks, + unsigned NumVTableThunks) { + SmallVector<llvm::Constant *, 64> Inits; - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - const llvm::Type *PtrDiffTy = + llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); QualType ClassType = CGM.getContext().getTagDeclType(RD); @@ -3079,8 +524,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, llvm::Constant* PureVirtualFn = 0; for (unsigned I = 0; I != NumComponents; ++I) { - VTableComponent Component = - VTableComponent::getFromOpaqueInteger(Components[I]); + VTableComponent Component = Components[I]; llvm::Constant *Init = 0; @@ -3126,7 +570,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { // We have a pure virtual member function. if (!PureVirtualFn) { - const llvm::FunctionType *Ty = + llvm::FunctionType *Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), /*isVarArg=*/false); PureVirtualFn = @@ -3138,7 +582,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, Init = PureVirtualFn; } else { // Check if we should use a thunk. - if (NextVTableThunkIndex < VTableThunks.size() && + if (NextVTableThunkIndex < NumVTableThunks && VTableThunks[NextVTableThunkIndex].first == I) { const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second; @@ -3147,7 +591,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, NextVTableThunkIndex++; } else { - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); + llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); Init = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); } @@ -3170,46 +614,45 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, } llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { + llvm::GlobalVariable *&VTable = VTables[RD]; + if (VTable) + return VTable; + + // We may need to generate a definition for this vtable. + if (ShouldEmitVTableInThisTU(RD)) + CGM.DeferredVTables.push_back(RD); + llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); - ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD)); + llvm::ArrayType::get(Int8PtrTy, + VTContext.getVTableLayout(RD).getNumVTableComponents()); - llvm::GlobalVariable *GV = + VTable = CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, llvm::GlobalValue::ExternalLinkage); - GV->setUnnamedAddr(true); - return GV; + VTable->setUnnamedAddr(true); + return VTable; } void CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { - // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVTableLayouts) { - VTableBuilder Builder(*this, RD, CharUnits::Zero(), - /*MostDerivedClassIsVirtual=*/0, RD); - - Builder.dumpLayout(llvm::errs()); - } + const VTableLayout &VTLayout = VTContext.getVTableLayout(RD); - assert(VTableThunksMap.count(RD) && - "No thunk status for this record decl!"); - - const VTableThunksTy& Thunks = VTableThunksMap[RD]; - // Create and set the initializer. llvm::Constant *Init = - CreateVTableInitializer(RD, getVTableComponentsData(RD), - getNumVTableComponents(RD), Thunks); + CreateVTableInitializer(RD, + VTLayout.vtable_component_begin(), + VTLayout.getNumVTableComponents(), + VTLayout.vtable_thunk_begin(), + VTLayout.getNumVTableThunks()); VTable->setInitializer(Init); // Set the correct linkage. @@ -3225,17 +668,13 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, bool BaseIsVirtual, llvm::GlobalVariable::LinkageTypes Linkage, VTableAddressPointsMapTy& AddressPoints) { - VTableBuilder Builder(*this, Base.getBase(), - Base.getBaseOffset(), - /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); - - // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVTableLayouts) - Builder.dumpLayout(llvm::errs()); + llvm::OwningPtr<VTableLayout> VTLayout( + VTContext.createConstructionVTableLayout(Base.getBase(), + Base.getBaseOffset(), + BaseIsVirtual, RD)); // Add the address points. - AddressPoints.insert(Builder.address_points_begin(), - Builder.address_points_end()); + AddressPoints = VTLayout->getAddressPoints(); // Get the mangled construction vtable name. llvm::SmallString<256> OutName; @@ -3244,11 +683,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(), Out); Out.flush(); - llvm::StringRef Name = OutName.str(); + StringRef Name = OutName.str(); - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents()); + llvm::ArrayType::get(Int8PtrTy, VTLayout->getNumVTableComponents()); // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = @@ -3258,19 +697,13 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // V-tables are always unnamed_addr. VTable->setUnnamedAddr(true); - // Add the thunks. - VTableThunksTy VTableThunks; - VTableThunks.append(Builder.vtable_thunks_begin(), - Builder.vtable_thunks_end()); - - // Sort them. - std::sort(VTableThunks.begin(), VTableThunks.end()); - // Create and set the initializer. llvm::Constant *Init = CreateVTableInitializer(Base.getBase(), - Builder.vtable_components_data_begin(), - Builder.getNumVTableComponents(), VTableThunks); + VTLayout->vtable_component_begin(), + VTLayout->getNumVTableComponents(), + VTLayout->vtable_thunk_begin(), + VTLayout->getNumVTableThunks()); VTable->setInitializer(Init); return VTable; @@ -3279,13 +712,10 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, void CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { - llvm::GlobalVariable *&VTable = VTables[RD]; - if (VTable) { - assert(VTable->getInitializer() && "VTable doesn't have a definition!"); + llvm::GlobalVariable *VTable = GetAddrOfVTable(RD); + if (VTable->hasInitializer()) return; - } - VTable = GetAddrOfVTable(RD); EmitVTableDefinition(VTable, Linkage, RD); if (RD->getNumVBases()) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h index eff6e56..828330e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h @@ -17,8 +17,10 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/GlobalVariable.h" #include "clang/Basic/ABI.h" +#include "clang/AST/BaseSubobject.h" #include "clang/AST/CharUnits.h" #include "clang/AST/GlobalDecl.h" +#include "clang/AST/VTableBuilder.h" namespace clang { class CXXRecordDecl; @@ -26,145 +28,18 @@ namespace clang { namespace CodeGen { class CodeGenModule; -// BaseSubobject - Uniquely identifies a direct or indirect base class. -// Stores both the base class decl and the offset from the most derived class to -// the base class. -class BaseSubobject { - /// Base - The base class declaration. - const CXXRecordDecl *Base; - - /// BaseOffset - The offset from the most derived class to the base class. - CharUnits BaseOffset; - -public: - BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset) - : Base(Base), BaseOffset(BaseOffset) { } - - /// getBase - Returns the base class declaration. - const CXXRecordDecl *getBase() const { return Base; } - - /// getBaseOffset - Returns the base class offset. - CharUnits getBaseOffset() const { return BaseOffset; } - - friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { - return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; - } -}; - -} // end namespace CodeGen -} // end namespace clang - -namespace llvm { - -template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> { - static clang::CodeGen::BaseSubobject getEmptyKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(), - clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey())); - } - - static clang::CodeGen::BaseSubobject getTombstoneKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(), - clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey())); - } - - static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { - return - DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^ - DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity()); - } - - static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, - const clang::CodeGen::BaseSubobject &RHS) { - return LHS == RHS; - } -}; - -// It's OK to treat BaseSubobject as a POD type. -template <> struct isPodLike<clang::CodeGen::BaseSubobject> { - static const bool value = true; -}; - -} - -namespace clang { -namespace CodeGen { - class CodeGenVTables { CodeGenModule &CGM; - /// MethodVTableIndices - Contains the index (relative to the vtable address - /// point) where the function pointer for a virtual function is stored. - typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; - MethodVTableIndicesTy MethodVTableIndices; - - typedef std::pair<const CXXRecordDecl *, - const CXXRecordDecl *> ClassPairTy; - - /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to - /// the address point) in chars where the offsets for virtual bases of a class - /// are stored. - typedef llvm::DenseMap<ClassPairTy, CharUnits> - VirtualBaseClassOffsetOffsetsMapTy; - VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + VTableContext VTContext; /// VTables - All the vtables which have been defined. llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables; - /// NumVirtualFunctionPointers - Contains the number of virtual function - /// pointers in the vtable for a given record decl. - llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; - - typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; - typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; - - /// Thunks - Contains all thunks that a given method decl will need. - ThunksMapTy Thunks; - - // The layout entry and a bool indicating whether we've actually emitted - // the vtable. - typedef llvm::PointerIntPair<uint64_t *, 1, bool> VTableLayoutData; - typedef llvm::DenseMap<const CXXRecordDecl *, VTableLayoutData> - VTableLayoutMapTy; - - /// VTableLayoutMap - Stores the vtable layout for all record decls. - /// The layout is stored as an array of 64-bit integers, where the first - /// integer is the number of vtable entries in the layout, and the subsequent - /// integers are the vtable components. - VTableLayoutMapTy VTableLayoutMap; - - typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy; - typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> AddressPointsMapTy; - - /// Address points - Address points for all vtables. - AddressPointsMapTy AddressPoints; - /// VTableAddressPointsMapTy - Address points for a single vtable. typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy; - typedef llvm::SmallVector<std::pair<uint64_t, ThunkInfo>, 1> - VTableThunksTy; - - typedef llvm::DenseMap<const CXXRecordDecl *, VTableThunksTy> - VTableThunksMapTy; - - /// VTableThunksMap - Contains thunks needed by vtables. - VTableThunksMapTy VTableThunksMap; - - uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const { - assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - - return VTableLayoutMap.lookup(RD).getPointer()[0]; - } - - const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const { - assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - - uint64_t *Components = VTableLayoutMap.lookup(RD).getPointer(); - return &Components[1]; - } - + typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy; typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy; /// SubVTTIndicies - Contains indices into the various sub-VTTs. @@ -177,12 +52,6 @@ class CodeGenVTables { /// indices. SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; - /// getNumVirtualFunctionPointers - Return the number of virtual function - /// pointers in the vtable for a given record decl. - uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); - - void ComputeMethodVTableIndices(const CXXRecordDecl *RD); - /// EmitThunk - Emit a single thunk. void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool UseAvailableExternallyLinkage); @@ -193,24 +62,20 @@ class CodeGenVTables { /// doesn't contain any incomplete types. void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk); - /// ComputeVTableRelatedInformation - Compute and store all vtable related - /// information (vtable layout, vbase offset offsets, thunks etc) for the - /// given record decl. - void ComputeVTableRelatedInformation(const CXXRecordDecl *RD, - bool VTableRequired); - /// CreateVTableInitializer - Create a vtable initializer for the given record /// decl. /// \param Components - The vtable components; this is really an array of /// VTableComponents. llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD, - const uint64_t *Components, + const VTableComponent *Components, unsigned NumComponents, - const VTableThunksTy &VTableThunks); + const VTableLayout::VTableThunkTy *VTableThunks, + unsigned NumVTableThunks); public: - CodeGenVTables(CodeGenModule &CGM) - : CGM(CGM) { } + CodeGenVTables(CodeGenModule &CGM); + + VTableContext &getVTableContext() { return VTContext; } /// \brief True if the VTable of this record must be emitted in the /// translation unit. @@ -230,19 +95,6 @@ public: uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, BaseSubobject Base); - /// getMethodVTableIndex - Return the index (relative to the vtable address - /// point) where the function pointer for the given virtual function is - /// stored. - uint64_t getMethodVTableIndex(GlobalDecl GD); - - /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the - /// vtable address point) where the offset of the virtual base that contains - /// the given base is stored, otherwise, if no virtual base contains the given - /// class, return 0. Base must be a virtual base class or an unambigious - /// base. - CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase); - /// getAddressPoint - Get the address point of the given subobject in the /// class decl. uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h index 4d0b841..489e600 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h @@ -337,65 +337,90 @@ class AggValueSlot { // Qualifiers Qualifiers Quals; + + /// DestructedFlag - This is set to true if some external code is + /// responsible for setting up a destructor for the slot. Otherwise + /// the code which constructs it should push the appropriate cleanup. + bool DestructedFlag : 1; + + /// ObjCGCFlag - This is set to true if writing to the memory in the + /// slot might require calling an appropriate Objective-C GC + /// barrier. The exact interaction here is unnecessarily mysterious. + bool ObjCGCFlag : 1; - // Associated flags. - bool LifetimeFlag : 1; - bool RequiresGCollection : 1; - - /// IsZeroed - This is set to true if the destination is known to be zero - /// before the assignment into it. This means that zero fields don't need to - /// be set. - bool IsZeroed : 1; + /// ZeroedFlag - This is set to true if the memory in the slot is + /// known to be zero before the assignment into it. This means that + /// zero fields don't need to be set. + bool ZeroedFlag : 1; + + /// AliasedFlag - This is set to true if the slot might be aliased + /// and it's not undefined behavior to access it through such an + /// alias. Note that it's always undefined behavior to access a C++ + /// object that's under construction through an alias derived from + /// outside the construction process. + /// + /// This flag controls whether calls that produce the aggregate + /// value may be evaluated directly into the slot, or whether they + /// must be evaluated into an unaliased temporary and then memcpy'ed + /// over. Since it's invalid in general to memcpy a non-POD C++ + /// object, it's important that this flag never be set when + /// evaluating an expression which constructs such an object. + bool AliasedFlag : 1; public: + enum IsAliased_t { IsNotAliased, IsAliased }; + enum IsDestructed_t { IsNotDestructed, IsDestructed }; + enum IsZeroed_t { IsNotZeroed, IsZeroed }; + enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers }; + /// ignored - Returns an aggregate value slot indicating that the /// aggregate value is being ignored. static AggValueSlot ignored() { AggValueSlot AV; AV.Addr = 0; AV.Quals = Qualifiers(); - AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0; + AV.DestructedFlag = AV.ObjCGCFlag = AV.ZeroedFlag = AV.AliasedFlag = false; return AV; } /// forAddr - Make a slot for an aggregate value. /// - /// \param Volatile - true if the slot should be volatile-initialized - /// - /// \param Qualifiers - The qualifiers that dictate how the slot - /// should be initialied. Only 'volatile' and the Objective-C - /// lifetime qualifiers matter. + /// \param quals - The qualifiers that dictate how the slot should + /// be initialied. Only 'volatile' and the Objective-C lifetime + /// qualifiers matter. /// - /// \param LifetimeExternallyManaged - true if the slot's lifetime - /// is being externally managed; false if a destructor should be - /// registered for any temporaries evaluated into the slot - /// \param RequiresGCollection - true if the slot is located + /// \param isDestructed - true if something else is responsible + /// for calling destructors on this object + /// \param needsGC - true if the slot is potentially located /// somewhere that ObjC GC calls should be emitted for - static AggValueSlot forAddr(llvm::Value *Addr, Qualifiers Quals, - bool LifetimeExternallyManaged, - bool RequiresGCollection = false, - bool IsZeroed = false) { + static AggValueSlot forAddr(llvm::Value *addr, Qualifiers quals, + IsDestructed_t isDestructed, + NeedsGCBarriers_t needsGC, + IsAliased_t isAliased, + IsZeroed_t isZeroed = IsNotZeroed) { AggValueSlot AV; - AV.Addr = Addr; - AV.Quals = Quals; - AV.LifetimeFlag = LifetimeExternallyManaged; - AV.RequiresGCollection = RequiresGCollection; - AV.IsZeroed = IsZeroed; + AV.Addr = addr; + AV.Quals = quals; + AV.DestructedFlag = isDestructed; + AV.ObjCGCFlag = needsGC; + AV.ZeroedFlag = isZeroed; + AV.AliasedFlag = isAliased; return AV; } - static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged, - bool RequiresGCollection = false, - bool IsZeroed = false) { + static AggValueSlot forLValue(LValue LV, IsDestructed_t isDestructed, + NeedsGCBarriers_t needsGC, + IsAliased_t isAliased, + IsZeroed_t isZeroed = IsNotZeroed) { return forAddr(LV.getAddress(), LV.getQuals(), - LifetimeExternallyManaged, RequiresGCollection, IsZeroed); + isDestructed, needsGC, isAliased, isZeroed); } - bool isLifetimeExternallyManaged() const { - return LifetimeFlag; + IsDestructed_t isExternallyDestructed() const { + return IsDestructed_t(DestructedFlag); } - void setLifetimeExternallyManaged(bool Managed = true) { - LifetimeFlag = Managed; + void setExternallyDestructed(bool destructed = true) { + DestructedFlag = destructed; } Qualifiers getQualifiers() const { return Quals; } @@ -408,8 +433,8 @@ public: return Quals.getObjCLifetime(); } - bool requiresGCollection() const { - return RequiresGCollection; + NeedsGCBarriers_t requiresGCollection() const { + return NeedsGCBarriers_t(ObjCGCFlag); } llvm::Value *getAddr() const { @@ -420,13 +445,17 @@ public: return Addr == 0; } + IsAliased_t isPotentiallyAliased() const { + return IsAliased_t(AliasedFlag); + } + RValue asRValue() const { return RValue::getAggregate(getAddr(), isVolatile()); } - void setZeroed(bool V = true) { IsZeroed = V; } - bool isZeroed() const { - return IsZeroed; + void setZeroed(bool V = true) { ZeroedFlag = V; } + IsZeroed_t isZeroed() const { + return IsZeroed_t(ZeroedFlag); } }; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp index 263e01e..68dd5c9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp @@ -30,12 +30,12 @@ using namespace llvm; namespace clang { class BackendConsumer : public ASTConsumer { - Diagnostic &Diags; + DiagnosticsEngine &Diags; BackendAction Action; const CodeGenOptions &CodeGenOpts; const TargetOptions &TargetOpts; const LangOptions &LangOpts; - llvm::raw_ostream *AsmOutStream; + raw_ostream *AsmOutStream; ASTContext *Context; Timer LLVMIRGeneration; @@ -45,12 +45,12 @@ namespace clang { llvm::OwningPtr<llvm::Module> TheModule; public: - BackendConsumer(BackendAction action, Diagnostic &_Diags, + BackendConsumer(BackendAction action, DiagnosticsEngine &_Diags, const CodeGenOptions &compopts, const TargetOptions &targetopts, const LangOptions &langopts, bool TimePasses, - const std::string &infile, llvm::raw_ostream *OS, + const std::string &infile, raw_ostream *OS, LLVMContext &C) : Diags(_Diags), Action(action), @@ -185,7 +185,7 @@ static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, // Translate the offset into the file. unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); SourceLocation NewLoc = - CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset); + CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset); return FullSourceLoc(NewLoc, CSM); } @@ -199,7 +199,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, // we re-format the SMDiagnostic in terms of a clang diagnostic. // Strip "error: " off the start of the message string. - llvm::StringRef Message = D.getMessage(); + StringRef Message = D.getMessage(); if (Message.startswith("error: ")) Message = Message.substr(7); @@ -259,7 +259,7 @@ llvm::LLVMContext *CodeGenAction::takeLLVMContext() { } static raw_ostream *GetOutputStream(CompilerInstance &CI, - llvm::StringRef InFile, + StringRef InFile, BackendAction Action) { switch (Action) { case Backend_EmitAssembly: @@ -275,14 +275,13 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI, return CI.createDefaultOutputFile(true, InFile, "o"); } - assert(0 && "Invalid action!"); - return 0; + llvm_unreachable("Invalid action!"); } ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { BackendAction BA = static_cast<BackendAction>(Act); - llvm::OwningPtr<llvm::raw_ostream> OS(GetOutputStream(CI, InFile, BA)); + llvm::OwningPtr<raw_ostream> OS(GetOutputStream(CI, InFile, BA)); if (BA != Backend_EmitNothing && !OS) return 0; @@ -320,17 +319,17 @@ void CodeGenAction::ExecuteAction() { TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext)); if (!TheModule) { // Translate from the diagnostic info to the SourceManager location. - SourceLocation Loc = SM.getLocation( + SourceLocation Loc = SM.translateFileLineCol( SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(), Err.getColumnNo() + 1); // Get a custom diagnostic for the error. We strip off a leading // diagnostic code if there is one. - llvm::StringRef Msg = Err.getMessage(); + StringRef Msg = Err.getMessage(); if (Msg.startswith("error: ")) Msg = Msg.substr(7); - unsigned DiagID = CI.getDiagnostics().getCustomDiagID(Diagnostic::Error, - Msg); + unsigned DiagID = CI.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, Msg); CI.getDiagnostics().Report(Loc, DiagID); return; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp index 702897a..8191f02 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGException.h" @@ -30,10 +31,10 @@ using namespace CodeGen; CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : CodeGenTypeCache(cgm), CGM(cgm), - Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), + Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()), AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), - NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1), - ExceptionSlot(0), EHSelectorSlot(0), + NormalCleanupDest(0), NextCleanupDestIndex(1), + EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), @@ -86,6 +87,10 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType type) { case Type::ObjCObject: case Type::ObjCInterface: return true; + + // In IRGen, atomic types are just the underlying type + case Type::Atomic: + return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType()); } llvm_unreachable("unknown type kind!"); } @@ -116,7 +121,8 @@ void CodeGenFunction::EmitReturnBlock() { dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin()); if (BI && BI->isUnconditional() && BI->getSuccessor(0) == ReturnBlock.getBlock()) { - // Reset insertion point and delete the branch. + // Reset insertion point, including debug location, and delete the branch. + Builder.SetCurrentDebugLocation(BI->getDebugLoc()); Builder.SetInsertPoint(BI->getParent()); BI->eraseFromParent(); delete ReturnBlock.getBlock(); @@ -189,7 +195,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } } - EmitIfUsed(*this, RethrowBlock.getBlock()); + EmitIfUsed(*this, EHResumeBlock); EmitIfUsed(*this, TerminateLandingPad); EmitIfUsed(*this, TerminateHandler); EmitIfUsed(*this, UnreachableBlock); @@ -215,7 +221,7 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site); llvm::PointerType *PointerTy = Int8PtrTy; llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy }; - const llvm::FunctionType *FunctionTy = + llvm::FunctionType *FunctionTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), ProfileFuncArgs, false); @@ -345,6 +351,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (Ty->isVariablyModifiedType()) EmitVariablyModifiedType(Ty); } + // Emit a location at the end of the prologue. + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitLocation(Builder, StartLoc); } void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { @@ -364,9 +373,12 @@ static void TryMarkNoThrow(llvm::Function *F) { for (llvm::Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) for (llvm::BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) - if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI)) + if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI)) { if (!Call->doesNotThrow()) return; + } else if (isa<llvm::ResumeInst>(&*BI)) { + return; + } F->setDoesNotThrow(true); } @@ -400,6 +412,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, EmitDestructorBody(Args); else if (isa<CXXConstructorDecl>(FD)) EmitConstructorBody(Args); + else if (getContext().getLangOptions().CUDA && + !CGM.getCodeGenOpts().CUDAIsDevice && + FD->hasAttr<CUDAGlobalAttr>()) + CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args); else EmitFunctionBody(Args); @@ -645,7 +661,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, llvm::Value *baseSizeInChars = llvm::ConstantInt::get(CGF.IntPtrTy, baseSizeAndAlign.first.getQuantity()); - const llvm::Type *i8p = Builder.getInt8PtrTy(); + llvm::Type *i8p = Builder.getInt8PtrTy(); llvm::Value *begin = Builder.CreateBitCast(dest, i8p, "vla.begin"); llvm::Value *end = Builder.CreateInBoundsGEP(dest, sizeInChars, "vla.end"); @@ -690,9 +706,9 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { // Cast the dest ptr to the appropriate i8 pointer type. unsigned DestAS = cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace(); - const llvm::Type *BP = Builder.getInt8PtrTy(DestAS); + llvm::Type *BP = Builder.getInt8PtrTy(DestAS); if (DestPtr->getType() != BP) - DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); + DestPtr = Builder.CreateBitCast(DestPtr, BP); // Get size and alignment info for this aggregate. std::pair<CharUnits, CharUnits> TypeInfo = @@ -740,7 +756,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), /*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, - NullConstant, llvm::Twine()); + NullConstant, Twine()); llvm::Value *SrcPtr = Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()); @@ -818,7 +834,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, // We have some number of constant-length arrays, so addr should // have LLVM type [M x [N x [...]]]*. Build a GEP that walks // down to the first element of addr. - llvm::SmallVector<llvm::Value*, 8> gepIndices; + SmallVector<llvm::Value*, 8> gepIndices; // GEP down to the array type. llvm::ConstantInt *zero = Builder.getInt32(0); @@ -828,7 +844,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, // constant-length arrays than to re-evaluate the array bounds. uint64_t countFromCLAs = 1; - const llvm::ArrayType *llvmArrayType = + llvm::ArrayType *llvmArrayType = cast<llvm::ArrayType>( cast<llvm::PointerType>(addr->getType())->getElementType()); while (true) { @@ -850,8 +866,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, baseType = arrayType->getElementType(); // Create the actual GEP. - addr = Builder.CreateInBoundsGEP(addr, gepIndices.begin(), - gepIndices.end(), "array.begin"); + addr = Builder.CreateInBoundsGEP(addr, gepIndices, "array.begin"); llvm::Value *numElements = llvm::ConstantInt::get(SizeTy, countFromCLAs); @@ -975,6 +990,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::FunctionNoProto: type = cast<FunctionType>(ty)->getResultType(); break; + + case Type::Atomic: + type = cast<AtomicType>(ty)->getValueType(); + break; } } while (type->isVariablyModifiedType()); } @@ -1018,3 +1037,50 @@ void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) { // In theory, we could try to duplicate the peepholes now, but whatever. protection.Inst->eraseFromParent(); } + +llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn, + llvm::Value *AnnotatedVal, + llvm::StringRef AnnotationStr, + SourceLocation Location) { + llvm::Value *Args[4] = { + AnnotatedVal, + Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy), + Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy), + CGM.EmitAnnotationLineNo(Location) + }; + return Builder.CreateCall(AnnotationFn, Args); +} + +void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) { + assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute"); + // FIXME We create a new bitcast for every annotation because that's what + // llvm-gcc was doing. + for (specific_attr_iterator<AnnotateAttr> + ai = D->specific_attr_begin<AnnotateAttr>(), + ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai) + EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation), + Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()), + (*ai)->getAnnotation(), D->getLocation()); +} + +llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D, + llvm::Value *V) { + assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute"); + llvm::Type *VTy = V->getType(); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, + CGM.Int8PtrTy); + + for (specific_attr_iterator<AnnotateAttr> + ai = D->specific_attr_begin<AnnotateAttr>(), + ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai) { + // FIXME Always emit the cast inst so we can differentiate between + // annotation on the first field of a struct and annotation on the struct + // itself. + if (VTy != CGM.Int8PtrTy) + V = Builder.Insert(new llvm::BitCastInst(V, CGM.Int8PtrTy)); + V = EmitAnnotationCall(F, V, (*ai)->getAnnotation(), D->getLocation()); + V = Builder.CreateBitCast(V, VTy); + } + + return V; +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index f27ed94..157623d 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -325,16 +325,8 @@ private: /// The innermost normal cleanup on the stack. stable_iterator InnermostNormalCleanup; - /// The innermost EH cleanup on the stack. - stable_iterator InnermostEHCleanup; - - /// The number of catches on the stack. - unsigned CatchDepth; - - /// The current EH destination index. Reset to FirstCatchIndex - /// whenever the last EH cleanup is popped. - unsigned NextEHDestIndex; - enum { FirstEHDestIndex = 1 }; + /// The innermost EH scope on the stack. + stable_iterator InnermostEHScope; /// The current set of branch fixups. A branch fixup is a jump to /// an as-yet unemitted label, i.e. a label for which we don't yet @@ -353,7 +345,7 @@ private: /// A a; /// foo: /// bar(); - llvm::SmallVector<BranchFixup, 8> BranchFixups; + SmallVector<BranchFixup, 8> BranchFixups; char *allocate(size_t Size); @@ -362,8 +354,7 @@ private: public: EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0), InnermostNormalCleanup(stable_end()), - InnermostEHCleanup(stable_end()), - CatchDepth(0), NextEHDestIndex(FirstEHDestIndex) {} + InnermostEHScope(stable_end()) {} ~EHScopeStack() { delete[] StartOfBuffer; } // Variadic templates would make this not terrible. @@ -435,8 +426,7 @@ public: return new (Buffer) T(N, a0, a1, a2); } - /// Pops a cleanup scope off the stack. This should only be called - /// by CodeGenFunction::PopCleanupBlock. + /// Pops a cleanup scope off the stack. This is private to CGCleanup.cpp. void popCleanup(); /// Push a set of catch handlers on the stack. The catch is @@ -444,7 +434,7 @@ public: /// set on it. class EHCatchScope *pushCatch(unsigned NumHandlers); - /// Pops a catch scope off the stack. + /// Pops a catch scope off the stack. This is private to CGException.cpp. void popCatch(); /// Push an exceptions filter on the stack. @@ -463,7 +453,7 @@ public: bool empty() const { return StartOfData == EndOfBuffer; } bool requiresLandingPad() const { - return (CatchDepth || hasEHCleanups()); + return InnermostEHScope != stable_end(); } /// Determines whether there are any normal cleanups on the stack. @@ -476,19 +466,13 @@ public: stable_iterator getInnermostNormalCleanup() const { return InnermostNormalCleanup; } - stable_iterator getInnermostActiveNormalCleanup() const; // CGException.h + stable_iterator getInnermostActiveNormalCleanup() const; - /// Determines whether there are any EH cleanups on the stack. - bool hasEHCleanups() const { - return InnermostEHCleanup != stable_end(); + stable_iterator getInnermostEHScope() const { + return InnermostEHScope; } - /// Returns the innermost EH cleanup on the stack, or stable_end() - /// if there are no EH cleanups. - stable_iterator getInnermostEHCleanup() const { - return InnermostEHCleanup; - } - stable_iterator getInnermostActiveEHCleanup() const; // CGException.h + stable_iterator getInnermostActiveEHScope() const; /// An unstable reference to a scope-stack depth. Invalidated by /// pushes but not pops. @@ -515,10 +499,6 @@ public: /// Translates an iterator into a stable_iterator. stable_iterator stabilize(iterator it) const; - /// Finds the nearest cleanup enclosing the given iterator. - /// Returns stable_iterator::invalid() if there are no such cleanups. - stable_iterator getEnclosingEHCleanup(iterator it) const; - /// Turn a stable reference to a scope depth into a unstable pointer /// to the EH stack. iterator find(stable_iterator save) const; @@ -547,9 +527,6 @@ public: /// Clears the branch-fixups list. This should only be called by /// ResolveAllBranchFixups. void clearFixups() { BranchFixups.clear(); } - - /// Gets the next EH destination index. - unsigned getNextEHDestIndex() { return NextEHDestIndex++; } }; /// CodeGenFunction - This class organizes the per-function state that is used @@ -580,26 +557,6 @@ public: unsigned Index; }; - /// An unwind destination is an abstract label, branching to which - /// may require a jump out through EH cleanups. - struct UnwindDest { - UnwindDest() : Block(0), ScopeDepth(), Index(0) {} - UnwindDest(llvm::BasicBlock *Block, - EHScopeStack::stable_iterator Depth, - unsigned Index) - : Block(Block), ScopeDepth(Depth), Index(Index) {} - - bool isValid() const { return Block != 0; } - llvm::BasicBlock *getBlock() const { return Block; } - EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; } - unsigned getDestIndex() const { return Index; } - - private: - llvm::BasicBlock *Block; - EHScopeStack::stable_iterator ScopeDepth; - unsigned Index; - }; - CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; @@ -629,9 +586,6 @@ public: /// iff the function has no return value. llvm::Value *ReturnValue; - /// RethrowBlock - Unified rethrow block. - UnwindDest RethrowBlock; - /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. llvm::AssertingVH<llvm::Instruction> AllocaInsertPt; @@ -652,16 +606,18 @@ public: /// i32s containing the indexes of the cleanup destinations. llvm::AllocaInst *NormalCleanupDest; - llvm::AllocaInst *EHCleanupDest; unsigned NextCleanupDestIndex; - /// The exception slot. All landing pads write the current - /// exception pointer into this alloca. + /// EHResumeBlock - Unified block containing a call to llvm.eh.resume. + llvm::BasicBlock *EHResumeBlock; + + /// The exception slot. All landing pads write the current exception pointer + /// into this alloca. llvm::Value *ExceptionSlot; - /// The selector slot. Under the MandatoryCleanup model, all - /// landing pads write the current selector value into this alloca. + /// The selector slot. Under the MandatoryCleanup model, all landing pads + /// write the current selector value into this alloca. llvm::AllocaInst *EHSelectorSlot; /// Emits a landing pad for the current EH stack. @@ -681,7 +637,7 @@ public: public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. - llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack; + SmallVector<llvm::Value*, 8> ObjCEHValueStack; /// A class controlling the emission of a finally block. class FinallyInfo { @@ -872,7 +828,7 @@ public: /// The given basic block lies in the current EH scope, but may be a /// target of a potentially scope-crossing jump; get a stable handle /// to which we can perform this jump later. - JumpDest getJumpDestInCurrentScope(llvm::StringRef Name = llvm::StringRef()) { + JumpDest getJumpDestInCurrentScope(StringRef Name = StringRef()) { return getJumpDestInCurrentScope(createBasicBlock(Name)); } @@ -886,14 +842,13 @@ public: /// a conservatively correct answer for this method. bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const; - /// EmitBranchThroughEHCleanup - Emit a branch from the current - /// insert block through the EH cleanup handling code (if any) and - /// then on to \arg Dest. - void EmitBranchThroughEHCleanup(UnwindDest Dest); + /// popCatchScope - Pops the catch scope at the top of the EHScope + /// stack, emitting any required code (other than the catch handlers + /// themselves). + void popCatchScope(); - /// getRethrowDest - Returns the unified outermost-scope rethrow - /// destination. - UnwindDest getRethrowDest(); + llvm::BasicBlock *getEHResumeBlock(); + llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope); /// An object to manage conditionally-evaluated expressions. class ConditionalEvaluation { @@ -1089,7 +1044,7 @@ private: JumpDest BreakBlock; JumpDest ContinueBlock; }; - llvm::SmallVector<BreakContinue, 8> BreakContinueStack; + SmallVector<BreakContinue, 8> BreakContinueStack; /// SwitchInsn - This is nearest current switch instruction. It is null if if /// current context is not in a switch. @@ -1135,7 +1090,7 @@ private: /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM /// type as well as the field number that contains the actual data. - llvm::DenseMap<const ValueDecl *, std::pair<const llvm::Type *, + llvm::DenseMap<const ValueDecl *, std::pair<llvm::Type *, unsigned> > ByRefValueInfo; llvm::BasicBlock *TerminateLandingPad; @@ -1161,13 +1116,17 @@ public: const LangOptions &getLangOptions() const { return CGM.getLangOptions(); } - /// Returns a pointer to the function's exception object slot, which - /// is assigned in every landing pad. + /// Returns a pointer to the function's exception object and selector slot, + /// which is assigned in every landing pad. llvm::Value *getExceptionSlot(); llvm::Value *getEHSelectorSlot(); + /// Returns the contents of the function's exception object and selector + /// slots. + llvm::Value *getExceptionFromSlot(); + llvm::Value *getSelectorFromSlot(); + llvm::Value *getNormalCleanupDestSlot(); - llvm::Value *getEHCleanupDestSlot(); llvm::BasicBlock *getUnreachableBlock() { if (!UnreachableBlock) { @@ -1248,9 +1207,8 @@ public: /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); - void GenerateObjCGetterBody(ObjCIvarDecl *Ivar, bool IsAtomic, bool IsStrong); - void GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD, - ObjCIvarDecl *Ivar); + void generateObjCGetterBody(const ObjCImplementationDecl *classImpl, + const ObjCPropertyImplDecl *propImpl); void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCMethodDecl *MD, bool ctor); @@ -1259,6 +1217,8 @@ public: /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + void generateObjCSetterBody(const ObjCImplementationDecl *classImpl, + const ObjCPropertyImplDecl *propImpl); bool IndirectObjCSetterArg(const CGFunctionInfo &FI); bool IvarTypeWithAggrGCObjects(QualType Ty); @@ -1269,7 +1229,7 @@ public: llvm::Value *EmitBlockLiteral(const BlockExpr *); llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *, const CGBlockInfo &Info, - const llvm::StructType *, + llvm::StructType *, llvm::Constant *BlockVarLayout); llvm::Function *GenerateBlockFunction(GlobalDecl GD, @@ -1298,7 +1258,7 @@ public: return GetAddrOfBlockDecl(E->getDecl(), E->isByRef()); } llvm::Value *GetAddrOfBlockDecl(const VarDecl *var, bool ByRef); - const llvm::Type *BuildByRefType(const VarDecl *var); + llvm::Type *BuildByRefType(const VarDecl *var); void GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo); @@ -1352,7 +1312,7 @@ public: /// GetVTablePtr - Return the Value of the vtable pointer member pointed /// to by This. - llvm::Value *GetVTablePtr(llvm::Value *This, const llvm::Type *Ty); + llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty); /// EnterDtorCleanups - Enter the cleanups necessary to complete the /// given phase of destruction for a destructor. The end result @@ -1415,7 +1375,7 @@ public: static bool hasAggregateLLVMType(QualType T); /// createBasicBlock - Create an LLVM basic block. - llvm::BasicBlock *createBasicBlock(llvm::StringRef name = "", + llvm::BasicBlock *createBasicBlock(StringRef name = "", llvm::Function *parent = 0, llvm::BasicBlock *before = 0) { #ifdef NDEBUG @@ -1444,6 +1404,10 @@ public: /// means the block can be ignored if it is unreachable. void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false); + /// EmitBlockAfterUses - Emit the given block somewhere hopefully + /// near its uses, and leave the insertion point in it. + void EmitBlockAfterUses(llvm::BasicBlock *BB); + /// EmitBranch - Emit a branch to the specified basic block from the current /// insert block, taking care to avoid creation of branches from dummy /// blocks. It is legal to call this function even if there is no current @@ -1486,8 +1450,8 @@ public: /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. The caller is responsible for setting an appropriate alignment on /// the alloca. - llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, - const llvm::Twine &Name = "tmp"); + llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, + const Twine &Name = "tmp"); /// InitTempAlloca - Provide an initial value for the given alloca. void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value); @@ -1497,17 +1461,19 @@ public: /// value needs to be stored into an alloca (for example, to avoid explicit /// PHI construction), but the type is the IR type, not the type appropriate /// for storing in memory. - llvm::AllocaInst *CreateIRTemp(QualType T, const llvm::Twine &Name = "tmp"); + llvm::AllocaInst *CreateIRTemp(QualType T, const Twine &Name = "tmp"); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignment. - llvm::AllocaInst *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp"); + llvm::AllocaInst *CreateMemTemp(QualType T, const Twine &Name = "tmp"); /// CreateAggTemp - Create a temporary memory object for the given /// aggregate type. - AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") { + AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") { return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(), - false); + AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); } /// Emit a cast to void* in the appropriate address space. @@ -1708,8 +1674,8 @@ public: void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, bool ForVirtualBase, llvm::Value *This); - void EmitNewArrayInitializer(const CXXNewExpr *E, llvm::Value *NewPtr, - llvm::Value *NumElements); + void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType, + llvm::Value *NewPtr, llvm::Value *NumElements); void EmitCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); @@ -2074,18 +2040,18 @@ public: ReturnValueSlot ReturnValue = ReturnValueSlot()); llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee, - llvm::ArrayRef<llvm::Value *> Args, - const llvm::Twine &Name = ""); + ArrayRef<llvm::Value *> Args, + const Twine &Name = ""); llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee, - const llvm::Twine &Name = ""); + const Twine &Name = ""); llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, - const llvm::Type *Ty); + llvm::Type *Ty); llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, - llvm::Value *This, const llvm::Type *Ty); + llvm::Value *This, llvm::Type *Ty); llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier *Qual, - const llvm::Type *Ty); + llvm::Type *Ty); llvm::Value *BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, @@ -2110,6 +2076,9 @@ public: const CXXMethodDecl *MD, ReturnValueSlot ReturnValue); + RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, + ReturnValueSlot ReturnValue); + RValue EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E); @@ -2122,14 +2091,14 @@ public: llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitNeonCall(llvm::Function *F, - llvm::SmallVectorImpl<llvm::Value*> &O, + SmallVectorImpl<llvm::Value*> &O, const char *name, unsigned shift = 0, bool rightshift = false); llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx); - llvm::Value *EmitNeonShiftVector(llvm::Value *V, const llvm::Type *Ty, + llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty, bool negateForRightShift); - llvm::Value *BuildVector(const llvm::SmallVectorImpl<llvm::Value*> &Ops); + llvm::Value *BuildVector(const SmallVectorImpl<llvm::Value*> &Ops); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); @@ -2163,7 +2132,7 @@ public: bool ignored); llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); - llvm::Value *EmitARCRetainBlock(llvm::Value *value); + llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory); void EmitARCRelease(llvm::Value *value, bool precise); llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); @@ -2175,10 +2144,13 @@ public: std::pair<LValue,llvm::Value*> EmitARCStoreStrong(const BinaryOperator *e, bool ignored); + llvm::Value *EmitObjCThrowOperand(const Expr *expr); + llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr); llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr); llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr); + llvm::Value *EmitARCExtendBlockObject(const Expr *expr); llvm::Value *EmitARCRetainScalarExpr(const Expr *expr); llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr); @@ -2311,6 +2283,25 @@ public: void EmitCXXThrowExpr(const CXXThrowExpr *E); + RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = 0); + + //===--------------------------------------------------------------------===// + // Annotations Emission + //===--------------------------------------------------------------------===// + + /// Emit an annotation call (intrinsic or builtin). + llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn, + llvm::Value *AnnotatedVal, + llvm::StringRef AnnotationStr, + SourceLocation Location); + + /// Emit local annotations for the local variable V, declared by D. + void EmitVarAnnotations(const VarDecl *D, llvm::Value *V); + + /// Emit field annotations for the given field & value. Returns the + /// annotation result. + llvm::Value *EmitFieldAnnotations(const FieldDecl *D, llvm::Value *V); + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// @@ -2370,7 +2361,7 @@ private: /// Ty, into individual arguments on the provided vector \arg Args. See /// ABIArgInfo::Expand. void ExpandTypeToArgs(QualType Ty, RValue Src, - llvm::SmallVector<llvm::Value*, 16> &Args, + SmallVector<llvm::Value*, 16> &Args, llvm::FunctionType *IRFuncTy); llvm::Value* EmitAsmInput(const AsmStmt &S, @@ -2439,7 +2430,7 @@ private: void EmitDeclMetadata(); CodeGenModule::ByrefHelpers * - buildByrefHelpers(const llvm::StructType &byrefType, + buildByrefHelpers(llvm::StructType &byrefType, const AutoVarEmission &emission); }; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index 0668039..924ec84 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -16,8 +16,10 @@ #include "CodeGenFunction.h" #include "CodeGenTBAA.h" #include "CGCall.h" +#include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "CGOpenCLRuntime.h" #include "TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/AST/ASTContext.h" @@ -27,7 +29,6 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" -#include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -44,8 +45,10 @@ using namespace clang; using namespace CodeGen; +static const char AnnotationSection[] = "llvm.metadata"; + static CGCXXABI &createCXXABI(CodeGenModule &CGM) { - switch (CGM.getContext().Target.getCXXABI()) { + switch (CGM.getContext().getTargetInfo().getCXXABI()) { case CXXABI_ARM: return *CreateARMCXXABI(CGM); case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM); case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM); @@ -58,22 +61,25 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) { CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, llvm::Module &M, const llvm::TargetData &TD, - Diagnostic &diags) + DiagnosticsEngine &diags) : Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), ABI(createCXXABI(*this)), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO), TBAA(0), - VTables(*this), Runtime(0), DebugInfo(0), ARCData(0), RRData(0), - CFConstantStringClassRef(0), ConstantStringClassRef(0), + VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), + DebugInfo(0), ARCData(0), RRData(0), CFConstantStringClassRef(0), + ConstantStringClassRef(0), NSConstantStringType(0), VMContext(M.getContext()), - NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), - BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0), BlockObjectAssign(0), BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0) { if (Features.ObjC1) - createObjCRuntime(); + createObjCRuntime(); + if (Features.OpenCL) + createOpenCLRuntime(); + if (Features.CUDA) + createCUDARuntime(); // Enable TBAA unless it's suppressed. if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0) @@ -98,17 +104,20 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Int8Ty = llvm::Type::getInt8Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); - PointerWidthInBits = C.Target.getPointerWidth(0); + PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); PointerAlignInBytes = - C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity(); - IntTy = llvm::IntegerType::get(LLVMContext, C.Target.getIntWidth()); + C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity(); + IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth()); IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); } CodeGenModule::~CodeGenModule() { - delete Runtime; + delete ObjCRuntime; + delete OpenCLRuntime; + delete CUDARuntime; + delete TheTargetCodeGenInfo; delete &ABI; delete TBAA; delete DebugInfo; @@ -118,21 +127,29 @@ CodeGenModule::~CodeGenModule() { void CodeGenModule::createObjCRuntime() { if (!Features.NeXTRuntime) - Runtime = CreateGNUObjCRuntime(*this); + ObjCRuntime = CreateGNUObjCRuntime(*this); else - Runtime = CreateMacObjCRuntime(*this); + ObjCRuntime = CreateMacObjCRuntime(*this); +} + +void CodeGenModule::createOpenCLRuntime() { + OpenCLRuntime = new CGOpenCLRuntime(*this); +} + +void CodeGenModule::createCUDARuntime() { + CUDARuntime = CreateNVCUDARuntime(*this); } void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); - if (Runtime) - if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction()) + if (ObjCRuntime) + if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); - EmitAnnotations(); + EmitGlobalAnnotations(); EmitLLVMUsed(); SimplifyPersonality(); @@ -142,6 +159,9 @@ void CodeGenModule::Release() { if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes) EmitCoverageFile(); + + if (DebugInfo) + DebugInfo->finalize(); } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { @@ -163,11 +183,11 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, } bool CodeGenModule::isTargetDarwin() const { - return getContext().Target.getTriple().isOSDarwin(); + return getContext().getTargetInfo().getTriple().isOSDarwin(); } -void CodeGenModule::Error(SourceLocation loc, llvm::StringRef error) { - unsigned diagID = getDiags().getCustomDiagID(Diagnostic::Error, error); +void CodeGenModule::Error(SourceLocation loc, StringRef error) { + unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error); getDiags().Report(Context.getFullLoc(loc), diagID); } @@ -177,7 +197,7 @@ void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID) @@ -190,7 +210,7 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, + unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; @@ -281,10 +301,10 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, GV->setUnnamedAddr(true); } -llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { +StringRef CodeGenModule::getMangledName(GlobalDecl GD) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); - llvm::StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()]; + StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()]; if (!Str.empty()) return Str; @@ -313,7 +333,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { char *Name = MangledNamesAllocator.Allocate<char>(Length); std::copy(Buffer.begin(), Buffer.end(), Name); - Str = llvm::StringRef(Name, Length); + Str = StringRef(Name, Length); return Str; } @@ -333,7 +353,7 @@ void CodeGenModule::getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer, MangleCtx.mangleBlock(cast<DeclContext>(D), BD, Out); } -llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) { +llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) { return getModule().getNamedValue(Name); } @@ -380,22 +400,6 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) { } } -void CodeGenModule::EmitAnnotations() { - if (Annotations.empty()) - return; - - // Create a new global variable for the ConstantStruct in the Module. - llvm::Constant *Array = - llvm::ConstantArray::get(llvm::ArrayType::get(Annotations[0]->getType(), - Annotations.size()), - Annotations); - llvm::GlobalValue *gv = - new llvm::GlobalVariable(TheModule, Array->getType(), false, - llvm::GlobalValue::AppendingLinkage, Array, - "llvm.global.annotations"); - gv->setSection("llvm.metadata"); -} - llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); @@ -413,7 +417,12 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { // definition somewhere else, so we can use available_externally linkage. if (Linkage == GVA_C99Inline) return llvm::Function::AvailableExternallyLinkage; - + + // Note that Apple's kernel linker doesn't support symbol + // coalescing, so we need to avoid linkonce and weak linkages there. + // Normally, this means we just map to internal, but for explicit + // instantiations we'll map to external. + // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because // a) if all references in this translation unit are optimized away, we @@ -432,7 +441,7 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { if (Linkage == GVA_ExplicitTemplateInstantiation) return !Context.getLangOptions().AppleKext ? llvm::Function::WeakODRLinkage - : llvm::Function::InternalLinkage; + : llvm::Function::ExternalLinkage; // Otherwise, we have strong external linkage. assert(Linkage == GVA_StrongExternal); @@ -460,29 +469,54 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); } +/// Determines whether the language options require us to model +/// unwind exceptions. We treat -fexceptions as mandating this +/// except under the fragile ObjC ABI with only ObjC exceptions +/// enabled. This means, for example, that C with -fexceptions +/// enables this. +static bool hasUnwindExceptions(const LangOptions &Features) { + // If exceptions are completely disabled, obviously this is false. + if (!Features.Exceptions) return false; + + // If C++ exceptions are enabled, this is true. + if (Features.CXXExceptions) return true; + + // If ObjC exceptions are enabled, this depends on the ABI. + if (Features.ObjCExceptions) { + if (!Features.ObjCNonFragileABI) return false; + } + + return true; +} + void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { if (CodeGenOpts.UnwindTables) F->setHasUWTable(); - if (!Features.Exceptions && !Features.ObjCNonFragileABI) + if (!hasUnwindExceptions(Features)) F->addFnAttr(llvm::Attribute::NoUnwind); - if (D->hasAttr<AlwaysInlineAttr>()) - F->addFnAttr(llvm::Attribute::AlwaysInline); - - if (D->hasAttr<NakedAttr>()) + if (D->hasAttr<NakedAttr>()) { + // Naked implies noinline: we should not be inlining such functions. F->addFnAttr(llvm::Attribute::Naked); + F->addFnAttr(llvm::Attribute::NoInline); + } if (D->hasAttr<NoInlineAttr>()) F->addFnAttr(llvm::Attribute::NoInline); + // (noinline wins over always_inline, and we can't specify both in IR) + if (D->hasAttr<AlwaysInlineAttr>() && + !F->hasFnAttr(llvm::Attribute::NoInline)) + F->addFnAttr(llvm::Attribute::AlwaysInline); + if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D)) F->setUnnamedAddr(true); - if (Features.getStackProtectorMode() == LangOptions::SSPOn) + if (Features.getStackProtector() == LangOptions::SSPOn) F->addFnAttr(llvm::Attribute::StackProtect); - else if (Features.getStackProtectorMode() == LangOptions::SSPReq) + else if (Features.getStackProtector() == LangOptions::SSPReq) F->addFnAttr(llvm::Attribute::StackProtectReq); unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); @@ -570,7 +604,7 @@ void CodeGenModule::EmitLLVMUsed() { if (LLVMUsed.empty()) return; - const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); // Convert LLVMUsed to what ConstantArray needs. std::vector<llvm::Constant*> UsedArray; @@ -597,7 +631,7 @@ void CodeGenModule::EmitLLVMUsed() { void CodeGenModule::EmitDeferred() { // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code - // for a static function, iterate until no changes are made. + // for a static function, iterate until no changes are made. while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { if (!DeferredVTables.empty()) { @@ -618,7 +652,7 @@ void CodeGenModule::EmitDeferred() { // ignore these cases. // // TODO: That said, looking this up multiple times is very wasteful. - llvm::StringRef Name = getMangledName(D); + StringRef Name = getMangledName(D); llvm::GlobalValue *CGRef = GetGlobalValue(Name); assert(CGRef && "Deferred decl wasn't referenced?"); @@ -635,54 +669,78 @@ void CodeGenModule::EmitDeferred() { } } -/// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the -/// annotation information for a given GlobalValue. The annotation struct is -/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the -/// GlobalValue being annotated. The second field is the constant string -/// created from the AnnotateAttr's annotation. The third field is a constant -/// string containing the name of the translation unit. The fourth field is -/// the line number in the file of the annotated value declaration. -/// -/// FIXME: this does not unique the annotation string constants, as llvm-gcc -/// appears to. -/// +void CodeGenModule::EmitGlobalAnnotations() { + if (Annotations.empty()) + return; + + // Create a new global variable for the ConstantStruct in the Module. + llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get( + Annotations[0]->getType(), Annotations.size()), Annotations); + llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), + Array->getType(), false, llvm::GlobalValue::AppendingLinkage, Array, + "llvm.global.annotations"); + gv->setSection(AnnotationSection); +} + +llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) { + llvm::StringMap<llvm::Constant*>::iterator i = AnnotationStrings.find(Str); + if (i != AnnotationStrings.end()) + return i->second; + + // Not found yet, create a new global. + llvm::Constant *s = llvm::ConstantArray::get(getLLVMContext(), Str, true); + llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), s->getType(), + true, llvm::GlobalValue::PrivateLinkage, s, ".str"); + gv->setSection(AnnotationSection); + gv->setUnnamedAddr(true); + AnnotationStrings[Str] = gv; + return gv; +} + +llvm::Constant *CodeGenModule::EmitAnnotationUnit(SourceLocation Loc) { + SourceManager &SM = getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + if (PLoc.isValid()) + return EmitAnnotationString(PLoc.getFilename()); + return EmitAnnotationString(SM.getBufferName(Loc)); +} + +llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) { + SourceManager &SM = getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(L); + unsigned LineNo = PLoc.isValid() ? PLoc.getLine() : + SM.getExpansionLineNumber(L); + return llvm::ConstantInt::get(Int32Ty, LineNo); +} + llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, - unsigned LineNo) { - llvm::Module *M = &getModule(); - - // get [N x i8] constants for the annotation string, and the filename string - // which are the 2nd and 3rd elements of the global annotation structure. - const llvm::Type *SBP = llvm::Type::getInt8PtrTy(VMContext); - llvm::Constant *anno = llvm::ConstantArray::get(VMContext, - AA->getAnnotation(), true); - llvm::Constant *unit = llvm::ConstantArray::get(VMContext, - M->getModuleIdentifier(), - true); - - // Get the two global values corresponding to the ConstantArrays we just - // created to hold the bytes of the strings. - llvm::GlobalValue *annoGV = - new llvm::GlobalVariable(*M, anno->getType(), false, - llvm::GlobalValue::PrivateLinkage, anno, - GV->getName()); - // translation unit name string, emitted into the llvm.metadata section. - llvm::GlobalValue *unitGV = - new llvm::GlobalVariable(*M, unit->getType(), false, - llvm::GlobalValue::PrivateLinkage, unit, - ".str"); - unitGV->setUnnamedAddr(true); + SourceLocation L) { + // Get the globals for file name, annotation, and the line number. + llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()), + *UnitGV = EmitAnnotationUnit(L), + *LineNoCst = EmitAnnotationLineNo(L); // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[4] = { - llvm::ConstantExpr::getBitCast(GV, SBP), - llvm::ConstantExpr::getBitCast(annoGV, SBP), - llvm::ConstantExpr::getBitCast(unitGV, SBP), - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LineNo) + llvm::ConstantExpr::getBitCast(GV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), + LineNoCst }; return llvm::ConstantStruct::getAnon(Fields); } +void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D, + llvm::GlobalValue *GV) { + assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute"); + // Get the struct elements for these annotations. + for (specific_attr_iterator<AnnotateAttr> + ai = D->specific_attr_begin<AnnotateAttr>(), + ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai) + Annotations.push_back(EmitAnnotateAttr(GV, *ai, D->getLocation())); +} + bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // Never defer when EmitAllDecls is specified. if (Features.EmitAllDecls) @@ -695,7 +753,7 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { const AliasAttr *AA = VD->getAttr<AliasAttr>(); assert(AA && "No alias?"); - const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType()); + llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType()); // See if there is already something with the target's name in the module. llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee()); @@ -728,34 +786,45 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { if (Global->hasAttr<AliasAttr>()) return EmitAliasDefinition(GD); - // Ignore declarations, they will be emitted on their first use. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) { - if (FD->getIdentifier()) { - llvm::StringRef Name = FD->getName(); - if (Name == "_Block_object_assign") { - BlockObjectAssignDecl = FD; - } else if (Name == "_Block_object_dispose") { - BlockObjectDisposeDecl = FD; - } + // If this is CUDA, be selective about which declarations we emit. + if (Features.CUDA) { + if (CodeGenOpts.CUDAIsDevice) { + if (!Global->hasAttr<CUDADeviceAttr>() && + !Global->hasAttr<CUDAGlobalAttr>() && + !Global->hasAttr<CUDAConstantAttr>() && + !Global->hasAttr<CUDASharedAttr>()) + return; + } else { + if (!Global->hasAttr<CUDAHostAttr>() && ( + Global->hasAttr<CUDADeviceAttr>() || + Global->hasAttr<CUDAConstantAttr>() || + Global->hasAttr<CUDASharedAttr>())) + return; } + } + // Ignore declarations, they will be emitted on their first use. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) { // Forward declarations are emitted lazily on first use. - if (!FD->doesThisDeclarationHaveABody()) + if (!FD->doesThisDeclarationHaveABody()) { + if (!FD->doesDeclarationForceExternallyVisibleDefinition()) + return; + + const FunctionDecl *InlineDefinition = 0; + FD->getBody(InlineDefinition); + + StringRef MangledName = getMangledName(GD); + llvm::StringMap<GlobalDecl>::iterator DDI = + DeferredDecls.find(MangledName); + if (DDI != DeferredDecls.end()) + DeferredDecls.erase(DDI); + EmitGlobalDefinition(InlineDefinition); return; + } } else { const VarDecl *VD = cast<VarDecl>(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); - if (VD->getIdentifier()) { - llvm::StringRef Name = VD->getName(); - if (Name == "_NSConcreteGlobalBlock") { - NSConcreteGlobalBlockDecl = VD; - } else if (Name == "_NSConcreteStackBlock") { - NSConcreteStackBlockDecl = VD; - } - } - - if (VD->isThisDeclarationADefinition() != VarDecl::Definition) return; } @@ -778,7 +847,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // If the value has already been used, add it directly to the // DeferredDeclsToEmit list. - llvm::StringRef MangledName = getMangledName(GD); + StringRef MangledName = getMangledName(GD); if (GetGlobalValue(MangledName)) DeferredDeclsToEmit.push_back(GD); else { @@ -827,7 +896,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) return EmitGlobalVarDefinition(VD); - assert(0 && "Invalid argument to EmitGlobalDefinition()"); + llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the @@ -838,8 +907,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the function when it is first created. llvm::Constant * -CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, - const llvm::Type *Ty, +CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName, + llvm::Type *Ty, GlobalDecl D, bool ForVTable, llvm::Attributes ExtraAttrs) { // Lookup the entry, lazily creating it if necessary. @@ -865,7 +934,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, // sure not to try to set attributes. bool IsIncompleteFunction = false; - const llvm::FunctionType *FTy; + llvm::FunctionType *FTy; if (isa<llvm::FunctionType>(Ty)) { FTy = cast<llvm::FunctionType>(Ty); } else { @@ -935,21 +1004,21 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, - const llvm::Type *Ty, + llvm::Type *Ty, bool ForVTable) { // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType()); - llvm::StringRef MangledName = getMangledName(GD); + StringRef MangledName = getMangledName(GD); return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable); } /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant * -CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, - llvm::StringRef Name, +CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, + StringRef Name, llvm::Attributes ExtraAttrs) { return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, ExtraAttrs); @@ -979,8 +1048,8 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D, /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the global when it is first created. llvm::Constant * -CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, - const llvm::PointerType *Ty, +CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, + llvm::PointerType *Ty, const VarDecl *D, bool UnnamedAddr) { // Lookup the entry, lazily creating it if necessary. @@ -1049,8 +1118,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, llvm::GlobalVariable * -CodeGenModule::CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, - const llvm::Type *Ty, +CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, + llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage) { llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name); llvm::GlobalVariable *OldGV = 0; @@ -1092,24 +1161,24 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, /// then it will be greated with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, - const llvm::Type *Ty) { + llvm::Type *Ty) { assert(D->hasGlobalStorage() && "Not a global variable"); QualType ASTTy = D->getType(); if (Ty == 0) Ty = getTypes().ConvertTypeForMem(ASTTy); - const llvm::PointerType *PTy = + llvm::PointerType *PTy = llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); - llvm::StringRef MangledName = getMangledName(D); + StringRef MangledName = getMangledName(D); return GetOrCreateLLVMGlobal(MangledName, PTy, D); } /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant * -CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty, - llvm::StringRef Name) { +CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty, + StringRef Name) { return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0, true); } @@ -1121,7 +1190,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { // If we have not seen a reference to this variable yet, place it // into the deferred declarations table to be emitted if needed // later. - llvm::StringRef MangledName = getMangledName(D); + StringRef MangledName = getMangledName(D); if (!GetGlobalValue(MangledName)) { DeferredDecls[MangledName] = D; return; @@ -1207,7 +1276,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { return llvm::GlobalVariable::LinkOnceODRLinkage; } -CharUnits CodeGenModule::GetTargetTypeStoreSize(const llvm::Type *Ty) const { +CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( TheTargetData.getTypeStoreSizeInBits(Ty)); } @@ -1253,7 +1322,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { } } - const llvm::Type* InitType = Init->getType(); + llvm::Type* InitType = Init->getType(); llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType); // Strip off a bitcast if we got one back. @@ -1282,7 +1351,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { getContext().getTargetAddressSpace(ASTTy)) { // Move the old entry aside so that we'll create a new one. - Entry->setName(llvm::StringRef()); + Entry->setName(StringRef()); // Make a new global with the correct type, this is now guaranteed to work. GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType)); @@ -1296,11 +1365,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { cast<llvm::GlobalValue>(Entry)->eraseFromParent(); } - if (const AnnotateAttr *AA = D->getAttr<AnnotateAttr>()) { - SourceManager &SM = Context.getSourceManager(); - AddAnnotation(EmitAnnotateAttr(GV, AA, - SM.getInstantiationLineNumber(D->getLocation()))); - } + if (D->hasAttr<AnnotateAttr>()) + AddGlobalAnnotations(D, GV); GV->setInitializer(Init); @@ -1326,10 +1392,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { EmitCXXGlobalVarDeclInitFunc(D, GV); // Emit global variable debug information. - if (CGDebugInfo *DI = getModuleDebugInfo()) { - DI->setLocation(D->getLocation()); + if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitGlobalVariable(GV, D); - } } llvm::GlobalValue::LinkageTypes @@ -1377,8 +1441,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *OldFn = dyn_cast<llvm::Function>(Old); if (OldFn == 0) return; - const llvm::Type *NewRetTy = NewFn->getReturnType(); - llvm::SmallVector<llvm::Value*, 4> ArgList; + llvm::Type *NewRetTy = NewFn->getReturnType(); + SmallVector<llvm::Value*, 4> ArgList; for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { @@ -1394,6 +1458,17 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, if (CI->getType() != NewRetTy && !CI->use_empty()) continue; + // Get the attribute list. + llvm::SmallVector<llvm::AttributeWithIndex, 8> AttrVec; + llvm::AttrListPtr AttrList = CI->getAttributes(); + + // Get any return attributes. + llvm::Attributes RAttrs = AttrList.getRetAttributes(); + + // Add the return attributes. + if (RAttrs) + AttrVec.push_back(llvm::AttributeWithIndex::get(0, RAttrs)); + // If the function was passed too few arguments, don't transform. If extra // arguments were passed, we silently drop them. If any of the types // mismatch, we don't transform. @@ -1406,10 +1481,17 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, DontTransform = true; break; } + + // Add any parameter attributes. + if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1)) + AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs)); } if (DontTransform) continue; + if (llvm::Attributes FnAttrs = AttrList.getFnAttributes()) + AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs)); + // Okay, we can transform this. Create the new call instruction and copy // over the required information. ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo); @@ -1417,7 +1499,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, ArgList.clear(); if (!NewCall->getType()->isVoidTy()) NewCall->takeName(CI); - NewCall->setAttributes(CI->getAttributes()); + NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec.begin(), + AttrVec.end())); NewCall->setCallingConv(CI->getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. @@ -1440,7 +1523,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { bool variadic = false; if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>()) variadic = fpt->isVariadic(); - const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic); + llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); @@ -1467,7 +1550,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // (e.g. "int f()") and then a definition of a different type // (e.g. "int f(int x)"). Move the old function aside so that it // doesn't interfere with GetAddrOfFunction. - OldFn->setName(llvm::StringRef()); + OldFn->setName(StringRef()); llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty)); // If this is an implementation of a function without a prototype, try to @@ -1510,6 +1593,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr<DestructorAttr>()) AddGlobalDtor(Fn, DA->getPriority()); + if (D->hasAttr<AnnotateAttr>()) + AddGlobalAnnotations(D, Fn); } void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { @@ -1517,7 +1602,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { const AliasAttr *AA = D->getAttr<AliasAttr>(); assert(AA && "Not an alias?"); - llvm::StringRef MangledName = getMangledName(GD); + StringRef MangledName = getMangledName(GD); // If there is a definition in the module, then it wins over the alias. // This is dubious, but allow it to be safe. Just ignore the alias. @@ -1525,7 +1610,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { if (Entry && !Entry->isDeclaration()) return; - const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. @@ -1582,37 +1667,8 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { SetCommonAttributes(D, GA); } -/// getBuiltinLibFunction - Given a builtin id for a function like -/// "__builtin_fabsf", return a Function* for "fabsf". -llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, - unsigned BuiltinID) { - assert((Context.BuiltinInfo.isLibFunction(BuiltinID) || - Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) && - "isn't a lib fn"); - - // Get the name, skip over the __builtin_ prefix (if necessary). - llvm::StringRef Name; - GlobalDecl D(FD); - - // If the builtin has been declared explicitly with an assembler label, - // use the mangled name. This differs from the plain label on platforms - // that prefix labels. - if (FD->hasAttr<AsmLabelAttr>()) - Name = getMangledName(D); - else if (Context.BuiltinInfo.isLibFunction(BuiltinID)) - Name = Context.BuiltinInfo.GetName(BuiltinID) + 10; - else - Name = Context.BuiltinInfo.GetName(BuiltinID); - - - const llvm::FunctionType *Ty = - cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); - - return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false); -} - llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, - llvm::ArrayRef<llvm::Type*> Tys) { + ArrayRef<llvm::Type*> Tys) { return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, Tys); } @@ -1623,7 +1679,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map, bool TargetIsLSB, bool &IsUTF16, unsigned &StringLength) { - llvm::StringRef String = Literal->getString(); + StringRef String = Literal->getString(); unsigned NumBytes = String.size(); // Check for simple case. @@ -1633,7 +1689,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map, } // Otherwise, convert the UTF8 literals into a byte string. - llvm::SmallVector<UTF16, 128> ToBuf(NumBytes); + SmallVector<UTF16, 128> ToBuf(NumBytes); const UTF8 *FromPtr = (UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; @@ -1665,7 +1721,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map, AsBytes.push_back(0); IsUTF16 = true; - return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size())); + return Map.GetOrCreateValue(StringRef(AsBytes.data(), AsBytes.size())); } static llvm::StringMapEntry<llvm::Constant*> & @@ -1673,7 +1729,7 @@ GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map, const StringLiteral *Literal, unsigned &StringLength) { - llvm::StringRef String = Literal->getString(); + StringRef String = Literal->getString(); StringLength = String.size(); return Map.GetOrCreateValue(String); } @@ -1696,18 +1752,18 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { - const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); Ty = llvm::ArrayType::get(Ty, 0); llvm::Constant *GV = CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"); // Decay array -> ptr CFConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + llvm::ConstantExpr::getGetElementPtr(GV, Zeros); } QualType CFTy = getContext().getCFConstantStringType(); - const llvm::StructType *STy = + llvm::StructType *STy = cast<llvm::StructType>(getTypes().ConvertType(CFTy)); std::vector<llvm::Constant*> Fields(4); @@ -1716,7 +1772,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { Fields[0] = CFConstantStringClassRef; // Flags. - const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); + llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) : llvm::ConstantInt::get(Ty, 0x07C8); @@ -1750,7 +1806,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); } - Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); // String length. Ty = getTypes().ConvertType(getContext().LongTy); @@ -1761,13 +1817,23 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_cfstring_"); - if (const char *Sect = getContext().Target.getCFStringSection()) + if (const char *Sect = getContext().getTargetInfo().getCFStringSection()) GV->setSection(Sect); Entry.setValue(GV); return GV; } +static RecordDecl * +CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, + DeclContext *DC, IdentifierInfo *Id) { + SourceLocation Loc; + if (Ctx.getLangOptions().CPlusPlus) + return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); + else + return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); +} + llvm::Constant * CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { unsigned StringLength = 0; @@ -1784,7 +1850,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { // If we don't already have it, get _NSConstantStringClassReference. if (!ConstantStringClassRef) { std::string StringClass(getLangOptions().ObjCConstantStringClass); - const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); llvm::Constant *GV; if (Features.ObjCNonFragileABI) { std::string str = @@ -1792,25 +1858,54 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { : "OBJC_CLASS_$_" + StringClass; GV = getObjCRuntime().GetClassGlobal(str); // Make sure the result is of the correct type. - const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); ConstantStringClassRef = llvm::ConstantExpr::getBitCast(GV, PTy); } else { std::string str = StringClass.empty() ? "_NSConstantStringClassReference" : "_" + StringClass + "ClassReference"; - const llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); + llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); GV = CreateRuntimeVariable(PTy, str); // Decay array -> ptr ConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + llvm::ConstantExpr::getGetElementPtr(GV, Zeros); } } - - QualType NSTy = getContext().getNSConstantStringType(); - - const llvm::StructType *STy = - cast<llvm::StructType>(getTypes().ConvertType(NSTy)); + + if (!NSConstantStringType) { + // Construct the type for a constant NSString. + RecordDecl *D = CreateRecordDecl(Context, TTK_Struct, + Context.getTranslationUnitDecl(), + &Context.Idents.get("__builtin_NSString")); + D->startDefinition(); + + QualType FieldTypes[3]; + + // const int *isa; + FieldTypes[0] = Context.getPointerType(Context.IntTy.withConst()); + // const char *str; + FieldTypes[1] = Context.getPointerType(Context.CharTy.withConst()); + // unsigned int length; + FieldTypes[2] = Context.UnsignedIntTy; + + // Create fields + for (unsigned i = 0; i < 3; ++i) { + FieldDecl *Field = FieldDecl::Create(Context, D, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + D->addDecl(Field); + } + + D->completeDefinition(); + QualType NSTy = Context.getTagDeclType(D); + NSConstantStringType = cast<llvm::StructType>(getTypes().ConvertType(NSTy)); + } std::vector<llvm::Constant*> Fields(3); @@ -1831,28 +1926,63 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { GV->setUnnamedAddr(true); CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); - Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); // String length. - const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); + llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[2] = llvm::ConstantInt::get(Ty, StringLength); // The struct. - C = llvm::ConstantStruct::get(STy, Fields); + C = llvm::ConstantStruct::get(NSConstantStringType, Fields); GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_nsstring_"); // FIXME. Fix section. if (const char *Sect = Features.ObjCNonFragileABI - ? getContext().Target.getNSStringNonFragileABISection() - : getContext().Target.getNSStringSection()) + ? getContext().getTargetInfo().getNSStringNonFragileABISection() + : getContext().getTargetInfo().getNSStringSection()) GV->setSection(Sect); Entry.setValue(GV); return GV; } +QualType CodeGenModule::getObjCFastEnumerationStateType() { + if (ObjCFastEnumerationStateType.isNull()) { + RecordDecl *D = CreateRecordDecl(Context, TTK_Struct, + Context.getTranslationUnitDecl(), + &Context.Idents.get("__objcFastEnumerationState")); + D->startDefinition(); + + QualType FieldTypes[] = { + Context.UnsignedLongTy, + Context.getPointerType(Context.getObjCIdType()), + Context.getPointerType(Context.UnsignedLongTy), + Context.getConstantArrayType(Context.UnsignedLongTy, + llvm::APInt(32, 5), ArrayType::Normal, 0) + }; + + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(Context, + D, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + D->addDecl(Field); + } + + D->completeDefinition(); + ObjCFastEnumerationStateType = Context.getTagDeclType(D); + } + + return ObjCFastEnumerationStateType; +} + /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { @@ -1864,8 +1994,20 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { // Resize the string to the right size. uint64_t RealLen = CAT->getSize().getZExtValue(); - if (E->isWide()) - RealLen *= Context.Target.getWCharWidth() / Context.getCharWidth(); + switch (E->getKind()) { + case StringLiteral::Ascii: + case StringLiteral::UTF8: + break; + case StringLiteral::Wide: + RealLen *= Context.getTargetInfo().getWCharWidth() / Context.getCharWidth(); + break; + case StringLiteral::UTF16: + RealLen *= Context.getTargetInfo().getChar16Width() / Context.getCharWidth(); + break; + case StringLiteral::UTF32: + RealLen *= Context.getTargetInfo().getChar32Width() / Context.getCharWidth(); + break; + } std::string Str = E->getString().str(); Str.resize(RealLen, '\0'); @@ -1879,8 +2021,11 @@ llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { // FIXME: This can be more efficient. // FIXME: We shouldn't need to bitcast the constant in the wide string case. - llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S)); - if (S->isWide()) { + CharUnits Align = getContext().getTypeAlignInChars(S->getType()); + llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S), + /* GlobalName */ 0, + Align.getQuantity()); + if (S->isWide() || S->isUTF16() || S->isUTF32()) { llvm::Type *DestTy = llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType())); C = llvm::ConstantExpr::getBitCast(C, DestTy); @@ -1900,10 +2045,11 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { /// GenerateWritableString -- Creates storage for a string literal. -static llvm::Constant *GenerateStringLiteral(llvm::StringRef str, +static llvm::GlobalVariable *GenerateStringLiteral(StringRef str, bool constant, CodeGenModule &CGM, - const char *GlobalName) { + const char *GlobalName, + unsigned Alignment) { // Create Constant for this string literal. Don't add a '\0'. llvm::Constant *C = llvm::ConstantArray::get(CGM.getLLVMContext(), str, false); @@ -1913,7 +2059,7 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str, new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant, llvm::GlobalValue::PrivateLinkage, C, GlobalName); - GV->setAlignment(1); + GV->setAlignment(Alignment); GV->setUnnamedAddr(true); return GV; } @@ -1926,8 +2072,9 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str, /// Feature.WriteableStrings. /// /// The result has pointer to array type. -llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str, - const char *GlobalName) { +llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str, + const char *GlobalName, + unsigned Alignment) { bool IsConstant = !Features.WritableStrings; // Get the default prefix if a name wasn't specified. @@ -1936,27 +2083,32 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str, // Don't share any string literals if strings aren't constant. if (!IsConstant) - return GenerateStringLiteral(Str, false, *this, GlobalName); + return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment); - llvm::StringMapEntry<llvm::Constant *> &Entry = + llvm::StringMapEntry<llvm::GlobalVariable *> &Entry = ConstantStringMap.GetOrCreateValue(Str); - if (Entry.getValue()) - return Entry.getValue(); + if (llvm::GlobalVariable *GV = Entry.getValue()) { + if (Alignment > GV->getAlignment()) { + GV->setAlignment(Alignment); + } + return GV; + } // Create a global variable for this. - llvm::Constant *C = GenerateStringLiteral(Str, true, *this, GlobalName); - Entry.setValue(C); - return C; + llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName, Alignment); + Entry.setValue(GV); + return GV; } /// GetAddrOfConstantCString - Returns a pointer to a character /// array containing the literal and a terminating '\0' /// character. The result has pointer to array type. llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str, - const char *GlobalName){ - llvm::StringRef StrWithNull(Str.c_str(), Str.size() + 1); - return GetAddrOfConstantString(StrWithNull, GlobalName); + const char *GlobalName, + unsigned Alignment) { + StringRef StrWithNull(Str.c_str(), Str.size() + 1); + return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment); } /// EmitObjCPropertyImplementations - Emit information for synthesized @@ -1988,9 +2140,8 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } static bool needsDestructMethod(ObjCImplementationDecl *impl) { - ObjCInterfaceDecl *iface - = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface()); - for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); + const ObjCInterfaceDecl *iface = impl->getClassInterface(); + for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); ivar; ivar = ivar->getNextIvar()) if (ivar->getType().isDestructedType()) return true; @@ -2007,8 +2158,10 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { Selector cxxSelector = getContext().Selectors.getSelector(0, &II); ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), - cxxSelector, getContext().VoidTy, 0, D, true, - false, true, false, ObjCMethodDecl::Required); + cxxSelector, getContext().VoidTy, 0, D, + /*isInstance=*/true, /*isVariadic=*/false, + /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); D->setHasCXXStructors(true); @@ -2024,9 +2177,14 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), - D->getLocation(), cxxSelector, + D->getLocation(), + cxxSelector, getContext().getObjCIdType(), 0, - D, true, false, true, false, + D, /*isInstance=*/true, + /*isVariadic=*/false, + /*isSynthesized=*/true, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); @@ -2134,13 +2292,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { } case Decl::ObjCProtocol: - Runtime->GenerateProtocol(cast<ObjCProtocolDecl>(D)); + ObjCRuntime->GenerateProtocol(cast<ObjCProtocolDecl>(D)); break; case Decl::ObjCCategoryImpl: // Categories have properties but don't support synthesize so we // can ignore them here. - Runtime->GenerateCategory(cast<ObjCCategoryImplDecl>(D)); + ObjCRuntime->GenerateCategory(cast<ObjCCategoryImplDecl>(D)); break; case Decl::ObjCImplementation: { @@ -2149,7 +2307,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { Context.ResetObjCLayout(OMD->getClassInterface()); EmitObjCPropertyImplementations(OMD); EmitObjCIvarInitializations(OMD); - Runtime->GenerateClass(OMD); + ObjCRuntime->GenerateClass(OMD); break; } case Decl::ObjCMethod: { @@ -2169,11 +2327,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::FileScopeAsm: { FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D); - llvm::StringRef AsmString = AD->getAsmString()->getString(); + StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); + else if (*--S.end() == '\n') + getModule().setModuleInlineAsm(S + AsmString.str()); else getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; @@ -2191,7 +2351,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, const void *Ptr) { uintptr_t PtrInt = reinterpret_cast<uintptr_t>(Ptr); - const llvm::Type *i64 = llvm::Type::getInt64Ty(Context); + llvm::Type *i64 = llvm::Type::getInt64Ty(Context); return llvm::ConstantInt::get(i64, PtrInt); } @@ -2222,7 +2382,7 @@ void CodeGenModule::EmitDeclMetadata() { llvm::NamedMDNode *GlobalMetadata = 0; // StaticLocalDeclMap - for (llvm::DenseMap<GlobalDecl,llvm::StringRef>::iterator + for (llvm::DenseMap<GlobalDecl,StringRef>::iterator I = MangledDeclNames.begin(), E = MangledDeclNames.end(); I != E; ++I) { llvm::GlobalValue *Addr = getModule().getNamedValue(I->second); @@ -2273,81 +2433,3 @@ void CodeGenModule::EmitCoverageFile() { } } } - -///@name Custom Runtime Function Interfaces -///@{ -// -// FIXME: These can be eliminated once we can have clients just get the required -// AST nodes from the builtin tables. - -llvm::Constant *CodeGenModule::getBlockObjectDispose() { - if (BlockObjectDispose) - return BlockObjectDispose; - - // If we saw an explicit decl, use that. - if (BlockObjectDisposeDecl) { - return BlockObjectDispose = GetAddrOfFunction( - BlockObjectDisposeDecl, - getTypes().GetFunctionType(BlockObjectDisposeDecl)); - } - - // Otherwise construct the function by hand. - llvm::Type *args[] = { Int8PtrTy, Int32Ty }; - const llvm::FunctionType *fty - = llvm::FunctionType::get(VoidTy, args, false); - return BlockObjectDispose = - CreateRuntimeFunction(fty, "_Block_object_dispose"); -} - -llvm::Constant *CodeGenModule::getBlockObjectAssign() { - if (BlockObjectAssign) - return BlockObjectAssign; - - // If we saw an explicit decl, use that. - if (BlockObjectAssignDecl) { - return BlockObjectAssign = GetAddrOfFunction( - BlockObjectAssignDecl, - getTypes().GetFunctionType(BlockObjectAssignDecl)); - } - - // Otherwise construct the function by hand. - llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty }; - const llvm::FunctionType *fty - = llvm::FunctionType::get(VoidTy, args, false); - return BlockObjectAssign = - CreateRuntimeFunction(fty, "_Block_object_assign"); -} - -llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { - if (NSConcreteGlobalBlock) - return NSConcreteGlobalBlock; - - // If we saw an explicit decl, use that. - if (NSConcreteGlobalBlockDecl) { - return NSConcreteGlobalBlock = GetAddrOfGlobalVar( - NSConcreteGlobalBlockDecl, - getTypes().ConvertType(NSConcreteGlobalBlockDecl->getType())); - } - - // Otherwise construct the variable by hand. - return NSConcreteGlobalBlock = - CreateRuntimeVariable(Int8PtrTy, "_NSConcreteGlobalBlock"); -} - -llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { - if (NSConcreteStackBlock) - return NSConcreteStackBlock; - - // If we saw an explicit decl, use that. - if (NSConcreteStackBlockDecl) { - return NSConcreteStackBlock = GetAddrOfGlobalVar( - NSConcreteStackBlockDecl, - getTypes().ConvertType(NSConcreteStackBlockDecl->getType())); - } - - // Otherwise construct the variable by hand. - return NSConcreteStackBlock = - CreateRuntimeVariable(Int8PtrTy, "_NSConcreteStackBlock"); -} - -///@} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index 86fb6d4..8e38a89 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -62,7 +62,7 @@ namespace clang { class VarDecl; class LangOptions; class CodeGenOptions; - class Diagnostic; + class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; class MangleBuffer; @@ -75,6 +75,8 @@ namespace CodeGen { class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; + class CGOpenCLRuntime; + class CGCUDARuntime; class BlockFieldFlags; class FunctionArgList; @@ -129,8 +131,12 @@ namespace CodeGen { /// The width of a pointer into the generic address space. unsigned char PointerWidthInBits; - /// The alignment of a pointer into the generic address space. - unsigned char PointerAlignInBytes; + /// The size and alignment of a pointer into the generic address + /// space. + union { + unsigned char PointerAlignInBytes; + unsigned char PointerSizeInBytes; + }; }; struct RREntrypoints { @@ -212,7 +218,7 @@ class CodeGenModule : public CodeGenTypeCache { llvm::Module &TheModule; const llvm::TargetData &TheTargetData; mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; - Diagnostic &Diags; + DiagnosticsEngine &Diags; CGCXXABI &ABI; CodeGenTypes Types; CodeGenTBAA *TBAA; @@ -221,7 +227,9 @@ class CodeGenModule : public CodeGenTypeCache { CodeGenVTables VTables; friend class CodeGenVTables; - CGObjCRuntime* Runtime; + CGObjCRuntime* ObjCRuntime; + CGOpenCLRuntime* OpenCLRuntime; + CGCUDARuntime* CUDARuntime; CGDebugInfo* DebugInfo; ARCEntrypoints *ARCData; RREntrypoints *RRData; @@ -257,13 +265,17 @@ class CodeGenModule : public CodeGenTypeCache { CtorList GlobalDtors; /// MangledDeclNames - A map of canonical GlobalDecls to their mangled names. - llvm::DenseMap<GlobalDecl, llvm::StringRef> MangledDeclNames; + llvm::DenseMap<GlobalDecl, StringRef> MangledDeclNames; llvm::BumpPtrAllocator MangledNamesAllocator; + /// Global annotations. std::vector<llvm::Constant*> Annotations; + /// Map used to get unique annotation strings. + llvm::StringMap<llvm::Constant*> AnnotationStrings; + llvm::StringMap<llvm::Constant*> CFConstantStringMap; - llvm::StringMap<llvm::Constant*> ConstantStringMap; + llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap; llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap; /// CXXGlobalInits - Global variables with initializers that need to run @@ -279,13 +291,16 @@ class CodeGenModule : public CodeGenTypeCache { /// - Global variables with initializers whose order of initialization /// is set by init_priority attribute. - llvm::SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8> + SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8> PrioritizedCXXGlobalInits; /// CXXGlobalDtors - Global destructor functions and arguments that need to /// run on termination. std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors; + /// @name Cache for Objective-C runtime types + /// @{ + /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; @@ -294,21 +309,29 @@ class CodeGenModule : public CodeGenTypeCache { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *ConstantStringClassRef; + /// \brief The LLVM type corresponding to NSConstantString. + llvm::StructType *NSConstantStringType; + + /// \brief The type used to describe the state of a fast enumeration in + /// Objective-C's for..in loop. + QualType ObjCFastEnumerationStateType; + + /// @} + /// Lazily create the Objective-C runtime void createObjCRuntime(); + void createOpenCLRuntime(); + void createCUDARuntime(); + llvm::LLVMContext &VMContext; /// @name Cache for Blocks Runtime Globals /// @{ - const VarDecl *NSConcreteGlobalBlockDecl; - const VarDecl *NSConcreteStackBlockDecl; llvm::Constant *NSConcreteGlobalBlock; llvm::Constant *NSConcreteStackBlock; - const FunctionDecl *BlockObjectAssignDecl; - const FunctionDecl *BlockObjectDisposeDecl; llvm::Constant *BlockObjectAssign; llvm::Constant *BlockObjectDispose; @@ -322,7 +345,8 @@ class CodeGenModule : public CodeGenTypeCache { /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, - llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags); + llvm::Module &M, const llvm::TargetData &TD, + DiagnosticsEngine &Diags); ~CodeGenModule(); @@ -332,13 +356,25 @@ public: /// getObjCRuntime() - Return a reference to the configured /// Objective-C runtime. CGObjCRuntime &getObjCRuntime() { - if (!Runtime) createObjCRuntime(); - return *Runtime; + if (!ObjCRuntime) createObjCRuntime(); + return *ObjCRuntime; } /// hasObjCRuntime() - Return true iff an Objective-C runtime has /// been configured. - bool hasObjCRuntime() { return !!Runtime; } + bool hasObjCRuntime() { return !!ObjCRuntime; } + + /// getOpenCLRuntime() - Return a reference to the configured OpenCL runtime. + CGOpenCLRuntime &getOpenCLRuntime() { + assert(OpenCLRuntime != 0); + return *OpenCLRuntime; + } + + /// getCUDARuntime() - Return a reference to the configured CUDA runtime. + CGCUDARuntime &getCUDARuntime() { + assert(CUDARuntime != 0); + return *CUDARuntime; + } /// getCXXABI() - Return a reference to the configured C++ ABI. CGCXXABI &getCXXABI() { return ABI; } @@ -369,9 +405,10 @@ public: llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } CodeGenVTables &getVTables() { return VTables; } - Diagnostic &getDiags() const { return Diags; } + VTableContext &getVTableContext() { return VTables.getVTableContext(); } + DiagnosticsEngine &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } - const TargetInfo &getTarget() const { return Context.Target; } + const TargetInfo &getTarget() const { return Context.getTargetInfo(); } llvm::LLVMContext &getLLVMContext() { return VMContext; } const TargetCodeGenInfo &getTargetCodeGenInfo(); bool isTargetDarwin() const; @@ -433,7 +470,7 @@ public: /// variable with the right type will be created and all uses of the old /// variable will be replaced with a bitcast to the new variable. llvm::GlobalVariable * - CreateOrReplaceCXXRuntimeVariable(llvm::StringRef Name, const llvm::Type *Ty, + CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage); /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the @@ -441,14 +478,14 @@ public: /// then it will be greated with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, - const llvm::Type *Ty = 0); + llvm::Type *Ty = 0); /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it. llvm::Constant *GetAddrOfFunction(GlobalDecl GD, - const llvm::Type *Ty = 0, + llvm::Type *Ty = 0, bool ForVTable = false); /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor @@ -544,8 +581,9 @@ public: /// /// \param GlobalName If provided, the name to use for the global /// (if one is created). - llvm::Constant *GetAddrOfConstantString(llvm::StringRef Str, - const char *GlobalName=0); + llvm::Constant *GetAddrOfConstantString(StringRef Str, + const char *GlobalName=0, + unsigned Alignment=1); /// GetAddrOfConstantCString - Returns a pointer to a character array /// containing the literal and a terminating '\0' character. The result has @@ -554,7 +592,12 @@ public: /// \param GlobalName If provided, the name to use for the global (if one is /// created). llvm::Constant *GetAddrOfConstantCString(const std::string &str, - const char *GlobalName=0); + const char *GlobalName=0, + unsigned Alignment=1); + + /// \brief Retrieve the record type that describes the state of an + /// Objective-C fast enumeration loop (for..in). + QualType getObjCFastEnumerationStateType(); /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. @@ -573,8 +616,8 @@ public: llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); - llvm::Function *getIntrinsic(unsigned IID, llvm::ArrayRef<llvm::Type*> Tys = - llvm::ArrayRef<llvm::Type*>()); + llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = + ArrayRef<llvm::Type*>()); /// EmitTopLevelDecl - Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); @@ -584,8 +627,6 @@ public: /// metadata global. void AddUsedGlobal(llvm::GlobalValue *GV); - void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); } - /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global /// destructor function. void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) { @@ -594,14 +635,14 @@ public: /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. - llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty, - llvm::StringRef Name, + llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, + StringRef Name, llvm::Attributes ExtraAttrs = llvm::Attribute::None); /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. - llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty, - llvm::StringRef Name); + llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, + StringRef Name); ///@name Custom Blocks Runtime Interfaces ///@{ @@ -629,11 +670,13 @@ public: /// but not always, an LLVM null constant. llvm::Constant *EmitNullConstant(QualType T); - llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, - const AnnotateAttr *AA, unsigned LineNo); + /// EmitNullConstantForBase - Return a null constant appropriate for + /// zero-initializing a base class with the given type. This is usually, + /// but not always, an LLVM null constant. + llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record); /// Error - Emit a general error that something can't be done. - void Error(SourceLocation loc, llvm::StringRef error); + void Error(SourceLocation loc, StringRef error); /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. @@ -688,7 +731,7 @@ public: AttributeListType &PAL, unsigned &CallingConv); - llvm::StringRef getMangledName(GlobalDecl GD); + StringRef getMangledName(GlobalDecl GD); void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer, const BlockDecl *BD); @@ -709,7 +752,7 @@ public: /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. - CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; + CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const; /// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global /// variable. @@ -719,17 +762,44 @@ public: std::vector<const CXXRecordDecl*> DeferredVTables; + /// Emit all the global annotations. + void EmitGlobalAnnotations(); + + /// Emit an annotation string. + llvm::Constant *EmitAnnotationString(llvm::StringRef Str); + + /// Emit the annotation's translation unit. + llvm::Constant *EmitAnnotationUnit(SourceLocation Loc); + + /// Emit the annotation line number. + llvm::Constant *EmitAnnotationLineNo(SourceLocation L); + + /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the + /// annotation information for a given GlobalValue. The annotation struct is + /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the + /// GlobalValue being annotated. The second field is the constant string + /// created from the AnnotateAttr's annotation. The third field is a constant + /// string containing the name of the translation unit. The fourth field is + /// the line number in the file of the annotated value declaration. + llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, + const AnnotateAttr *AA, + SourceLocation L); + + /// Add global annotations that are set on D, for the global GV. Those + /// annotations are emitted during finalization of the LLVM code. + void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); + private: - llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref); + llvm::GlobalValue *GetGlobalValue(StringRef Ref); - llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName, - const llvm::Type *Ty, + llvm::Constant *GetOrCreateLLVMFunction(StringRef MangledName, + llvm::Type *Ty, GlobalDecl D, bool ForVTable, llvm::Attributes ExtraAttrs = llvm::Attribute::None); - llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName, - const llvm::PointerType *PTy, + llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, + llvm::PointerType *PTy, const VarDecl *D, bool UnnamedAddr = false); @@ -804,8 +874,6 @@ private: /// suitable for use as a LLVM constructor or destructor array. void EmitCtorList(const CtorList &Fns, const char *GlobalName); - void EmitAnnotations(void); - /// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the /// given type. void EmitFundamentalRTTIDescriptor(QualType Type); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp index 53e40b2..887c1ea 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -58,7 +58,7 @@ llvm::MDNode *CodeGenTBAA::getChar() { /// getTBAAInfoForNamedType - Create a TBAA tree node with the given string /// as its identifier, and the given Parent node as its tree parent. -llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr, +llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(StringRef NameStr, llvm::MDNode *Parent, bool Readonly) { // Currently there is only one flag defined - the readonly flag. @@ -75,7 +75,7 @@ llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr, // Create the mdnode. unsigned Len = llvm::array_lengthof(Ops) - !Flags; - return llvm::MDNode::get(VMContext, llvm::ArrayRef<llvm::Value*>(Ops, Len)); + return llvm::MDNode::get(VMContext, llvm::makeArrayRef(Ops, Len)); } static bool TypeHasMayAlias(QualType QTy) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h index c458347..9fe51fb 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h @@ -15,7 +15,7 @@ #ifndef CLANG_CODEGEN_CODEGENTBAA_H #define CLANG_CODEGEN_CODEGENTBAA_H -#include "llvm/LLVMContext.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" namespace llvm { @@ -55,7 +55,7 @@ class CodeGenTBAA { /// considered to be equivalent to it. llvm::MDNode *getChar(); - llvm::MDNode *getTBAAInfoForNamedType(llvm::StringRef NameStr, + llvm::MDNode *getTBAAInfoForNamedType(StringRef NameStr, llvm::MDNode *Parent, bool Readonly = false); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp index 764688f..e0d9218 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp @@ -29,7 +29,7 @@ using namespace CodeGen; CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, const llvm::TargetData &TD, const ABIInfo &Info, CGCXXABI &CXXABI, const CodeGenOptions &CGO) - : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD), + : Context(Ctx), Target(Ctx.getTargetInfo()), TheModule(M), TheTargetData(TD), TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) { SkippedLayout = false; } @@ -47,7 +47,7 @@ CodeGenTypes::~CodeGenTypes() { void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty, - llvm::StringRef suffix) { + StringRef suffix) { llvm::SmallString<256> TypeName; llvm::raw_svector_ostream OS(TypeName); OS << RD->getKindName() << '.'; @@ -263,6 +263,8 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext, const llvm::fltSemantics &format) { + if (&format == &llvm::APFloat::IEEEhalf) + return llvm::Type::getInt16Ty(VMContext); if (&format == &llvm::APFloat::IEEEsingle) return llvm::Type::getFloatTy(VMContext); if (&format == &llvm::APFloat::IEEEdouble) @@ -273,8 +275,7 @@ static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext, return llvm::Type::getPPC_FP128Ty(VMContext); if (&format == &llvm::APFloat::x87DoubleExtended) return llvm::Type::getX86_FP80Ty(VMContext); - assert(0 && "Unknown float format!"); - return 0; + llvm_unreachable("Unknown float format!"); } /// ConvertType - Convert the specified type to its LLVM form. @@ -342,6 +343,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { static_cast<unsigned>(Context.getTypeSize(T))); break; + case BuiltinType::Half: + // Half is special: it might be lowered to i16 (and will be storage-only + // type),. or can be represented as a set of native operations. + + // FIXME: Ask target which kind of half FP it prefers (storage only vs + // native). + ResultType = llvm::Type::getInt16Ty(getLLVMContext()); + break; case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: @@ -418,7 +427,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { } case Type::ConstantArray: { const ConstantArrayType *A = cast<ConstantArrayType>(Ty); - const llvm::Type *EltTy = ConvertTypeForMem(A->getElementType()); + llvm::Type *EltTy = ConvertTypeForMem(A->getElementType()); + + // Lower arrays of undefined struct type to arrays of i8 just to have a + // concrete type. + if (!EltTy->isSized()) { + SkippedLayout = true; + EltTy = llvm::Type::getInt8Ty(getLLVMContext()); + } + ResultType = llvm::ArrayType::get(EltTy, A->getSize().getZExtValue()); break; } @@ -502,7 +519,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { // these. llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(Ty)]; if (!T) - T = llvm::StructType::createNamed(getLLVMContext(), ""); + T = llvm::StructType::create(getLLVMContext()); ResultType = T; break; } @@ -511,15 +528,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { // Protocol qualifications do not influence the LLVM type, we just return a // pointer to the underlying interface type. We don't need to worry about // recursive conversion. - const llvm::Type *T = - ConvertType(cast<ObjCObjectPointerType>(Ty)->getPointeeType()); + llvm::Type *T = + ConvertTypeForMem(cast<ObjCObjectPointerType>(Ty)->getPointeeType()); ResultType = T->getPointerTo(); break; } case Type::Enum: { const EnumDecl *ED = cast<EnumType>(Ty)->getDecl(); - if (ED->isDefinition() || ED->isFixed()) + if (ED->isCompleteDefinition() || ED->isFixed()) return ConvertType(ED->getIntegerType()); // Return a placeholder 'i32' type. This can be changed later when the // type is defined (see UpdateCompletedType), but is likely to be the @@ -541,6 +558,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty)); break; } + + case Type::Atomic: { + ResultType = ConvertTypeForMem(cast<AtomicType>(Ty)->getValueType()); + break; + } } assert(ResultType && "Didn't convert a type?"); @@ -559,7 +581,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { // If we don't have a StructType at all yet, create the forward declaration. if (Entry == 0) { - Entry = llvm::StructType::createNamed(getLLVMContext(), ""); + Entry = llvm::StructType::create(getLLVMContext()); addRecordTypeName(RD, Entry, ""); } llvm::StructType *Ty = Entry; @@ -567,7 +589,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { // If this is still a forward declaration, or the LLVM type is already // complete, there's nothing more to do. RD = RD->getDefinition(); - if (RD == 0 || !Ty->isOpaque()) + if (RD == 0 || !RD->isCompleteDefinition() || !Ty->isOpaque()) return Ty; // If converting this type would cause us to infinitely loop, don't do it! diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h index 7c0fb81..7f0f8ac 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h @@ -93,7 +93,7 @@ class CodeGenTypes { /// a recursive struct conversion, set this to true. bool SkippedLayout; - llvm::SmallVector<const RecordDecl *, 8> DeferredRecords; + SmallVector<const RecordDecl *, 8> DeferredRecords; private: /// TypeCache - This map keeps cache of llvm::Types @@ -138,7 +138,7 @@ public: /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, /// and/or incomplete argument types, this will return the opaque type. - const llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD); + llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*); @@ -190,7 +190,7 @@ public: /// /// \param ArgTys - must all actually be canonical as params const CGFunctionInfo &getFunctionInfo(CanQualType RetTy, - const llvm::SmallVectorImpl<CanQualType> &ArgTys, + const SmallVectorImpl<CanQualType> &ArgTys, const FunctionType::ExtInfo &Info); /// \brief Compute a new LLVM record layout object for the given record. @@ -200,7 +200,7 @@ public: /// addRecordTypeName - Compute a name from the given record decl with an /// optional suffix and name the given LLVM type using it. void addRecordTypeName(const RecordDecl *RD, llvm::StructType *Ty, - llvm::StringRef suffix); + StringRef suffix); public: // These are internal details of CGT that shouldn't be used externally. @@ -211,7 +211,7 @@ public: // These are internal details of CGT that shouldn't be used externally. /// argument types it would be passed as on the provided vector \arg /// ArgTys. See ABIArgInfo::Expand. void GetExpandedTypes(QualType type, - llvm::SmallVectorImpl<llvm::Type*> &expanded); + SmallVectorImpl<llvm::Type*> &expanded); /// IsZeroInitializable - Return whether a type can be /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp index 0c86080f..c3f635a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -96,12 +96,12 @@ public: void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys); + SmallVectorImpl<CanQualType> &ArgTys); void BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys); + SmallVectorImpl<CanQualType> &ArgTys); void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, @@ -131,12 +131,12 @@ public: void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys); + SmallVectorImpl<CanQualType> &ArgTys); void BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType T, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys); + SmallVectorImpl<CanQualType> &ArgTys); void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, @@ -215,11 +215,11 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), FPT->isVariadic()); - const llvm::IntegerType *ptrdiff = getPtrDiffTy(); + llvm::IntegerType *ptrdiff = getPtrDiffTy(); llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); @@ -259,7 +259,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, CGF.EmitBlock(FnVirtual); // Cast the adjusted this to a pointer to vtable pointer and load. - const llvm::Type *VTableTy = Builder.getInt8PtrTy(); + llvm::Type *VTableTy = Builder.getInt8PtrTy(); llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); VTable = Builder.CreateLoad(VTable, "memptr.vtable"); @@ -307,7 +307,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, // Cast the address to the appropriate pointer type, adopting the // address space of the base pointer. - const llvm::Type *PType + llvm::Type *PType = CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); return Builder.CreateBitCast(Addr, PType); } @@ -478,7 +478,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C, llvm::Constant * ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { - const llvm::Type *ptrdiff_t = getPtrDiffTy(); + llvm::Type *ptrdiff_t = getPtrDiffTy(); // Itanium C++ ABI 2.3: // A NULL pointer is represented as -1. @@ -504,16 +504,16 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { MD = MD->getCanonicalDecl(); CodeGenTypes &Types = CGM.getTypes(); - const llvm::Type *ptrdiff_t = getPtrDiffTy(); + llvm::Type *ptrdiff_t = getPtrDiffTy(); // Get the function pointer (or index if this is a virtual function). llvm::Constant *MemPtr[2]; if (MD->isVirtual()) { - uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + uint64_t Index = CGM.getVTableContext().getMethodVTableIndex(MD); const ASTContext &Context = getContext(); CharUnits PointerWidth = - Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); uint64_t VTableOffset = (Index * PointerWidth.getQuantity()); if (IsARM) { @@ -535,7 +535,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { } } else { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); - const llvm::Type *Ty; + llvm::Type *Ty; // Check whether the function has a computable LLVM signature. if (Types.isFuncTypeConvertible(FPT)) { // The function has a computable LLVM signature; use the correct type. @@ -678,7 +678,7 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { ASTContext &Context = getContext(); // 'this' is already there. @@ -692,7 +692,7 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys); ResTy = ArgTys[0]; } @@ -702,7 +702,7 @@ void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { ASTContext &Context = getContext(); // 'this' is already there. @@ -717,7 +717,7 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, CXXDtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys); if (Type != Dtor_Deleting) @@ -784,7 +784,7 @@ void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType); // Destructor thunks in the ARM ABI have indeterminate results. - const llvm::Type *T = + llvm::Type *T = cast<llvm::PointerType>(CGF.ReturnValue->getType())->getElementType(); RValue Undef = RValue::get(llvm::UndefValue::get(T)); return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType); @@ -829,27 +829,7 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr, if (expr->doesUsualArrayDeleteWantSize()) return true; - // Automatic Reference Counting: - // We need an array cookie for pointers with strong or weak lifetime. - if (getContext().getLangOptions().ObjCAutoRefCount && - elementType->isObjCLifetimeType()) { - switch (elementType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - return false; - - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Weak: - return true; - } - } - - // Otherwise, if the class has a non-trivial destructor, it always - // needs a cookie. - const CXXRecordDecl *record = - elementType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); - return (record && !record->hasTrivialDestructor()); + return elementType.isDestructedType(); } CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { @@ -907,7 +887,7 @@ void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF, CharUnits &CookieSize) { // Derive a char* in the same address space as the pointer. unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); - const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); + llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); // If we don't need an array cookie, bail out early. if (!NeedsArrayCookie(expr, ElementType)) { @@ -919,7 +899,7 @@ void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF, QualType SizeTy = getContext().getSizeType(); CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); - const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); CookieSize = std::max(SizeSize, getContext().getTypeAlignInChars(ElementType)); @@ -968,7 +948,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, ASTContext &Ctx = getContext(); CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType()); - const llvm::IntegerType *SizeTy = + llvm::IntegerType *SizeTy = cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType())); // The cookie is always at the start of the buffer. @@ -1000,7 +980,7 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, CharUnits &CookieSize) { // Derive a char* in the same address space as the pointer. unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); - const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); + llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); // If we don't need an array cookie, bail out early. if (!NeedsArrayCookie(expr, ElementType)) { @@ -1012,7 +992,7 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, QualType SizeTy = getContext().getSizeType(); CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); - const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); // The cookie size is always 2 * sizeof(size_t). CookieSize = 2 * SizeSize; @@ -1036,10 +1016,9 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // int __cxa_guard_acquire(__guard *guard_object); - llvm::Type *ArgTys[] = { GuardPtrTy }; - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy), - ArgTys, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); } @@ -1047,10 +1026,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // void __cxa_guard_release(__guard *guard_object); - llvm::Type *ArgTys[] = { GuardPtrTy }; - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - ArgTys, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); } @@ -1058,10 +1036,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, llvm::PointerType *GuardPtrTy) { // void __cxa_guard_abort(__guard *guard_object); - llvm::Type *ArgTys[] = { GuardPtrTy }; - const llvm::FunctionType *FTy = + llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - ArgTys, /*isVarArg=*/false); + GuardPtrTy, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); } @@ -1090,7 +1067,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool threadsafe = (getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl()); - const llvm::IntegerType *GuardTy; + llvm::IntegerType *GuardTy; // If we have a global variable with internal linkage and thread-safe statics // are disabled, we can just let the guard variable be of type i8. @@ -1152,21 +1129,28 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // } } else { // Load the first byte of the guard variable. - const llvm::Type *PtrTy = Builder.getInt8PtrTy(); - llvm::Value *V = - Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp"); - - IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); + llvm::Type *PtrTy = Builder.getInt8PtrTy(); + llvm::LoadInst *LI = + Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy)); + LI->setAlignment(1); + + // Itanium ABI: + // An implementation supporting thread-safety on multiprocessor + // systems must also guarantee that references to the initialized + // object do not occur before the load of the initialization flag. + // + // In LLVM, we do this by marking the load Acquire. + if (threadsafe) + LI->setAtomic(llvm::Acquire); + + IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized"); } llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); - llvm::BasicBlock *NoCheckBlock = EndBlock; - if (threadsafe) NoCheckBlock = CGF.createBasicBlock("init.barrier"); - // Check if the first byte of the guard variable is zero. - Builder.CreateCondBr(IsInitialized, InitCheckBlock, NoCheckBlock); + Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock); CGF.EmitBlock(InitCheckBlock); @@ -1200,23 +1184,5 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable); } - // Emit an acquire memory barrier if using thread-safe statics: - // Itanium ABI: - // An implementation supporting thread-safety on multiprocessor - // systems must also guarantee that references to the initialized - // object do not occur before the load of the initialization flag. - if (threadsafe) { - Builder.CreateBr(EndBlock); - CGF.EmitBlock(NoCheckBlock); - - llvm::Value *_false = Builder.getFalse(); - llvm::Value *_true = Builder.getTrue(); - - Builder.CreateCall5(CGM.getIntrinsic(llvm::Intrinsic::memory_barrier), - /* load-load, load-store */ _true, _true, - /* store-load, store-store */ _false, _false, - /* device or I/O */ _false); - } - CGF.EmitBlock(EndBlock); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 747e5e3..e200e79 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -31,7 +31,7 @@ public: void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { // 'this' is already in place // TODO: 'for base' flag } @@ -39,7 +39,7 @@ public: void BuildDestructorSignature(const CXXDestructorDecl *Ctor, CXXDtorType Type, CanQualType &ResTy, - llvm::SmallVectorImpl<CanQualType> &ArgTys) { + SmallVectorImpl<CanQualType> &ArgTys) { // 'this' is already in place // TODO: 'for base' flag } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp index 4a2c4abbe..793ee91 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp @@ -27,7 +27,7 @@ using namespace clang; namespace { class CodeGeneratorImpl : public CodeGenerator { - Diagnostic &Diags; + DiagnosticsEngine &Diags; llvm::OwningPtr<const llvm::TargetData> TD; ASTContext *Ctx; const CodeGenOptions CodeGenOpts; // Intentionally copied in. @@ -35,7 +35,7 @@ namespace { llvm::OwningPtr<llvm::Module> M; llvm::OwningPtr<CodeGen::CodeGenModule> Builder; public: - CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName, + CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName, const CodeGenOptions &CGO, llvm::LLVMContext& C) : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {} @@ -52,9 +52,9 @@ namespace { virtual void Initialize(ASTContext &Context) { Ctx = &Context; - M->setTargetTriple(Ctx->Target.getTriple().getTriple()); - M->setDataLayout(Ctx->Target.getTargetDescription()); - TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription())); + M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple()); + M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); + TD.reset(new llvm::TargetData(Ctx->getTargetInfo().getTargetDescription())); Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, Diags)); } @@ -112,7 +112,7 @@ namespace { }; } -CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags, +CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, const std::string& ModuleName, const CodeGenOptions &CGO, llvm::LLVMContext& C) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index df2c1bd..e1dc8f7 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -57,12 +57,12 @@ const llvm::TargetData &ABIInfo::getTargetData() const { void ABIArgInfo::dump() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: OS << "Direct Type="; - if (const llvm::Type *Ty = getCoerceToType()) + if (llvm::Type *Ty = getCoerceToType()) Ty->print(OS); else OS << "null"; @@ -87,6 +87,25 @@ void ABIArgInfo::dump() const { TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; } +// If someone can figure out a general rule for this, that would be great. +// It's probably just doomed to be platform-dependent, though. +unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { + // Verified for: + // x86-64 FreeBSD, Linux, Darwin + // x86-32 FreeBSD, Linux, Darwin + // PowerPC Linux, Darwin + // ARM Darwin (*not* EABI) + return 32; +} + +bool TargetCodeGenInfo::isNoProtoCallVariadic(CallingConv CC) const { + // The following conventions are known to require this to be false: + // x86_stdcall + // MIPS + // For everything else, we just prefer false unless we opt out. + return false; +} + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -348,7 +367,7 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { /// UseX86_MMXType - Return true if this is an MMX type that should use the special /// x86_mmx type. -bool UseX86_MMXType(const llvm::Type *IRType) { +bool UseX86_MMXType(llvm::Type *IRType) { // If the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>, use the // special x86_mmx type. return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 && @@ -357,7 +376,7 @@ bool UseX86_MMXType(const llvm::Type *IRType) { } static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, - llvm::StringRef Constraint, + StringRef Constraint, llvm::Type* Ty) { if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) return llvm::Type::getX86_MMXTy(CGF.getLLVMContext()); @@ -428,7 +447,7 @@ public: llvm::Value *Address) const; llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, - llvm::StringRef Constraint, + StringRef Constraint, llvm::Type* Ty) const { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } @@ -724,8 +743,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const { llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *BPP = llvm::PointerType::getUnqual(BP); CGBuilderTy &Builder = CGF.Builder; llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, @@ -765,7 +784,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::LLVMContext &Context = CGF.getLLVMContext(); - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); // 0-7 are the eight integer registers; the order is different @@ -892,7 +911,7 @@ class X86_64ABIInfo : public ABIInfo { /// required strict binary compatibility with older versions of GCC /// may need to exempt themselves. bool honorsRevision0_98() const { - return !getContext().Target.getTriple().isOSDarwin(); + return !getContext().getTargetInfo().getTriple().isOSDarwin(); } public: @@ -932,7 +951,7 @@ public: CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::LLVMContext &Context = CGF.getLLVMContext(); - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); // 0-15 are the 16 integer registers. @@ -943,11 +962,20 @@ public: } llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, - llvm::StringRef Constraint, + StringRef Constraint, llvm::Type* Ty) const { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } + bool isNoProtoCallVariadic(CallingConv CC) const { + // The default CC on x86-64 sets %al to the number of SSA + // registers used, and GCC sets this when calling an unprototyped + // function, so we override the default behavior. + if (CC == CC_Default || CC == CC_C) return true; + + return TargetCodeGenInfo::isNoProtoCallVariadic(CC); + } + }; class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { @@ -964,7 +992,7 @@ public: CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::LLVMContext &Context = CGF.getLLVMContext(); - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); // 0-15 are the 16 integer registers. @@ -1309,8 +1337,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, continue; uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - uint64_t Size = - i->getBitWidth()->EvaluateAsInt(getContext()).getZExtValue(); + uint64_t Size = i->getBitWidthValue(getContext()); uint64_t EB_Lo = Offset / 64; uint64_t EB_Hi = (Offset + Size - 1) / 64; @@ -1489,14 +1516,14 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, /// float member at the specified offset. For example, {int,{float}} has a /// float at offset 4. It is conservatively correct for this routine to return /// false. -static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset, +static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, const llvm::TargetData &TD) { // Base case if we find a float. if (IROffset == 0 && IRType->isFloatTy()) return true; // If this is a struct, recurse into the field at the specified offset. - if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) { + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) { const llvm::StructLayout *SL = TD.getStructLayout(STy); unsigned Elt = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(Elt); @@ -1504,8 +1531,8 @@ static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset, } // If this is an array, recurse into the field at the specified offset. - if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) { - const llvm::Type *EltTy = ATy->getElementType(); + if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) { + llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = TD.getTypeAllocSize(EltTy); IROffset -= IROffset/EltSize*EltSize; return ContainsFloatAtOffset(EltTy, IROffset, TD); @@ -1578,7 +1605,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, } } - if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) { + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) { // If this is a struct, recurse into the field at the specified offset. const llvm::StructLayout *SL = getTargetData().getStructLayout(STy); if (IROffset < SL->getSizeInBytes()) { @@ -1590,7 +1617,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, } } - if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) { + if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = getTargetData().getTypeAllocSize(EltTy); unsigned EltOffset = IROffset/EltSize*EltSize; @@ -1678,7 +1705,7 @@ classifyReturnType(QualType RetTy) const { case SSEUp: case X87Up: - assert(0 && "Invalid classification for lo word."); + llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via // hidden argument. @@ -1732,7 +1759,7 @@ classifyReturnType(QualType RetTy) const { // never occur as a hi class. case Memory: case X87: - assert(0 && "Invalid classification for hi word."); + llvm_unreachable("Invalid classification for hi word."); case ComplexX87: // Previously handled. case NoClass: @@ -1820,7 +1847,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt, case SSEUp: case X87Up: - assert(0 && "Invalid classification for lo word."); + llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 @@ -1864,8 +1891,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt, case Memory: case X87: case ComplexX87: - assert(0 && "Invalid classification for hi word."); - break; + llvm_unreachable("Invalid classification for hi word."); case NoClass: break; @@ -1970,7 +1996,7 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, } // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *Res = CGF.Builder.CreateBitCast(overflow_arg_area, llvm::PointerType::getUnqual(LTy)); @@ -2061,22 +2087,22 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // collect arguments from different places; often what should result in a // simple assembling of a structure from scattered addresses has many more // loads than necessary. Can we clean this up? - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *RegAddr = CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), "reg_save_area"); if (neededInt && neededSSE) { // FIXME: Cleanup. assert(AI.isDirect() && "Unexpected ABI info for mixed regs"); - const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); + llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); llvm::Value *Tmp = CGF.CreateTempAlloca(ST); assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); - const llvm::Type *TyLo = ST->getElementType(0); - const llvm::Type *TyHi = ST->getElementType(1); + llvm::Type *TyLo = ST->getElementType(0); + llvm::Type *TyHi = ST->getElementType(1); assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) && "Unexpected ABI info for mixed regs"); - const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); - const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); + llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); + llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr; @@ -2104,9 +2130,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); llvm::Value *RegAddrHi = CGF.Builder.CreateConstGEP1_32(RegAddrLo, 16); llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext); - const llvm::Type *DblPtrTy = + llvm::Type *DblPtrTy = llvm::PointerType::getUnqual(DoubleTy); - const llvm::StructType *ST = llvm::StructType::get(DoubleTy, + llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, NULL); llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, @@ -2166,7 +2192,7 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { // FIXME: mingw-w64-gcc emits 128-bit struct as i128 if (Size == 128 && - getContext().Target.getTriple().getOS() == llvm::Triple::MinGW32) + getContext().getTargetInfo().getTriple().getOS() == llvm::Triple::MinGW32) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); @@ -2198,8 +2224,8 @@ void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *BPP = llvm::PointerType::getUnqual(BP); CGBuilderTy &Builder = CGF.Builder; llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, @@ -2246,7 +2272,7 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::LLVMContext &Context = CGF.getLLVMContext(); - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); @@ -2300,6 +2326,11 @@ private: public: ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {} + bool isEABI() const { + StringRef Env = getContext().getTargetInfo().getTriple().getEnvironmentName(); + return (Env == "gnueabi" || Env == "eabi"); + } + private: ABIKind getABIKind() const { return Kind; } @@ -2317,11 +2348,15 @@ public: ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) :TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {} + const ARMABIInfo &getABIInfo() const { + return static_cast<const ARMABIInfo&>(TargetCodeGenInfo::getABIInfo()); + } + int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { return 13; } - llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const { + StringRef getARCRetainAutoreleasedReturnValueMarker() const { return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue"; } @@ -2330,7 +2365,7 @@ public: CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::LLVMContext &Context = CGF.getLLVMContext(); - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); // 0-15 are the 16 integer registers. @@ -2338,6 +2373,11 @@ public: return false; } + + unsigned getSizeOfUnwindException() const { + if (getABIInfo().isEABI()) return 88; + return TargetCodeGenInfo::getSizeOfUnwindException(); + } }; } @@ -2354,8 +2394,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // Calling convention as default by an ABI. llvm::CallingConv::ID DefaultCC; - llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName(); - if (Env == "gnueabi" || Env == "eabi") + if (isEABI()) DefaultCC = llvm::CallingConv::ARM_AAPCS; else DefaultCC = llvm::CallingConv::ARM_APCS; @@ -2379,6 +2418,73 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { } } +/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous +/// aggregate. If HAMembers is non-null, the number of base elements +/// contained in the type is returned through it; this is used for the +/// recursive calls that check aggregate component types. +static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, + ASTContext &Context, + uint64_t *HAMembers = 0) { + uint64_t Members; + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members)) + return false; + Members *= AT->getSize().getZExtValue(); + } else if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + if (RD->isUnion() || RD->hasFlexibleArrayMember()) + return false; + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + if (!CXXRD->isAggregate()) + return false; + } + Members = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + uint64_t FldMembers; + if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers)) + return false; + Members += FldMembers; + } + } else { + Members = 1; + if (const ComplexType *CT = Ty->getAs<ComplexType>()) { + Members = 2; + Ty = CT->getElementType(); + } + + // Homogeneous aggregates for AAPCS-VFP must have base types of float, + // double, or 64-bit or 128-bit vectors. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() != BuiltinType::Float && + BT->getKind() != BuiltinType::Double) + return false; + } else if (const VectorType *VT = Ty->getAs<VectorType>()) { + unsigned VecSize = Context.getTypeSize(VT); + if (VecSize != 64 && VecSize != 128) + return false; + } else { + return false; + } + + // The base type must be the same for all members. Vector types of the + // same total size are treated as being equivalent here. + const Type *TyPtr = Ty.getTypePtr(); + if (!Base) + Base = TyPtr; + if (Base != TyPtr && + (!Base->isVectorType() || !TyPtr->isVectorType() || + Context.getTypeSize(Base) != Context.getTypeSize(TyPtr))) + return false; + } + + // Homogeneous Aggregates can have at most 4 members of the base type. + if (HAMembers) + *HAMembers = Members; + return (Members <= 4); +} + ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. @@ -2398,23 +2504,26 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (getABIKind() == ARMABIInfo::AAPCS_VFP) { + // Homogeneous Aggregates need to be expanded. + const Type *Base = 0; + if (isHomogeneousAggregate(Ty, Base, getContext())) + return ABIArgInfo::getExpand(); + } + // Otherwise, pass by coercing to a structure of the appropriate size. // + // FIXME: This is kind of nasty... but there isn't much choice because the ARM + // backend doesn't support byval. // FIXME: This doesn't handle alignment > 64 bits. - const llvm::Type* ElemTy; + llvm::Type* ElemTy; unsigned SizeRegs; - if (getContext().getTypeSizeInChars(Ty) <= CharUnits::fromQuantity(64)) { - ElemTy = llvm::Type::getInt32Ty(getVMContext()); - SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; - } else if (getABIKind() == ARMABIInfo::APCS) { - // Initial ARM ByVal support is APCS-only. - return ABIArgInfo::getIndirect(0, /*ByVal=*/true); - } else { - // FIXME: This is kind of nasty... but there isn't much choice - // because most of the ARM calling conventions don't yet support - // byval. + if (getContext().getTypeAlign(Ty) > 32) { ElemTy = llvm::Type::getInt64Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; + } else { + ElemTy = llvm::Type::getInt32Ty(getVMContext()); + SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; } llvm::Type *STy = @@ -2579,14 +2688,23 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - // FIXME: Need to handle alignment - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *BPP = llvm::PointerType::getUnqual(BP); CGBuilderTy &Builder = CGF.Builder; llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + // Handle address alignment for type alignment > 32 bits + uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8; + if (TyAlign > 4) { + assert((TyAlign & (TyAlign - 1)) == 0 && + "Alignment is not power of 2!"); + llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty); + AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1)); + AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1))); + Addr = Builder.CreateIntToPtr(AddrAsInt, BP); + } llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); @@ -2623,6 +2741,9 @@ class PTXTargetCodeGenInfo : public TargetCodeGenInfo { public: PTXTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new PTXABIInfo(CGT)) {} + + virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const; }; ABIArgInfo PTXABIInfo::classifyReturnType(QualType RetTy) const { @@ -2652,13 +2773,21 @@ void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const { // Calling convention as default by an ABI. llvm::CallingConv::ID DefaultCC; - llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName(); - if (Env == "device") + const LangOptions &LangOpts = getContext().getLangOptions(); + if (LangOpts.OpenCL || LangOpts.CUDA) { + // If we are in OpenCL or CUDA mode, then default to device functions DefaultCC = llvm::CallingConv::PTX_Device; - else - DefaultCC = llvm::CallingConv::PTX_Kernel; - + } else { + // If we are in standard C/C++ mode, use the triple to decide on the default + StringRef Env = + getContext().getTargetInfo().getTriple().getEnvironmentName(); + if (Env == "device") + DefaultCC = llvm::CallingConv::PTX_Device; + else + DefaultCC = llvm::CallingConv::PTX_Kernel; + } FI.setEffectiveCallingConvention(DefaultCC); + } llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -2667,6 +2796,36 @@ llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return 0; } +void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D, + llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const{ + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) return; + + llvm::Function *F = cast<llvm::Function>(GV); + + // Perform special handling in OpenCL mode + if (M.getLangOptions().OpenCL) { + // Use OpenCL function attributes to set proper calling conventions + // By default, all functions are device functions + if (FD->hasAttr<OpenCLKernelAttr>()) { + // OpenCL __kernel functions get a kernel calling convention + F->setCallingConv(llvm::CallingConv::PTX_Kernel); + // And kernel functions are not subject to inlining + F->addFnAttr(llvm::Attribute::NoInline); + } + } + + // Perform special handling in CUDA mode. + if (M.getLangOptions().CUDA) { + // CUDA __global__ functions get a kernel calling convention. Since + // __global__ functions cannot be called from the device, we do not + // need to set the noinline attribute. + if (FD->getAttr<CUDAGlobalAttr>()) + F->setCallingConv(llvm::CallingConv::PTX_Kernel); + } +} + } //===----------------------------------------------------------------------===// @@ -2891,7 +3050,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, // Step 3: Emit ISR vector alias. unsigned Num = attr->getNumber() + 0xffe0; new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage, - "vector_" + llvm::Twine::utohexstr(Num), + "vector_" + Twine::utohexstr(Num), GV, &M.getModule()); } } @@ -2904,6 +3063,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, namespace { class MipsABIInfo : public ABIInfo { + static const unsigned MinABIStackAlignInBytes = 4; public: MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} @@ -2914,10 +3074,13 @@ public: CodeGenFunction &CGF) const; }; +const unsigned MipsABIInfo::MinABIStackAlignInBytes; + class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { + unsigned SizeOfUnwindException; public: - MIPSTargetCodeGenInfo(CodeGenTypes &CGT) - : TargetCodeGenInfo(new MipsABIInfo(CGT)) {} + MIPSTargetCodeGenInfo(CodeGenTypes &CGT, unsigned SZ) + : TargetCodeGenInfo(new MipsABIInfo(CGT)), SizeOfUnwindException(SZ) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { return 29; @@ -2925,6 +3088,10 @@ public: bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const; + + unsigned getSizeOfUnwindException() const { + return SizeOfUnwindException; + } }; } @@ -2934,6 +3101,11 @@ ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const { if (getContext().getTypeSize(Ty) == 0) return ABIArgInfo::getIgnore(); + // Records with non trivial destructors/constructors should not be passed + // by value. + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0); } @@ -2973,7 +3145,37 @@ void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - return 0; + llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; + llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped; + + if (TypeAlign > MinABIStackAlignInBytes) { + llvm::Value *AddrAsInt32 = CGF.Builder.CreatePtrToInt(Addr, CGF.Int32Ty); + llvm::Value *Inc = llvm::ConstantInt::get(CGF.Int32Ty, TypeAlign - 1); + llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -TypeAlign); + llvm::Value *Add = CGF.Builder.CreateAdd(AddrAsInt32, Inc); + llvm::Value *And = CGF.Builder.CreateAnd(Add, Mask); + AddrTyped = CGF.Builder.CreateIntToPtr(And, PTy); + } + else + AddrTyped = Builder.CreateBitCast(Addr, PTy); + + llvm::Value *AlignedAddr = Builder.CreateBitCast(AddrTyped, BP); + TypeAlign = std::max(TypeAlign, MinABIStackAlignInBytes); + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, TypeAlign); + llvm::Value *NextAddr = + Builder.CreateGEP(AlignedAddr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; } bool @@ -2987,7 +3189,7 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, // Everything on MIPS is 4 bytes. Double-precision FP registers // are aliased to pairs of single-precision FP registers. - const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); // 0-31 are the general purpose registers, $0 - $31. @@ -3009,29 +3211,98 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, return false; } +//===----------------------------------------------------------------------===// +// TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults. +// Currently subclassed only to implement custom OpenCL C function attribute +// handling. +//===----------------------------------------------------------------------===// + +namespace { + +class TCETargetCodeGenInfo : public DefaultTargetCodeGenInfo { +public: + TCETargetCodeGenInfo(CodeGenTypes &CGT) + : DefaultTargetCodeGenInfo(CGT) {} + + virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const; +}; + +void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D, + llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const { + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) return; + + llvm::Function *F = cast<llvm::Function>(GV); + + if (M.getLangOptions().OpenCL) { + if (FD->hasAttr<OpenCLKernelAttr>()) { + // OpenCL C Kernel functions are not subject to inlining + F->addFnAttr(llvm::Attribute::NoInline); + + if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) { + + // Convert the reqd_work_group_size() attributes to metadata. + llvm::LLVMContext &Context = F->getContext(); + llvm::NamedMDNode *OpenCLMetadata = + M.getModule().getOrInsertNamedMetadata("opencl.kernel_wg_size_info"); + + SmallVector<llvm::Value*, 5> Operands; + Operands.push_back(F); + + Operands.push_back(llvm::Constant::getIntegerValue( + llvm::Type::getInt32Ty(Context), + llvm::APInt( + 32, + FD->getAttr<ReqdWorkGroupSizeAttr>()->getXDim()))); + Operands.push_back(llvm::Constant::getIntegerValue( + llvm::Type::getInt32Ty(Context), + llvm::APInt( + 32, + FD->getAttr<ReqdWorkGroupSizeAttr>()->getYDim()))); + Operands.push_back(llvm::Constant::getIntegerValue( + llvm::Type::getInt32Ty(Context), + llvm::APInt( + 32, + FD->getAttr<ReqdWorkGroupSizeAttr>()->getZDim()))); + + // Add a boolean constant operand for "required" (true) or "hint" (false) + // for implementing the work_group_size_hint attr later. Currently + // always true as the hint is not yet implemented. + Operands.push_back(llvm::ConstantInt::getTrue(llvm::Type::getInt1Ty(Context))); + + OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands)); + } + } + } +} + +} const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; - // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't - // free it. - - const llvm::Triple &Triple = getContext().Target.getTriple(); + const llvm::Triple &Triple = getContext().getTargetInfo().getTriple(); switch (Triple.getArch()) { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: - return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types)); + return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 24)); + + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 32)); case llvm::Triple::arm: case llvm::Triple::thumb: { ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; - if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) + if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0) Kind = ARMABIInfo::APCS; else if (CodeGenOpts.FloatABI == "hard") Kind = ARMABIInfo::AAPCS_VFP; @@ -3055,8 +3326,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::msp430: return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); + case llvm::Triple::tce: + return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types)); + case llvm::Triple::x86: { - bool DisableMMX = strcmp(getContext().Target.getABI(), "no-mmx") == 0; + bool DisableMMX = strcmp(getContext().getTargetInfo().getABI(), "no-mmx") == 0; if (Triple.isOSDarwin()) return *(TheTargetCodeGenInfo = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h index d5e8884..8f90c7b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h @@ -15,6 +15,8 @@ #ifndef CLANG_CODEGEN_TARGETINFO_H #define CLANG_CODEGEN_TARGETINFO_H +#include "clang/Basic/LLVM.h" +#include "clang/AST/Type.h" #include "llvm/ADT/StringRef.h" namespace llvm { @@ -58,7 +60,7 @@ namespace clang { /// uint64 private_1; /// uint64 private_2; /// }; - unsigned getSizeOfUnwindException() const { return 32; } + virtual unsigned getSizeOfUnwindException() const; /// Controls whether __builtin_extend_pointer should sign-extend /// pointers to uint64_t or zero-extend them (the default). Has @@ -107,7 +109,7 @@ namespace clang { } virtual llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, - llvm::StringRef Constraint, + StringRef Constraint, llvm::Type* Ty) const { return Ty; } @@ -122,9 +124,43 @@ namespace clang { /// a particular instruction sequence. This functions returns /// that instruction sequence in inline assembly, which will be /// empty if none is required. - virtual llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const { + virtual StringRef getARCRetainAutoreleasedReturnValueMarker() const { return ""; } + + /// Determine whether a call to an unprototyped functions under + /// the given calling convention should use the variadic + /// convention or the non-variadic convention. + /// + /// There's a good reason to make a platform's variadic calling + /// convention be different from its non-variadic calling + /// convention: the non-variadic arguments can be passed in + /// registers (better for performance), and the variadic arguments + /// can be passed on the stack (also better for performance). If + /// this is done, however, unprototyped functions *must* use the + /// non-variadic convention, because C99 states that a call + /// through an unprototyped function type must succeed if the + /// function was defined with a non-variadic prototype with + /// compatible parameters. Therefore, splitting the conventions + /// makes it impossible to call a variadic function through an + /// unprototyped type. Since function prototypes came out in the + /// late 1970s, this is probably an acceptable trade-off. + /// Nonetheless, not all platforms are willing to make it, and in + /// particularly x86-64 bends over backwards to make the + /// conventions compatible. + /// + /// The default is false. This is correct whenever: + /// - the conventions are exactly the same, because it does not + /// matter and the resulting IR will be somewhat prettier in + /// certain cases; or + /// - the conventions are substantively different in how they pass + /// arguments, because in this case using the variadic convention + /// will lead to C99 violations. + /// It is not necessarily correct when arguments are passed in the + /// same way and some out-of-band information is passed for the + /// benefit of variadic callees, as is the case for x86-64. + /// In this case the ABI should be consulted. + virtual bool isNoProtoCallVariadic(CallingConv CC) const; }; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp index 549ce0a..52c0dbb 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Action.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Action.h" +#include "llvm/Support/ErrorHandling.h" #include <cassert> using namespace clang::driver; @@ -31,10 +32,10 @@ const char *Action::getClassName(ActionClass AC) { case LinkJobClass: return "linker"; case LipoJobClass: return "lipo"; case DsymutilJobClass: return "dsymutil"; + case VerifyJobClass: return "verify"; } - assert(0 && "invalid class"); - return 0; + llvm_unreachable("invalid class"); } InputAction::InputAction(const Arg &_Input, types::ID _Type) @@ -84,3 +85,7 @@ LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type) : JobAction(DsymutilJobClass, Inputs, Type) { } + +VerifyJobAction::VerifyJobAction(ActionList &Inputs, types::ID Type) + : JobAction(VerifyJobClass, Inputs, Type) { +} diff --git a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp index b8af9cc..ca9b944 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp @@ -46,6 +46,17 @@ void ArgList::append(Arg *A) { Args.push_back(A); } +void ArgList::eraseArg(OptSpecifier Id) { + for (iterator it = begin(), ie = end(); it != ie; ) { + if ((*it)->getOption().matches(Id)) { + it = Args.erase(it); + ie = end(); + } else { + ++it; + } + } +} + Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const { // FIXME: Make search efficient? for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) @@ -117,19 +128,19 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { return Default; } -llvm::StringRef ArgList::getLastArgValue(OptSpecifier Id, - llvm::StringRef Default) const { +StringRef ArgList::getLastArgValue(OptSpecifier Id, + StringRef Default) const { if (Arg *A = getLastArg(Id)) return A->getValue(*this); return Default; } int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, - clang::Diagnostic &Diags) const { + clang::DiagnosticsEngine &Diags) const { int Res = Default; if (Arg *A = getLastArg(Id)) { - if (llvm::StringRef(A->getValue(*this)).getAsInteger(10, Res)) + if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) Diags.Report(diag::err_drv_invalid_int_value) << A->getAsString(*this) << A->getValue(*this); } @@ -138,7 +149,7 @@ int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, } std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const { - llvm::SmallVector<const char *, 16> Values; + SmallVector<const char *, 16> Values; AddAllArgValues(Values, Id); return std::vector<std::string>(Values.begin(), Values.end()); } @@ -177,7 +188,7 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, (*it)->claim(); if (Joined) { - Output.push_back(MakeArgString(llvm::StringRef(Translation) + + Output.push_back(MakeArgString(StringRef(Translation) + (*it)->getValue(*this, 0))); } else { Output.push_back(Translation); @@ -192,16 +203,22 @@ void ArgList::ClaimAllArgs(OptSpecifier Id0) const { (*it)->claim(); } -const char *ArgList::MakeArgString(const llvm::Twine &T) const { +void ArgList::ClaimAllArgs() const { + for (const_iterator it = begin(), ie = end(); it != ie; ++it) + if (!(*it)->isClaimed()) + (*it)->claim(); +} + +const char *ArgList::MakeArgString(const Twine &T) const { llvm::SmallString<256> Str; T.toVector(Str); return MakeArgString(Str.str()); } const char *ArgList::GetOrMakeJoinedArgString(unsigned Index, - llvm::StringRef LHS, - llvm::StringRef RHS) const { - llvm::StringRef Cur = getArgString(Index); + StringRef LHS, + StringRef RHS) const { + StringRef Cur = getArgString(Index); if (Cur.size() == LHS.size() + RHS.size() && Cur.startswith(LHS) && Cur.endswith(RHS)) return Cur.data(); @@ -223,7 +240,7 @@ InputArgList::~InputArgList() { delete *it; } -unsigned InputArgList::MakeIndex(llvm::StringRef String0) const { +unsigned InputArgList::MakeIndex(StringRef String0) const { unsigned Index = ArgStrings.size(); // Tuck away so we have a reliable const char *. @@ -233,8 +250,8 @@ unsigned InputArgList::MakeIndex(llvm::StringRef String0) const { return Index; } -unsigned InputArgList::MakeIndex(llvm::StringRef String0, - llvm::StringRef String1) const { +unsigned InputArgList::MakeIndex(StringRef String0, + StringRef String1) const { unsigned Index0 = MakeIndex(String0); unsigned Index1 = MakeIndex(String1); assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!"); @@ -242,7 +259,7 @@ unsigned InputArgList::MakeIndex(llvm::StringRef String0, return Index0; } -const char *InputArgList::MakeArgString(llvm::StringRef Str) const { +const char *InputArgList::MakeArgString(StringRef Str) const { return getArgString(MakeIndex(Str)); } @@ -259,7 +276,7 @@ DerivedArgList::~DerivedArgList() { delete *it; } -const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const { +const char *DerivedArgList::MakeArgString(StringRef Str) const { return BaseArgs.MakeArgString(Str); } @@ -270,7 +287,7 @@ Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const { } Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, - llvm::StringRef Value) const { + StringRef Value) const { unsigned Index = BaseArgs.MakeIndex(Value); Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg); SynthesizedArgs.push_back(A); @@ -278,7 +295,7 @@ Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, } Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, - llvm::StringRef Value) const { + StringRef Value) const { unsigned Index = BaseArgs.MakeIndex(Opt->getName(), Value); Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg); SynthesizedArgs.push_back(A); @@ -286,7 +303,7 @@ Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, } Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt, - llvm::StringRef Value) const { + StringRef Value) const { unsigned Index = BaseArgs.MakeIndex(Opt->getName().str() + Value.str()); Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index) + Opt->getName().size(), diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 2657faa..d02da95 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -16,16 +16,19 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Program.h" #include <sys/stat.h> #include <errno.h> + using namespace clang::driver; +using namespace clang; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), - TranslatedArgs(_TranslatedArgs) { + TranslatedArgs(_TranslatedArgs), Redirects(0) { } Compilation::~Compilation() { @@ -43,6 +46,13 @@ Compilation::~Compilation() { for (ActionList::iterator it = Actions.begin(), ie = Actions.end(); it != ie; ++it) delete *it; + + // Free redirections of stdout/stderr. + if (Redirects) { + delete Redirects[1]; + delete Redirects[2]; + delete [] Redirects; + } } const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, @@ -60,14 +70,14 @@ const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, return *Entry; } -void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, +void Compilation::PrintJob(raw_ostream &OS, const Job &J, const char *Terminator, bool Quote) const { if (const Command *C = dyn_cast<Command>(&J)) { OS << " \"" << C->getExecutable() << '"'; for (ArgStringList::const_iterator it = C->getArguments().begin(), ie = C->getArguments().end(); it != ie; ++it) { OS << ' '; - if (!Quote) { + if (!Quote && !std::strpbrk(*it, " \"\\$")) { OS << *it; continue; } @@ -135,9 +145,9 @@ int Compilation::ExecuteCommand(const Command &C, std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); Argv[C.getArguments().size() + 1] = 0; - if (getDriver().CCCEcho || getDriver().CCPrintOptions || - getArgs().hasArg(options::OPT_v)) { - llvm::raw_ostream *OS = &llvm::errs(); + if ((getDriver().CCCEcho || getDriver().CCPrintOptions || + getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { + raw_ostream *OS = &llvm::errs(); // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the // output stream. @@ -167,7 +177,7 @@ int Compilation::ExecuteCommand(const Command &C, std::string Error; int Res = llvm::sys::Program::ExecuteAndWait(Prog, Argv, - /*env*/0, /*redirects*/0, + /*env*/0, Redirects, /*secondsToWait*/0, /*memoryLimit*/0, &Error); if (!Error.empty()) { @@ -195,3 +205,24 @@ int Compilation::ExecuteJob(const Job &J, return 0; } } + +void Compilation::initCompilationForDiagnostics(void) { + // Free actions and jobs. + DeleteContainerPointers(Actions); + Jobs.clear(); + + // Clear temporary/results file lists. + TempFiles.clear(); + ResultFiles.clear(); + + // Remove any user specified output. Claim any unclaimed arguments, so as + // to avoid emitting warnings about unused args. + if (TranslatedArgs->hasArg(options::OPT_o)) + TranslatedArgs->eraseArg(options::OPT_o); + TranslatedArgs->ClaimAllArgs(); + + // Redirect stdout/stderr to /dev/null. + Redirects = new const llvm::sys::Path*[3](); + Redirects[1] = new const llvm::sys::Path(); + Redirects[2] = new const llvm::sys::Path(); +} diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 0860572..4e2d7b6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -25,7 +25,6 @@ #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" -#include "clang/Driver/Types.h" #include "clang/Basic/Version.h" @@ -33,6 +32,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/FileSystem.h" @@ -46,11 +46,11 @@ using namespace clang::driver; using namespace clang; -Driver::Driver(llvm::StringRef ClangExecutable, - llvm::StringRef DefaultHostTriple, - llvm::StringRef DefaultImageName, - bool IsProduction, bool CXXIsProduction, - Diagnostic &Diags) +Driver::Driver(StringRef ClangExecutable, + StringRef DefaultHostTriple, + StringRef DefaultImageName, + bool IsProduction, + DiagnosticsEngine &Diags) : Opts(createDriverOptTable()), Diags(Diags), ClangExecutable(ClangExecutable), UseStdLib(true), DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName), @@ -60,9 +60,9 @@ Driver::Driver(llvm::StringRef ClangExecutable, CCLogDiagnosticsFilename(0), CCCIsCXX(false), CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), - CCCGenericGCCName(""), CheckInputsExist(true), CCCUseClang(true), - CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), - SuppressMissingInputWarning(false) { + CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), + CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true), + CCCUsePCH(true), SuppressMissingInputWarning(false) { if (IsProduction) { // In a "production" build, only use clang on architectures we expect to // work, and don't use clang C++. @@ -73,16 +73,13 @@ Driver::Driver(llvm::StringRef ClangExecutable, CCCClangArchs.insert(llvm::Triple::x86); CCCClangArchs.insert(llvm::Triple::x86_64); CCCClangArchs.insert(llvm::Triple::arm); - - if (!CXXIsProduction) - CCCUseClangCXX = false; } Name = llvm::sys::path::stem(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); // Compute the path to the resource directory. - llvm::StringRef ClangResourceDir(CLANG_RESOURCE_DIR); + StringRef ClangResourceDir(CLANG_RESOURCE_DIR); llvm::SmallString<128> P(Dir); if (ClangResourceDir != "") llvm::sys::path::append(P, ClangResourceDir); @@ -96,7 +93,7 @@ Driver::~Driver() { delete Host; } -InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) { +InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); unsigned MissingArgIndex, MissingArgCount; InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), @@ -120,6 +117,43 @@ InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) { return Args; } +// Determine which compilation mode we are in. We look for options which +// affect the phase, starting with the earliest phases, and record which +// option we used to determine the final phase. +phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg) +const { + Arg *PhaseArg = 0; + phases::ID FinalPhase; + + // -{E,M,MM} only run the preprocessor. + if (CCCIsCPP || + (PhaseArg = DAL.getLastArg(options::OPT_E)) || + (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) { + FinalPhase = phases::Preprocess; + + // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || + (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || + (PhaseArg = DAL.getLastArg(options::OPT__analyze, + options::OPT__analyze_auto)) || + (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || + (PhaseArg = DAL.getLastArg(options::OPT_S))) { + FinalPhase = phases::Compile; + + // -c only runs up to the assembler. + } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { + FinalPhase = phases::Assemble; + + // Otherwise do everything. + } else + FinalPhase = phases::Link; + + if (FinalPhaseArg) + *FinalPhaseArg = PhaseArg; + + return FinalPhase; +} + DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DerivedArgList *DAL = new DerivedArgList(Args); @@ -142,7 +176,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Add the remaining values as Xlinker arguments. for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - if (llvm::StringRef(A->getValue(Args, i)) != "--no-demangle") + if (StringRef(A->getValue(Args, i)) != "--no-demangle") DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker), A->getValue(Args, i)); @@ -154,10 +188,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // care to encourage this usage model. if (A->getOption().matches(options::OPT_Wp_COMMA) && A->getNumValues() == 2 && - (A->getValue(Args, 0) == llvm::StringRef("-MD") || - A->getValue(Args, 0) == llvm::StringRef("-MMD"))) { + (A->getValue(Args, 0) == StringRef("-MD") || + A->getValue(Args, 0) == StringRef("-MMD"))) { // Rewrite to -MD/-MMD along with -MF. - if (A->getValue(Args, 0) == llvm::StringRef("-MD")) + if (A->getValue(Args, 0) == StringRef("-MD")) DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD)); else DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD)); @@ -168,7 +202,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Rewrite reserved library names. if (A->getOption().matches(options::OPT_l)) { - llvm::StringRef Value = A->getValue(Args); + StringRef Value = A->getValue(Args); // Rewrite unless -nostdlib is present. if (!HasNostdlib && Value == "stdc++") { @@ -201,12 +235,20 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { return DAL; } -Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) { +Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); - // FIXME: Handle environment options which effect driver behavior, somewhere - // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH, - // CC_PRINT_OPTIONS. + // FIXME: Handle environment options which affect driver behavior, somewhere + // (client?). GCC_EXEC_PREFIX, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS. + + if (char *env = ::getenv("COMPILER_PATH")) { + StringRef CompilerPath = env; + while (!CompilerPath.empty()) { + std::pair<StringRef, StringRef> Split = CompilerPath.split(':'); + PrefixDirs.push_back(Split.first); + CompilerPath = Split.second; + } + } // FIXME: What are we going to do with -V and -b? @@ -242,11 +284,11 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) { CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang); CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp); if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) { - llvm::StringRef Cur = A->getValue(*Args); + StringRef Cur = A->getValue(*Args); CCCClangArchs.clear(); while (!Cur.empty()) { - std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(','); + std::pair<StringRef, StringRef> Split = Cur.split(','); if (!Split.first.empty()) { llvm::Triple::ArchType Arch = @@ -296,12 +338,17 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) { if (!HandleImmediateArgs(*C)) return C; + // Construct the list of inputs. + InputList Inputs; + BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs); + // Construct the list of abstract actions to perform for this compilation. if (Host->useDriverDriver()) BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(), - C->getActions()); + Inputs, C->getActions()); else - BuildActions(C->getDefaultToolChain(), C->getArgs(), C->getActions()); + BuildActions(C->getDefaultToolChain(), C->getArgs(), Inputs, + C->getActions()); if (CCCPrintActions) { PrintActions(*C); @@ -313,7 +360,112 @@ Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) { return C; } -int Driver::ExecuteCompilation(const Compilation &C) const { +// When clang crashes, produce diagnostic information including the fully +// preprocessed source file(s). Request that the developer attach the +// diagnostic information to a bug report. +void Driver::generateCompilationDiagnostics(Compilation &C, + const Command *FailingCommand) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Please submit a bug report to " BUG_REPORT_URL " and include command" + " line arguments and all diagnostic information."; + + // Suppress driver output and emit preprocessor output to temp file. + CCCIsCPP = true; + CCGenDiagnostics = true; + + // Clear stale state and suppress tool output. + C.initCompilationForDiagnostics(); + Diags.Reset(); + + // Construct the list of inputs. + InputList Inputs; + BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs); + + for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) { + bool IgnoreInput = false; + + // Ignore input from stdin or any inputs that cannot be preprocessed. + if (!strcmp(it->second->getValue(C.getArgs()), "-")) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s) - ignoring input from stdin" + "."; + IgnoreInput = true; + } else if (types::getPreprocessedType(it->first) == types::TY_INVALID) { + IgnoreInput = true; + } + + if (IgnoreInput) { + it = Inputs.erase(it); + ie = Inputs.end(); + } else { + ++it; + } + } + + // Don't attempt to generate preprocessed files if multiple -arch options are + // used. + int Archs = 0; + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); + it != ie; ++it) { + Arg *A = *it; + if (A->getOption().matches(options::OPT_arch)) { + Archs++; + if (Archs > 1) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s) - cannot generate " + "preprocessed source with multiple -arch options."; + return; + } + } + } + + if (Inputs.empty()) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s) - no preprocessable inputs."; + return; + } + + // Construct the list of abstract actions to perform for this compilation. + if (Host->useDriverDriver()) + BuildUniversalActions(C.getDefaultToolChain(), C.getArgs(), + Inputs, C.getActions()); + else + BuildActions(C.getDefaultToolChain(), C.getArgs(), Inputs, + C.getActions()); + + BuildJobs(C); + + // If there were errors building the compilation, quit now. + if (Diags.hasErrorOccurred()) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s)."; + return; + } + + // Generate preprocessed output. + FailingCommand = 0; + int Res = C.ExecuteJob(C.getJobs(), FailingCommand); + + // If the command succeeded, we are done. + if (Res == 0) { + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Preprocessed source(s) are located at:"; + ArgStringList Files = C.getTempFiles(); + for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); + it != ie; ++it) + Diag(clang::diag::note_drv_command_failed_diag_msg) << *it; + } else { + // Failure, remove preprocessed files. + if (!C.getArgs().hasArg(options::OPT_save_temps)) + C.CleanupFileList(C.getTempFiles(), true); + + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "Error generating preprocessed source(s)."; + } +} + +int Driver::ExecuteCompilation(const Compilation &C, + const Command *&FailingCommand) const { // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.PrintJob(llvm::errs(), C.getJobs(), "\n", true); @@ -321,10 +473,9 @@ int Driver::ExecuteCompilation(const Compilation &C) const { } // If there were errors building the compilation, quit now. - if (getDiags().hasErrorOccurred()) + if (Diags.hasErrorOccurred()) return 1; - const Command *FailingCommand = 0; int Res = C.ExecuteJob(C.getJobs(), FailingCommand); // Remove temp files. @@ -382,7 +533,7 @@ void Driver::PrintHelp(bool ShowHidden) const { ShowHidden); } -void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { +void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. OS << getClangFullVersion() << '\n'; @@ -397,7 +548,7 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { /// PrintDiagnosticCategories - Implement the --print-diagnostic-categories /// option. -static void PrintDiagnosticCategories(llvm::raw_ostream &OS) { +static void PrintDiagnosticCategories(raw_ostream &OS) { // Skip the empty category. for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories(); i != max; ++i) @@ -457,7 +608,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { llvm::outs() << *it; } llvm::outs() << "\n"; - llvm::outs() << "libraries: ="; + llvm::outs() << "libraries: =" << ResourceDir; std::string sysroot; if (Arg *A = C.getArgs().getLastArg(options::OPT__sysroot_EQ)) @@ -465,8 +616,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), ie = TC.getFilePaths().end(); it != ie; ++it) { - if (it != TC.getFilePaths().begin()) - llvm::outs() << ':'; + llvm::outs() << ':'; const char *path = it->c_str(); if (path[0] == '=') llvm::outs() << sysroot << path + 1; @@ -594,12 +744,13 @@ static bool ContainsCompileOrAssembleAction(const Action *A) { void Driver::BuildUniversalActions(const ToolChain &TC, const DerivedArgList &Args, + const InputList &BAInputs, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); // Collect the list of architectures. Duplicates are allowed, but should only // be handled once (in the order seen). llvm::StringSet<> ArchNames; - llvm::SmallVector<const char *, 4> Archs; + SmallVector<const char *, 4> Archs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -638,7 +789,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, } ActionList SingleActions; - BuildActions(TC, Args, SingleActions); + BuildActions(TC, Args, BAInputs, SingleActions); // Add in arch bindings for every top level action, as well as lipo and // dsymutil steps if needed. @@ -683,23 +834,33 @@ void Driver::BuildUniversalActions(const ToolChain &TC, Actions.pop_back(); Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM)); + + // Verify the debug output if we're in assert mode. + // TODO: The verifier is noisy by default so put this under an + // option for now. + #ifndef NDEBUG + if (Args.hasArg(options::OPT_verify)) { + ActionList VerifyInputs; + VerifyInputs.push_back(Actions.back()); + Actions.pop_back(); + Actions.push_back(new VerifyJobAction(VerifyInputs, + types::TY_Nothing)); + } + #endif } } } } -void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, - ActionList &Actions) const { - llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); - // Start by constructing the list of inputs and their types. - +// Construct a the list of inputs and their types. +void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, + InputList &Inputs) const { // Track the current user specified (-x) input. We also explicitly track the // argument used to set the type; we only want to claim the type when we // actually use it, so we warn about unused -x arguments. types::ID InputType = types::TY_Nothing; Arg *InputTypeArg = 0; - llvm::SmallVector<std::pair<types::ID, const Arg*>, 16> Inputs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -803,7 +964,6 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, } } } - if (CCCIsCPP && Inputs.empty()) { // If called as standalone preprocessor, stdin is processed // if no other input is present. @@ -812,40 +972,19 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, A->claim(); Inputs.push_back(std::make_pair(types::TY_C, A)); } +} + +void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const { + llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); if (!SuppressMissingInputWarning && Inputs.empty()) { Diag(clang::diag::err_drv_no_input_files); return; } - // Determine which compilation mode we are in. We look for options which - // affect the phase, starting with the earliest phases, and record which - // option we used to determine the final phase. - Arg *FinalPhaseArg = 0; - phases::ID FinalPhase; - - // -{E,M,MM} only run the preprocessor. - if (CCCIsCPP || - (FinalPhaseArg = Args.getLastArg(options::OPT_E)) || - (FinalPhaseArg = Args.getLastArg(options::OPT_M, options::OPT_MM))) { - FinalPhase = phases::Preprocess; - - // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. - } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || - (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) || - (FinalPhaseArg = Args.getLastArg(options::OPT__analyze, - options::OPT__analyze_auto)) || - (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) || - (FinalPhaseArg = Args.getLastArg(options::OPT_S))) { - FinalPhase = phases::Compile; - - // -c only runs up to the assembler. - } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) { - FinalPhase = phases::Assemble; - - // Otherwise do everything. - } else - FinalPhase = phases::Link; + Arg *FinalPhaseArg; + phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); // Reject -Z* at the top level, these options should never have been exposed // by gcc. @@ -935,7 +1074,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, llvm::PrettyStackTraceString CrashInfo("Constructing phase actions"); // Build the appropriate action. switch (Phase) { - case phases::Link: assert(0 && "link action invalid here."); + case phases::Link: llvm_unreachable("link action invalid here."); case phases::Preprocess: { types::ID OutputTy; // -{M, MM} alter the output type. @@ -971,8 +1110,7 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, return new AssembleJobAction(Input, types::TY_Object); } - assert(0 && "invalid phase in ConstructPhaseAction"); - return 0; + llvm_unreachable("invalid phase in ConstructPhaseAction"); } bool Driver::IsUsingLTO(const ArgList &Args) const { @@ -1048,7 +1186,8 @@ void Driver::BuildJobs(Compilation &C) const { Arg *A = *it; // FIXME: It would be nice to be able to send the argument to the - // Diagnostic, so that extra values, position, and so on could be printed. + // DiagnosticsEngine, so that extra values, position, and so on could be + // printed. if (!A->isClaimed()) { if (A->getOption().hasNoArgumentUnused()) continue; @@ -1091,7 +1230,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) || C.getArgs().hasArg(options::OPT_static) || C.getArgs().hasArg(options::OPT_fapple_kext)); - bool IsDarwin = TC->getTriple().getOS() == llvm::Triple::Darwin; + bool IsDarwin = TC->getTriple().isOSDarwin(); bool IsIADefault = TC->IsIntegratedAssemblerDefault() && !(HasStatic && IsDarwin); if (C.getArgs().hasFlag(options::OPT_integrated_as, @@ -1176,6 +1315,11 @@ void Driver::BuildJobsForAction(Compilation &C, if (AtTopLevel && isa<DsymutilJobAction>(A)) SubJobAtTopLevel = true; + // Also treat verify sub-jobs as being at the top-level. They don't + // produce any output and so don't need temporary output names. + if (AtTopLevel && isa<VerifyJobAction>(A)) + SubJobAtTopLevel = true; + InputInfo II; BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, LinkingOutput, II); @@ -1198,7 +1342,7 @@ void Driver::BuildJobsForAction(Compilation &C, A->getType(), BaseInput); } - if (CCCPrintBindings) { + if (CCCPrintBindings && !CCGenDiagnostics) { llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"' << " - \"" << T.getName() << "\", inputs: ["; for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) { @@ -1219,27 +1363,31 @@ const char *Driver::GetNamedOutputPath(Compilation &C, bool AtTopLevel) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? - if (AtTopLevel && !isa<DsymutilJobAction>(JA)) { + if (AtTopLevel && !isa<DsymutilJobAction>(JA) && + !isa<VerifyJobAction>(JA)) { if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) return C.addResultFile(FinalOutput->getValue(C.getArgs())); } // Default to writing to stdout? - if (AtTopLevel && isa<PreprocessJobAction>(JA)) + if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics) return "-"; // Output to a temporary file? - if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) { + if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) || + CCGenDiagnostics) { + StringRef Name = llvm::sys::path::filename(BaseInput); + std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = - GetTemporaryPath(types::getTypeTempSuffix(JA.getType())); + GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); } llvm::SmallString<128> BasePath(BaseInput); - llvm::StringRef BaseName; + StringRef BaseName; // Dsymutil actions should use the full path. - if (isa<DsymutilJobAction>(JA)) + if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA)) BaseName = BasePath; else BaseName = llvm::sys::path::filename(BasePath); @@ -1261,12 +1409,14 @@ const char *Driver::GetNamedOutputPath(Compilation &C, NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str()); } - // If we're saving temps and the temp filename conflicts with the input + // If we're saving temps and the temp filename conflicts with the input // filename, then avoid overwriting input file. if (!AtTopLevel && C.getArgs().hasArg(options::OPT_save_temps) && - NamedOutput == BaseName) { + NamedOutput == BaseName) { + StringRef Name = llvm::sys::path::filename(BaseInput); + std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = - GetTemporaryPath(types::getTypeTempSuffix(JA.getType())); + GetTemporaryPath(Split.first, types::getTypeTempSuffix(JA.getType())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); } @@ -1300,6 +1450,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { return P.str(); } + llvm::sys::Path P(ResourceDir); + P.appendComponent(Name); + bool Exists; + if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) + return P.str(); + const ToolChain::path_list &List = TC.getFilePaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { @@ -1318,40 +1474,53 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { return Name; } +static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) { + bool Exists; + return (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists + : P.canExecute()); +} + std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC, bool WantFile) const { + std::string TargetSpecificExecutable(DefaultHostTriple + "-" + Name); // Respect a limited subset of the '-Bprefix' functionality in GCC by // attempting to use this prefix when lokup up program paths. for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), ie = PrefixDirs.end(); it != ie; ++it) { llvm::sys::Path P(*it); + P.appendComponent(TargetSpecificExecutable); + if (isPathExecutable(P, WantFile)) return P.str(); + P.eraseComponent(); P.appendComponent(Name); - bool Exists; - if (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists - : P.canExecute()) - return P.str(); + if (isPathExecutable(P, WantFile)) return P.str(); } const ToolChain::path_list &List = TC.getProgramPaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { llvm::sys::Path P(*it); + P.appendComponent(TargetSpecificExecutable); + if (isPathExecutable(P, WantFile)) return P.str(); + P.eraseComponent(); P.appendComponent(Name); - bool Exists; - if (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists - : P.canExecute()) - return P.str(); + if (isPathExecutable(P, WantFile)) return P.str(); } // If all else failed, search the path. - llvm::sys::Path P(llvm::sys::Program::FindProgramByName(Name)); + llvm::sys::Path + P(llvm::sys::Program::FindProgramByName(TargetSpecificExecutable)); + if (!P.empty()) + return P.str(); + + P = llvm::sys::Path(llvm::sys::Program::FindProgramByName(Name)); if (!P.empty()) return P.str(); return Name; } -std::string Driver::GetTemporaryPath(const char *Suffix) const { +std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix) + const { // FIXME: This is lame; sys::Path should provide this function (in particular, // it should know how to find the temporary files dir). std::string Error; @@ -1363,7 +1532,7 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const { if (!TmpDir) TmpDir = "/tmp"; llvm::sys::Path P(TmpDir); - P.appendComponent("cc"); + P.appendComponent(Prefix); if (P.makeUnique(false, &Error)) { Diag(clang::diag::err_drv_unable_to_make_temp) << Error; return ""; @@ -1388,6 +1557,8 @@ const HostInfo *Driver::GetHostInfo(const char *TripleStr) const { case llvm::Triple::AuroraUX: return createAuroraUXHostInfo(*this, Triple); case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: return createDarwinHostInfo(*this, Triple); case llvm::Triple::DragonFly: return createDragonFlyHostInfo(*this, Triple); diff --git a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp index 3b1c2c7..292678b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp @@ -188,7 +188,7 @@ bool UnknownHostInfo::useDriverDriver() const { ToolChain *UnknownHostInfo::CreateToolChain(const ArgList &Args, const char *ArchName) const { assert(!ArchName && - "Unexpected arch name on platform without driver driver support."); + "Unexpected arch name on platform without driver support."); // Automatically handle some instances of -m32/-m64 we know about. std::string Arch = getArchName(); diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 51055e9..5443d70 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -9,6 +9,8 @@ #include "clang/Driver/Job.h" +#include "llvm/ADT/STLExtras.h" + #include <cassert> using namespace clang::driver; @@ -28,6 +30,10 @@ JobList::~JobList() { delete *it; } +void JobList::clear() { + DeleteContainerPointers(Jobs); +} + void Job::addCommand(Command *C) { cast<JobList>(this)->addJob(C); } diff --git a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp index 0252b3e..4f5390b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp @@ -12,11 +12,12 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> -#include <cassert> #include <map> using namespace clang::driver; using namespace clang::driver::options; +using namespace clang; // Ordering on Info. The ordering is *almost* lexicographic, with two // exceptions. First, '\0' comes at the end of the alphabet instead of @@ -116,7 +117,7 @@ OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) if (!(getInfo(i) < getInfo(i + 1))) { getOption(i)->dump(); getOption(i + 1)->dump(); - assert(0 && "Options are not in order!"); + llvm_unreachable("Options are not in order!"); } } #endif @@ -268,10 +269,10 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { // Add metavar, if used. switch (Opts.getOptionKind(Id)) { case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: - assert(0 && "Invalid option with help text."); + llvm_unreachable("Invalid option with help text."); case Option::MultiArgClass: - assert(0 && "Cannot print metavar for this kind of option."); + llvm_unreachable("Cannot print metavar for this kind of option."); case Option::FlagClass: break; @@ -291,7 +292,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { return Name; } -static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title, +static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, std::vector<std::pair<std::string, const char*> > &OptionHelp) { OS << Title << ":\n"; @@ -342,7 +343,7 @@ static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { return getOptionHelpGroup(Opts, GroupID); } -void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name, +void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, bool ShowHidden) const { OS << "OVERVIEW: " << Title << "\n"; OS << '\n'; diff --git a/contrib/llvm/tools/clang/lib/Driver/Option.cpp b/contrib/llvm/tools/clang/lib/Driver/Option.cpp index 90d21a3..ee1963f 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Option.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Option.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include <cassert> #include <algorithm> using namespace clang::driver; @@ -61,7 +62,7 @@ void Option::dump() const { llvm::errs() << "<"; switch (Kind) { default: - assert(0 && "Invalid kind"); + llvm_unreachable("Invalid kind"); #define P(N) case N: llvm::errs() << #N; break P(GroupClass); P(InputClass); @@ -114,8 +115,7 @@ OptionGroup::OptionGroup(OptSpecifier ID, const char *Name, } Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const { - assert(0 && "accept() should never be called on an OptionGroup"); - return 0; + llvm_unreachable("accept() should never be called on an OptionGroup"); } InputOption::InputOption(OptSpecifier ID) @@ -123,8 +123,7 @@ InputOption::InputOption(OptSpecifier ID) } Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const { - assert(0 && "accept() should never be called on an InputOption"); - return 0; + llvm_unreachable("accept() should never be called on an InputOption"); } UnknownOption::UnknownOption(OptSpecifier ID) @@ -132,8 +131,7 @@ UnknownOption::UnknownOption(OptSpecifier ID) } Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const { - assert(0 && "accept() should never be called on an UnknownOption"); - return 0; + llvm_unreachable("accept() should never be called on an UnknownOption"); } FlagOption::FlagOption(OptSpecifier ID, const char *Name, diff --git a/contrib/llvm/tools/clang/lib/Driver/Phases.cpp b/contrib/llvm/tools/clang/lib/Driver/Phases.cpp index f360002..b885eee 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Phases.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Phases.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Phases.h" +#include "llvm/Support/ErrorHandling.h" #include <cassert> @@ -22,6 +23,5 @@ const char *phases::getPhaseName(ID Id) { case Link: return "linker"; } - assert(0 && "Invalid phase id."); - return 0; + llvm_unreachable("Invalid phase id."); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index 74b6591..d09ab16 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -18,11 +18,11 @@ #include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/Options.h" #include "llvm/Support/ErrorHandling.h" - using namespace clang::driver; +using namespace clang; -ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple) - : Host(_Host), Triple(_Triple) { +ToolChain::ToolChain(const HostInfo &H, const llvm::Triple &T) + : Host(H), Triple(T) { } ToolChain::~ToolChain() { @@ -79,7 +79,7 @@ static const char *getARMTargetCPU(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(Args); - llvm::StringRef MArch; + StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(Args); @@ -134,7 +134,7 @@ static const char *getARMTargetCPU(const ArgList &Args, // // FIXME: This is redundant with -mcpu, why does LLVM use this. // FIXME: tblgen this, or kill it! -static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { +static const char *getLLVMArchSuffixForARM(StringRef CPU) { if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" || CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" || CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" || @@ -169,7 +169,8 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { return ""; } -std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const { +std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, + types::ID InputType) const { switch (getTriple().getArch()) { default: return getTripleString(); @@ -182,12 +183,14 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const { // Thumb2 is the default for V7 on Darwin. // // FIXME: Thumb should just be another -target-feaure, not in the triple. - llvm::StringRef Suffix = + StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); - bool ThumbDefault = - (Suffix == "v7" && getTriple().getOS() == llvm::Triple::Darwin); + bool ThumbDefault = (Suffix == "v7" && getTriple().isOSDarwin()); std::string ArchName = "arm"; - if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) + + // Assembly files should start in ARM mode. + if (InputType != types::TY_PP_Asm && + Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) ArchName = "thumb"; Triple.setArchName(ArchName + Suffix.str()); @@ -196,25 +199,26 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const { } } -std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const { +std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { // Diagnose use of Darwin OS deployment target arguments on non-Darwin. if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, options::OPT_miphoneos_version_min_EQ, options::OPT_mios_simulator_version_min_EQ)) - getDriver().Diag(clang::diag::err_drv_clang_unsupported) + getDriver().Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); - return ComputeLLVMTriple(Args); + return ComputeLLVMTriple(Args, InputType); } ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - llvm::StringRef Value = A->getValue(Args); + StringRef Value = A->getValue(Args); if (Value == "libc++") return ToolChain::CST_Libcxx; if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; - getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) + getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 29abb6d..4c62543 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -27,6 +27,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -45,12 +46,14 @@ using namespace clang::driver; using namespace clang::driver::toolchains; +using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple), TargetInitialized(false), - ARCRuntimeForSimulator(ARCSimulator_None) + ARCRuntimeForSimulator(ARCSimulator_None), + LibCXXForSimulator(LibCXXSimulator_None) { // Compute the initial Darwin version based on the host. bool HadExtra; @@ -58,7 +61,7 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple) if (!Driver::GetReleaseVersion(&OSName.c_str()[6], DarwinVersion[0], DarwinVersion[1], DarwinVersion[2], HadExtra)) - getDriver().Diag(clang::diag::err_drv_invalid_darwin_version) << OSName; + getDriver().Diag(diag::err_drv_invalid_darwin_version) << OSName; llvm::raw_string_ostream(MacosxVersionMin) << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' @@ -112,52 +115,40 @@ void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const { runtime.HasTerminate = false; } -// FIXME: Can we tablegen this? -static const char *GetArmArchForMArch(llvm::StringRef Value) { - if (Value == "armv6k") - return "armv6"; - - if (Value == "armv5tej") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "armv4t") - return "armv4t"; - - if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || - Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || - Value == "armv7m") - return "armv7"; - - return 0; -} - -// FIXME: Can we tablegen this? -static const char *GetArmArchForMCpu(llvm::StringRef Value) { - if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || - Value == "arm946e-s" || Value == "arm966e-s" || - Value == "arm968e-s" || Value == "arm10e" || - Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || - Value == "arm1026ej-s") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "arm1136j-s" || Value == "arm1136jf-s" || - Value == "arm1176jz-s" || Value == "arm1176jzf-s" || - Value == "cortex-m0" ) - return "armv6"; - - if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") - return "armv7"; - - return 0; -} - -llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { +/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. +bool Darwin::hasBlocksRuntime() const { + if (isTargetIPhoneOS()) + return !isIPhoneOSVersionLT(3, 2); + else + return !isMacosxVersionLT(10, 6); +} + +static const char *GetArmArchForMArch(StringRef Value) { + return llvm::StringSwitch<const char*>(Value) + .Case("armv6k", "armv6") + .Case("armv5tej", "armv5") + .Case("xscale", "xscale") + .Case("armv4t", "armv4t") + .Case("armv7", "armv7") + .Cases("armv7a", "armv7-a", "armv7") + .Cases("armv7r", "armv7-r", "armv7") + .Cases("armv7m", "armv7-m", "armv7") + .Default(0); +} + +static const char *GetArmArchForMCpu(StringRef Value) { + return llvm::StringSwitch<const char *>(Value) + .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "arm926ej-s","armv5") + .Cases("arm10e", "arm10tdmi", "armv5") + .Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5") + .Case("xscale", "xscale") + .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", + "arm1176jzf-s", "cortex-m0", "armv6") + .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7") + .Default(0); +} + +StringRef Darwin::getDarwinArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); @@ -184,8 +175,9 @@ Darwin::~Darwin() { delete it->second; } -std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const { - llvm::Triple Triple(ComputeLLVMTriple(Args)); +std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); // If the target isn't initialized (e.g., an unknown Darwin platform, return // the default triple). @@ -212,9 +204,10 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI. if (Inputs.size() == 1 && types::isCXX(Inputs[0]->getType()) && - getTriple().getOS() == llvm::Triple::Darwin && + getTriple().isOSDarwin() && getTriple().getArch() == llvm::Triple::x86 && - C.getArgs().getLastArg(options::OPT_fapple_kext)) + (C.getArgs().getLastArg(options::OPT_fapple_kext) || + C.getArgs().getLastArg(options::OPT_mkernel))) Key = JA.getKind(); else Key = Action::AnalyzeJobClass; @@ -236,7 +229,7 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, switch (Key) { case Action::InputClass: case Action::BindArchClass: - assert(0 && "Invalid tool kind."); + llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::darwin::Preprocess(*this); break; case Action::AnalyzeJobClass: @@ -257,6 +250,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; + case Action::VerifyJobClass: + T = new tools::darwin::VerifyDebug(*this); break; } } @@ -267,8 +262,6 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) : Darwin(Host, Triple) { - std::string UsrPrefix = "llvm-gcc-4.2/"; - getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -281,16 +274,24 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) // For fallback, we need to know how to find the GCC cc1 executables, so we // also add the GCC libexec paths. This is legacy code that can be removed // once fallback is no longer useful. + AddGCCLibexecPath(DarwinVersion[0]); + AddGCCLibexecPath(DarwinVersion[0] - 2); + AddGCCLibexecPath(DarwinVersion[0] - 1); + AddGCCLibexecPath(DarwinVersion[0] + 1); + AddGCCLibexecPath(DarwinVersion[0] + 2); +} + +void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) { std::string ToolChainDir = "i686-apple-darwin"; - ToolChainDir += llvm::utostr(DarwinVersion[0]); + ToolChainDir += llvm::utostr(darwinVersion); ToolChainDir += "/4.2.1"; std::string Path = getDriver().Dir; - Path += "/../" + UsrPrefix + "libexec/gcc/"; + Path += "/../llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); - Path = "/usr/" + UsrPrefix + "libexec/gcc/"; + Path = "/usr/llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); } @@ -308,7 +309,7 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, P.appendComponent("gcc"); switch (getTriple().getArch()) { default: - assert(0 && "Invalid Darwin arch!"); + llvm_unreachable("Invalid Darwin arch!"); case llvm::Triple::x86: case llvm::Triple::x86_64: P.appendComponent("i686-apple-darwin10"); @@ -332,7 +333,7 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, case llvm::Triple::arm: case llvm::Triple::thumb: { std::string Triple = ComputeLLVMTriple(Args); - llvm::StringRef TripleStr = Triple; + StringRef TripleStr = Triple; if (TripleStr.startswith("armv5") || TripleStr.startswith("thumbv5")) ArchSpecificDir = "v5"; else if (TripleStr.startswith("armv6") || TripleStr.startswith("thumbv6")) @@ -364,8 +365,8 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - - CmdArgs.push_back("-force_load"); + + CmdArgs.push_back("-force_load"); llvm::sys::Path P(getDriver().ClangExecutable); P.eraseComponent(); // 'clang' P.eraseComponent(); // 'bin' @@ -387,13 +388,13 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, } void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, - ArgStringList &CmdArgs, + ArgStringList &CmdArgs, const char *DarwinStaticLib) const { llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent(DarwinStaticLib); - + // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; @@ -412,7 +413,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // cares. This is useful in situations where someone wants to statically link // something like libstdc++, and needs its runtime support routines. if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { - getDriver().Diag(clang::diag::err_drv_unsupported_opt) + getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); return; } @@ -425,8 +426,9 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, if (isTargetIPhoneOS()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. - if (!isTargetIOSSimulator()) - CmdArgs.push_back("-lgcc_s.1"); + // Linking against libgcc_s.1 isn't needed for iOS 5.0+ + if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator()) + CmdArgs.push_back("-lgcc_s.1"); // We currently always need a static runtime library for iOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); @@ -456,7 +458,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } -static inline llvm::StringRef SimulatorVersionDefineName() { +static inline StringRef SimulatorVersionDefineName() { return "__IPHONE_OS_VERSION_MIN_REQUIRED"; } @@ -465,11 +467,11 @@ static inline llvm::StringRef SimulatorVersionDefineName() { // and return the grouped values as integers, e.g: // __IPHONE_OS_VERSION_MIN_REQUIRED=40201 // will return Major=4, Minor=2, Micro=1. -static bool GetVersionFromSimulatorDefine(llvm::StringRef define, +static bool GetVersionFromSimulatorDefine(StringRef define, unsigned &Major, unsigned &Minor, unsigned &Micro) { assert(define.startswith(SimulatorVersionDefineName())); - llvm::StringRef name, version; + StringRef name, version; llvm::tie(name, version) = define.split('='); if (version.empty()) return false; @@ -500,13 +502,15 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (!iOSVersion) { for (arg_iterator it = Args.filtered_begin(options::OPT_D), ie = Args.filtered_end(); it != ie; ++it) { - llvm::StringRef define = (*it)->getValue(Args); + StringRef define = (*it)->getValue(Args); if (define.startswith(SimulatorVersionDefineName())) { - unsigned Major, Minor, Micro; + unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) { ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime : ARCSimulator_HasARCRuntime; + LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable + : LibCXXSimulator_Available; } break; } @@ -514,61 +518,78 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } if (OSXVersion && (iOSVersion || iOSSimVersion)) { - getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args); iOSVersion = iOSSimVersion = 0; } else if (iOSVersion && iOSSimVersion) { - getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << iOSSimVersion->getAsString(Args); iOSSimVersion = 0; } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) { - // If not deployment target was specified on the command line, check for + // If no deployment target was specified on the command line, check for // environment defines. - const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET"); - const char *iOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"); - const char *iOSSimTarget = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET"); - - // Ignore empty strings. - if (OSXTarget && OSXTarget[0] == '\0') - OSXTarget = 0; - if (iOSTarget && iOSTarget[0] == '\0') - iOSTarget = 0; - if (iOSSimTarget && iOSSimTarget[0] == '\0') - iOSSimTarget = 0; + StringRef OSXTarget; + StringRef iOSTarget; + StringRef iOSSimTarget; + if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) + OSXTarget = env; + if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) + iOSTarget = env; + if (char *env = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET")) + iOSSimTarget = env; + + // If no '-miphoneos-version-min' specified on the command line and + // IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default + // based on isysroot. + if (iOSTarget.empty()) { + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + StringRef first, second; + StringRef isysroot = A->getValue(Args); + llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); + if (second != "") + iOSTarget = second.substr(0,3); + } + } + + // If no OSX or iOS target has been specified and we're compiling for armv7, + // go ahead as assume we're targeting iOS. + if (OSXTarget.empty() && iOSTarget.empty()) + if (getDarwinArchName(Args) == "armv7") + iOSTarget = "0.0"; // Handle conflicting deployment targets // // FIXME: Don't hardcode default here. // Do not allow conflicts with the iOS simulator target. - if (iOSSimTarget && (OSXTarget || iOSTarget)) { - getDriver().Diag(clang::diag::err_drv_conflicting_deployment_targets) + if (!iOSSimTarget.empty() && (!OSXTarget.empty() || !iOSTarget.empty())) { + getDriver().Diag(diag::err_drv_conflicting_deployment_targets) << "IOS_SIMULATOR_DEPLOYMENT_TARGET" - << (OSXTarget ? "MACOSX_DEPLOYMENT_TARGET" : + << (!OSXTarget.empty() ? "MACOSX_DEPLOYMENT_TARGET" : "IPHONEOS_DEPLOYMENT_TARGET"); } // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. - if (OSXTarget && iOSTarget) { + if (!OSXTarget.empty() && !iOSTarget.empty()) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) - OSXTarget = 0; + OSXTarget = ""; else - iOSTarget = 0; + iOSTarget = ""; } - if (OSXTarget) { + if (!OSXTarget.empty()) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); Args.append(OSXVersion); - } else if (iOSTarget) { + } else if (!iOSTarget.empty()) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); Args.append(iOSVersion); - } else if (iOSSimTarget) { + } else if (!iOSSimTarget.empty()) { const Option *O = Opts.getOption( options::OPT_mios_simulator_version_min_EQ); iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); @@ -584,7 +605,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // Reject invalid architecture combinations. if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 && getTriple().getArch() != llvm::Triple::x86_64)) { - getDriver().Diag(clang::diag::err_drv_invalid_arch_for_deployment_target) + getDriver().Diag(diag::err_drv_invalid_arch_for_deployment_target) << getTriple().getArchName() << iOSSimVersion->getAsString(Args); } @@ -596,7 +617,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) - getDriver().Diag(clang::diag::err_drv_invalid_version_number) + getDriver().Diag(diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); } else { const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; @@ -604,7 +625,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) - getDriver().Diag(clang::diag::err_drv_invalid_version_number) + getDriver().Diag(diag::err_drv_invalid_version_number) << Version->getAsString(Args); } @@ -708,7 +729,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // triple arch, or the arch being bound. // // FIXME: Canonicalize name. - llvm::StringRef XarchArch = A->getValue(Args, 0); + StringRef XarchArch = A->getValue(Args, 0); if (!(XarchArch == getArchName() || (BoundArch && XarchArch == BoundArch))) continue; @@ -727,11 +748,11 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_with_args) + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; } else if (XarchArg->getOption().isDriverOption()) { - getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_isdriver) + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } @@ -768,7 +789,6 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, case options::OPT_fapple_kext: DAL->append(A); DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); - DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); break; case options::OPT_dependency_file: @@ -788,12 +808,6 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); break; - case options::OPT_fterminated_vtables: - case options::OPT_findirect_virtual_calls: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_fapple_kext)); - DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); - break; - case options::OPT_shared: DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); break; @@ -834,7 +848,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. if (BoundArch) { - llvm::StringRef Name = BoundArch; + StringRef Name = BoundArch; const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ); const Option *MArch = Opts.getOption(options::OPT_march_EQ); @@ -904,6 +918,28 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // argument. AddDeploymentTarget(*DAL); + // Validate the C++ standard library choice. + CXXStdlibType Type = GetCXXStdlibType(*DAL); + if (Type == ToolChain::CST_Libcxx) { + switch (LibCXXForSimulator) { + case LibCXXSimulator_None: + // Handle non-simulator cases. + if (isTargetIPhoneOS()) { + if (isIPhoneOSVersionLT(5, 0)) { + getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) + << "iOS 5.0"; + } + } + break; + case LibCXXSimulator_NotAvailable: + getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) + << "iOS 5.0"; + break; + case LibCXXSimulator_Available: + break; + } + } + return DAL; } @@ -946,8 +982,9 @@ bool Darwin::SupportsObjCGC() const { } std::string -Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const { - return ComputeLLVMTriple(Args); +Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + return ComputeLLVMTriple(Args, InputType); } /// Generic_GCC - A tool chain using the 'gcc' command to perform @@ -982,7 +1019,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, switch (Key) { case Action::InputClass: case Action::BindArchClass: - assert(0 && "Invalid tool kind."); + llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::gcc::Preprocess(*this); break; case Action::PrecompileJobClass: @@ -1002,6 +1039,8 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; + case Action::VerifyJobClass: + T = new tools::darwin::VerifyDebug(*this); break; } } @@ -1071,7 +1110,7 @@ Tool &TCEToolChain::SelectTool(const Compilation &C, case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; default: - assert(false && "Unsupported action for TCE target."); + llvm_unreachable("Unsupported action for TCE target."); } } return *T; @@ -1350,32 +1389,24 @@ static bool IsUbuntu(enum LinuxDistro Distro) { Distro == UbuntuNatty || Distro == UbuntuOneiric; } -static bool IsDebianBased(enum LinuxDistro Distro) { - return IsDebian(Distro) || IsUbuntu(Distro); -} - +// FIXME: This should be deleted. We should assume a multilib environment, and +// fallback gracefully if any parts of it are absent. static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) { if (Arch == llvm::Triple::x86_64) { bool Exists; if (Distro == Exherbo && (llvm::sys::fs::exists("/usr/lib32/libc.so", Exists) || !Exists)) return false; - - return true; } - if (Arch == llvm::Triple::ppc64) - return true; - if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && - IsDebianBased(Distro)) - return true; - return false; + + return true; } static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { llvm::OwningPtr<llvm::MemoryBuffer> File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { - llvm::StringRef Data = File.get()->getBuffer(); - llvm::SmallVector<llvm::StringRef, 8> Lines; + StringRef Data = File.get()->getBuffer(); + SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) { if (Lines[i] == "DISTRIB_CODENAME=hardy") @@ -1399,7 +1430,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { } if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { - llvm::StringRef Data = File.get()->getBuffer(); + StringRef Data = File.get()->getBuffer(); if (Data.startswith("Fedora release 15")) return Fedora15; else if (Data.startswith("Fedora release 14")) @@ -1407,24 +1438,24 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { else if (Data.startswith("Fedora release 13")) return Fedora13; else if (Data.startswith("Fedora release") && - Data.find("Rawhide") != llvm::StringRef::npos) + Data.find("Rawhide") != StringRef::npos) return FedoraRawhide; else if (Data.startswith("Red Hat Enterprise Linux") && - Data.find("release 6") != llvm::StringRef::npos) + Data.find("release 6") != StringRef::npos) return RHEL6; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && - Data.find("release 5") != llvm::StringRef::npos) + Data.find("release 5") != StringRef::npos) return RHEL5; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && - Data.find("release 4") != llvm::StringRef::npos) + Data.find("release 4") != StringRef::npos) return RHEL4; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) { - llvm::StringRef Data = File.get()->getBuffer(); + StringRef Data = File.get()->getBuffer(); if (Data[0] == '5') return DebianLenny; else if (Data.startswith("squeeze/sid")) @@ -1435,7 +1466,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) { - llvm::StringRef Data = File.get()->getBuffer(); + StringRef Data = File.get()->getBuffer(); if (Data.startswith("openSUSE 11.3")) return OpenSuse11_3; else if (Data.startswith("openSUSE 11.4")) @@ -1455,164 +1486,282 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } -static std::string findGCCBaseLibDir(const std::string &GccTriple) { - // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but - // avoids adding yet another option to configure/cmake. - // It would probably be cleaner to break it in two variables - // CXX_GCC_ROOT with just /foo/bar - // CXX_GCC_VER with 4.5.2 - // Then we would have - // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER - // and this function would return - // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER - llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT); - if (CxxIncludeRoot != "") { - // This is of the form /foo/bar/include/c++/4.5.2/ - if (CxxIncludeRoot.back() == '/') - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the / - llvm::StringRef Version = llvm::sys::path::filename(CxxIncludeRoot); - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++ - llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include - std::string ret(CxxIncludeRoot.c_str()); - ret.append("/lib/gcc/"); - ret.append(CXX_INCLUDE_ARCH); - ret.append("/"); - ret.append(Version); - return ret; - } - static const char* GccVersions[] = {"4.6.1", "4.6.0", "4.6", - "4.5.2", "4.5.1", "4.5", - "4.4.5", "4.4.4", "4.4.3", "4.4", - "4.3.4", "4.3.3", "4.3.2", "4.3", - "4.2.4", "4.2.3", "4.2.2", "4.2.1", - "4.2", "4.1.1"}; +/// \brief Trivial helper function to simplify code checking path existence. +static bool PathExists(StringRef Path) { bool Exists; - for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) { - std::string Suffix = GccTriple + "/" + GccVersions[i]; - std::string t1 = "/usr/lib/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) - return t1; - std::string t2 = "/usr/lib64/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) - return t2; - std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix; - if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) - return t3; - } - return ""; + if (!llvm::sys::fs::exists(Path, Exists)) + return Exists; + return false; } -Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) - : Generic_ELF(Host, Triple) { - llvm::Triple::ArchType Arch = - llvm::Triple(getDriver().DefaultHostTriple).getArch(); +namespace { +/// \brief This is a class to find a viable GCC installation for Clang to use. +/// +/// This class tries to find a GCC installation on the system, and report +/// information about it. It starts from the host information provided to the +/// Driver, and has logic for fuzzing that where appropriate. +class GCCInstallationDetector { + /// \brief Struct to store and manipulate GCC versions. + /// + /// We rely on assumptions about the form and structure of GCC version + /// numbers: they consist of at most three '.'-separated components, and each + /// component is a non-negative integer. + struct GCCVersion { + unsigned Major, Minor, Patch; + + static GCCVersion Parse(StringRef VersionText) { + const GCCVersion BadVersion = {0, 0, 0}; + std::pair<StringRef, StringRef> First = VersionText.split('.'); + std::pair<StringRef, StringRef> Second = First.second.split('.'); + + GCCVersion GoodVersion = {0, 0, 0}; + if (First.first.getAsInteger(10, GoodVersion.Major)) + return BadVersion; + if (Second.first.getAsInteger(10, GoodVersion.Minor)) + return BadVersion; + // We accept a number, or a string for the patch version, in case there + // is a strang suffix, or other mangling: '4.1.x', '4.1.2-rc3'. When it + // isn't a number, we just use '0' as the number but accept it. + if (Second.first.getAsInteger(10, GoodVersion.Patch)) + GoodVersion.Patch = 0; + return GoodVersion; + } - std::string Suffix32 = ""; - if (Arch == llvm::Triple::x86_64) - Suffix32 = "/32"; + bool operator<(const GCCVersion &RHS) const { + if (Major < RHS.Major) return true; + if (Major > RHS.Major) return false; + if (Minor < RHS.Minor) return true; + if (Minor > RHS.Minor) return false; + return Patch < RHS.Patch; + } + bool operator>(const GCCVersion &RHS) const { return RHS < *this; } + bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } + bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } + }; + + bool IsValid; + std::string GccTriple; + + // FIXME: These might be better as path objects. + std::string GccInstallPath; + std::string GccParentLibPath; + + llvm::SmallString<128> CxxIncludeRoot; + +public: + /// \brief Construct a GCCInstallationDetector from the driver. + /// + /// This performs all of the autodetection and sets up the various paths. + /// Once constructed, a GCCInstallation is esentially immutable. + GCCInstallationDetector(const Driver &D) + : IsValid(false), + GccTriple(D.DefaultHostTriple), + CxxIncludeRoot(CXX_INCLUDE_ROOT) { + // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but + // avoids adding yet another option to configure/cmake. + // It would probably be cleaner to break it in two variables + // CXX_GCC_ROOT with just /foo/bar + // CXX_GCC_VER with 4.5.2 + // Then we would have + // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER + // and this function would return + // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER + if (CxxIncludeRoot != "") { + // This is of the form /foo/bar/include/c++/4.5.2/ + if (CxxIncludeRoot.back() == '/') + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the / + StringRef Version = llvm::sys::path::filename(CxxIncludeRoot); + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++ + llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include + GccInstallPath = CxxIncludeRoot.str(); + GccInstallPath.append("/lib/gcc/"); + GccInstallPath.append(CXX_INCLUDE_ARCH); + GccInstallPath.append("/"); + GccInstallPath.append(Version); + GccParentLibPath = GccInstallPath + "/../../.."; + IsValid = true; + return; + } - std::string Suffix64 = ""; - if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) - Suffix64 = "/64"; + llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch(); + // The library directories which may contain GCC installations. + SmallVector<StringRef, 4> CandidateLibDirs; + // The compatible GCC triples for this particular architecture. + SmallVector<StringRef, 10> CandidateTriples; + CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples); + + // Always include the default host triple as the final fallback if no + // specific triple is detected. + CandidateTriples.push_back(D.DefaultHostTriple); + + // Compute the set of prefixes for our search. + SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), + D.PrefixDirs.end()); + Prefixes.push_back(D.SysRoot); + Prefixes.push_back(D.SysRoot + "/usr"); + Prefixes.push_back(D.InstalledDir + "/.."); + + // Loop over the various components which exist and select the best GCC + // installation available. GCC installs are ranked by version number. + GCCVersion BestVersion = {0, 0, 0}; + for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) { + if (!PathExists(Prefixes[i])) + continue; + for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) { + const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str(); + if (!PathExists(LibDir)) + continue; + for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k) + ScanLibDirForGCCTriple(LibDir, CandidateTriples[k], BestVersion); + } + } + } - std::string Lib32 = "lib"; + /// \brief Check whether we detected a valid GCC install. + bool isValid() const { return IsValid; } + + /// \brief Get the GCC triple for the detected install. + const std::string &getTriple() const { return GccTriple; } + + /// \brief Get the detected GCC installation path. + const std::string &getInstallPath() const { return GccInstallPath; } + + /// \brief Get the detected GCC parent lib path. + const std::string &getParentLibPath() const { return GccParentLibPath; } + +private: + static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch, + SmallVectorImpl<StringRef> &LibDirs, + SmallVectorImpl<StringRef> &Triples) { + if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) { + static const char *const ARMLibDirs[] = { "/lib" }; + static const char *const ARMTriples[] = { "arm-linux-gnueabi" }; + LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); + Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples)); + } else if (HostArch == llvm::Triple::x86_64) { + static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; + static const char *const X86_64Triples[] = { + "x86_64-linux-gnu", + "x86_64-unknown-linux-gnu", + "x86_64-pc-linux-gnu", + "x86_64-redhat-linux6E", + "x86_64-redhat-linux", + "x86_64-suse-linux", + "x86_64-manbo-linux-gnu", + "x86_64-linux-gnu", + "x86_64-slackware-linux" + }; + LibDirs.append(X86_64LibDirs, + X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); + Triples.append(X86_64Triples, + X86_64Triples + llvm::array_lengthof(X86_64Triples)); + } else if (HostArch == llvm::Triple::x86) { + static const char *const X86LibDirs[] = { "/lib32", "/lib" }; + static const char *const X86Triples[] = { + "i686-linux-gnu", + "i386-linux-gnu", + "i686-pc-linux-gnu", + "i486-linux-gnu", + "i686-redhat-linux", + "i386-redhat-linux", + "i586-suse-linux", + "i486-slackware-linux" + }; + LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); + Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); + } else if (HostArch == llvm::Triple::ppc) { + static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; + static const char *const PPCTriples[] = { + "powerpc-linux-gnu", + "powerpc-unknown-linux-gnu" + }; + LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); + Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); + } else if (HostArch == llvm::Triple::ppc64) { + static const char *const PPC64LibDirs[] = { "/lib64", "/lib" }; + static const char *const PPC64Triples[] = { + "powerpc64-unknown-linux-gnu" + }; + LibDirs.append(PPC64LibDirs, + PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); + Triples.append(PPC64Triples, + PPC64Triples + llvm::array_lengthof(PPC64Triples)); + } + } - bool Exists; - if (!llvm::sys::fs::exists("/lib32", Exists) && Exists) - Lib32 = "lib32"; - - std::string Lib64 = "lib"; - bool Symlink; - if (!llvm::sys::fs::exists("/lib64", Exists) && Exists && - (llvm::sys::fs::is_symlink("/lib64", Symlink) || !Symlink)) - Lib64 = "lib64"; - - std::string GccTriple = ""; - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { - if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) && - Exists) - GccTriple = "arm-linux-gnueabi"; - } else if (Arch == llvm::Triple::x86_64) { - if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-linux-gnu", Exists) && - Exists) - GccTriple = "x86_64-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-unknown-linux-gnu", - Exists) && Exists) - GccTriple = "x86_64-unknown-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-pc-linux-gnu", - Exists) && Exists) - GccTriple = "x86_64-pc-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux6E", - Exists) && Exists) - GccTriple = "x86_64-redhat-linux6E"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux", - Exists) && Exists) - GccTriple = "x86_64-redhat-linux"; - else if (!llvm::sys::fs::exists("/usr/lib64/gcc/x86_64-suse-linux", - Exists) && Exists) - GccTriple = "x86_64-suse-linux"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu", - Exists) && Exists) - GccTriple = "x86_64-manbo-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/x86_64-linux-gnu/gcc", - Exists) && Exists) - GccTriple = "x86_64-linux-gnu"; - } else if (Arch == llvm::Triple::x86) { - if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists) - GccTriple = "i686-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-pc-linux-gnu", Exists) && - Exists) - GccTriple = "i686-pc-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-linux-gnu", Exists) && - Exists) - GccTriple = "i486-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-redhat-linux", Exists) && - Exists) - GccTriple = "i686-redhat-linux"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) && - Exists) - GccTriple = "i586-suse-linux"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-slackware-linux", Exists) - && Exists) - GccTriple = "i486-slackware-linux"; - } else if (Arch == llvm::Triple::ppc) { - if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists) - GccTriple = "powerpc-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", - Exists) && Exists) - GccTriple = "powerpc-unknown-linux-gnu"; - } else if (Arch == llvm::Triple::ppc64) { - if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", - Exists) && Exists) - GccTriple = "powerpc64-unknown-linux-gnu"; - else if (!llvm::sys::fs::exists("/usr/lib64/gcc/" - "powerpc64-unknown-linux-gnu", Exists) && - Exists) - GccTriple = "powerpc64-unknown-linux-gnu"; + void ScanLibDirForGCCTriple(const std::string &LibDir, + StringRef CandidateTriple, + GCCVersion &BestVersion) { + // There are various different suffixes involving the triple we + // check for. We also record what is necessary to walk from each back + // up to the lib directory. + const std::string Suffixes[] = { + "/gcc/" + CandidateTriple.str(), + "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), + + // Ubuntu has a strange mis-matched pair of triples that this happens to + // match. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + "/" + CandidateTriple.str() + "/gcc/i686-linux-gnu" + }; + const std::string InstallSuffixes[] = { + "/../../..", + "/../../../..", + "/../../../.." + }; + // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. + const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) - + (CandidateTriple != "i386-linux-gnu")); + for (unsigned i = 0; i < NumSuffixes; ++i) { + StringRef Suffix = Suffixes[i]; + llvm::error_code EC; + for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + static const GCCVersion MinVersion = { 4, 1, 1 }; + if (CandidateVersion < MinVersion) + continue; + if (CandidateVersion <= BestVersion) + continue; + if (!PathExists(LI->path() + "/crtbegin.o")) + continue; + + BestVersion = CandidateVersion; + GccTriple = CandidateTriple.str(); + // FIXME: We hack together the directory name here instead of + // using LI to ensure stable path separators across Windows and + // Linux. + GccInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str(); + GccParentLibPath = GccInstallPath + InstallSuffixes[i]; + IsValid = true; + } + } } +}; +} - std::string Base = findGCCBaseLibDir(GccTriple); - path_list &Paths = getFilePaths(); - bool Is32Bits = (getArch() == llvm::Triple::x86 || - getArch() == llvm::Triple::ppc); +static void addPathIfExists(const std::string &Path, + ToolChain::path_list &Paths) { + if (PathExists(Path)) Paths.push_back(Path); +} - std::string Suffix; - std::string Lib; +Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) + : Generic_ELF(Host, Triple) { + llvm::Triple::ArchType Arch = + llvm::Triple(getDriver().DefaultHostTriple).getArch(); + const std::string &SysRoot = getDriver().SysRoot; + GCCInstallationDetector GCCInstallation(getDriver()); - if (Is32Bits) { - Suffix = Suffix32; - Lib = Lib32; - } else { - Suffix = Suffix64; - Lib = Lib64; - } + // OpenSuse stores the linker with the compiler, add that to the search + // path. + ToolChain::path_list &PPaths = getProgramPaths(); + PPaths.push_back(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple() + "/bin"); - llvm::sys::Path LinkerPath(Base + "/../../../../" + GccTriple + "/bin/ld"); - if (!llvm::sys::fs::exists(LinkerPath.str(), Exists) && Exists) - Linker = LinkerPath.str(); - else - Linker = GetProgramPath("ld"); + Linker = GetProgramPath("ld"); LinuxDistro Distro = DetectLinuxDistro(Arch); @@ -1646,29 +1795,63 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) if (IsOpenSuse(Distro)) ExtraOpts.push_back("--enable-new-dtags"); - if (Distro == ArchLinux) - Lib = "lib"; + // The selection of paths to try here is designed to match the patterns which + // the GCC driver itself uses, as this is part of the GCC-compatible driver. + // This was determined by running GCC in a fake filesystem, creating all + // possible permutations of these directories, and seeing which ones it added + // to the link paths. + path_list &Paths = getFilePaths(); + const bool Is32Bits = (getArch() == llvm::Triple::x86 || + getArch() == llvm::Triple::ppc); + + const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : ""; + const std::string Suffix64 = Arch == llvm::Triple::x86_64 ? "" : "/64"; + const std::string Suffix = Is32Bits ? Suffix32 : Suffix64; + const std::string Multilib = Is32Bits ? "lib32" : "lib64"; - Paths.push_back(Base + Suffix); + // FIXME: Because we add paths only when they exist on the system, I think we + // should remove the concept of 'HasMultilib'. It's more likely to break the + // behavior than to preserve any useful invariant on the system. if (HasMultilib(Arch, Distro)) { - if (IsOpenSuse(Distro) && Is32Bits) - Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib"); - Paths.push_back(Base + "/../../../../" + Lib); + // Add the multilib suffixed paths. + if (GCCInstallation.isValid()) { + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const std::string &GccTriple = GCCInstallation.getTriple(); + // FIXME: This OpenSuse-specific path shouldn't be needed any more, but + // I don't want to remove it without finding someone to test. + if (IsOpenSuse(Distro) && Is32Bits) + Paths.push_back(LibPath + "/../" + GccTriple + "/lib/../lib"); + + addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths); + addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib, + Paths); + addPathIfExists(LibPath + "/../" + Multilib, Paths); + } + addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); + addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); + + // Try walking via the GCC triple path in case of multiarch GCC + // installations with strange symlinks. + if (GCCInstallation.isValid()) + addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple() + + "/../../" + Multilib, Paths); } - // FIXME: This is in here to find crt1.o. It is provided by libc, and - // libc (like gcc), can be installed in any directory. Once we are - // fetching this from a config file, we should have a libc prefix. - Paths.push_back("/lib/../" + Lib); - Paths.push_back("/usr/lib/../" + Lib); + // Add the non-multilib suffixed paths (if potentially different). + if (GCCInstallation.isValid()) { + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const std::string &GccTriple = GCCInstallation.getTriple(); + if (!Suffix.empty() || !HasMultilib(Arch, Distro)) + addPathIfExists(GCCInstallation.getInstallPath(), Paths); + addPathIfExists(LibPath + "/../" + GccTriple + "/lib", Paths); + addPathIfExists(LibPath, Paths); + } + addPathIfExists(SysRoot + "/lib", Paths); + addPathIfExists(SysRoot + "/usr/lib", Paths); - if (!Suffix.empty()) - Paths.push_back(Base); - if (IsOpenSuse(Distro)) - Paths.push_back(Base + "/../../../../" + GccTriple + "/lib"); - Paths.push_back(Base + "/../../.."); - if (Arch == getArch() && IsUbuntu(Distro)) - Paths.push_back("/usr/lib/" + GccTriple); + // Add a multiarch lib directory whenever it exists and is plausible. + if (GCCInstallation.isValid() && Arch == getArch()) + addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple(), Paths); } bool Linux::HasNativeLLVMSupport() const { @@ -1756,6 +1939,10 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, else Key = JA.getKind(); + bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIntegratedAssemblerDefault()); + Tool *&T = Tools[Key]; if (!T) { switch (Key) { @@ -1763,14 +1950,19 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, case Action::BindArchClass: case Action::LipoJobClass: case Action::DsymutilJobClass: - assert(0 && "Invalid tool kind."); + case Action::VerifyJobClass: + llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: case Action::PrecompileJobClass: case Action::AnalyzeJobClass: case Action::CompileJobClass: T = new tools::Clang(*this); break; case Action::AssembleJobClass: - T = new tools::ClangAs(*this); break; + if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO) + T = new tools::darwin::Assemble(*this); + else + T = new tools::ClangAs(*this); + break; case Action::LinkJobClass: T = new tools::visualstudio::Link(*this); break; } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index d68016b..dfcb253 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -66,6 +66,12 @@ private: ARCSimulator_NoARCRuntime } ARCRuntimeForSimulator; + mutable enum { + LibCXXSimulator_None, + LibCXXSimulator_NotAvailable, + LibCXXSimulator_Available + } LibCXXForSimulator; + private: /// Whether we are targeting iPhoneOS target. mutable bool TargetIsIPhoneOS; @@ -89,7 +95,8 @@ public: Darwin(const HostInfo &Host, const llvm::Triple& Triple); ~Darwin(); - std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + std::string ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const; /// @name Darwin Specific Toolchain API /// { @@ -139,7 +146,7 @@ public: /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler /// invocation. For example, Darwin treats different ARM variations as /// distinct architectures. - llvm::StringRef getDarwinArchName(const ArgList &Args) const; + StringRef getDarwinArchName(const ArgList &Args) const; static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { for (unsigned i=0; i < 3; ++i) { @@ -187,6 +194,7 @@ public: virtual bool HasNativeLLVMSupport() const; virtual void configureObjCRuntime(ObjCRuntime &runtime) const; + virtual bool hasBlocksRuntime() const; virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; @@ -237,9 +245,12 @@ public: return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6)); } virtual bool IsUnwindTablesDefault() const; - virtual unsigned GetDefaultStackProtectorLevel() const { - // Stack protectors default to on for 10.6 and beyond. - return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 6); + virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { + // Stack protectors default to on for user code on 10.5, + // and for everything in 10.6 and beyond + return !isTargetIPhoneOS() && + (!isMacosxVersionLT(10, 6) || + (!isMacosxVersionLT(10, 5) && !KernelOrKext)); } virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; @@ -257,6 +268,9 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { +private: + void AddGCCLibexecPath(unsigned darwinVersion); + public: DarwinClang(const HostInfo &Host, const llvm::Triple& Triple); @@ -288,7 +302,8 @@ public: Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} - std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + std::string ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const; virtual const char *GetDefaultRelocationModel() const { return "pic"; } }; diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 64ad146..94849a6 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -45,25 +45,14 @@ using namespace clang::driver; using namespace clang::driver::tools; - -/// FindTargetProgramPath - Return path of the target specific version of -/// ProgName. If it doesn't exist, return path of ProgName itself. -static std::string FindTargetProgramPath(const ToolChain &TheToolChain, - const std::string TripleString, - const char *ProgName) { - std::string Executable(TripleString + "-" + ProgName); - std::string Path(TheToolChain.GetProgramPath(Executable.c_str())); - if (Path != Executable) - return Path; - return TheToolChain.GetProgramPath(ProgName); -} +using namespace clang; /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; } @@ -74,14 +63,14 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { if (Args.hasArg(options::OPT_static)) if (const Arg *A = Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-static"; } // Quote target names for inclusion in GNU Make dependency files. // Only the characters '$', '#', ' ', '\t' are quoted. -static void QuoteTarget(llvm::StringRef Target, - llvm::SmallVectorImpl<char> &Res) { +static void QuoteTarget(StringRef Target, + SmallVectorImpl<char> &Res) { for (unsigned i = 0, e = Target.size(); i != e; ++i) { switch (Target[i]) { case ' ': @@ -126,7 +115,7 @@ static void AddLinkerInputs(const ToolChain &TC, II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) - D.Diag(clang::diag::err_drv_no_linker_llvm_support) + D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); } @@ -168,20 +157,52 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, // the link line. We cannot do the same thing because unlike gcov there is a // libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is // not supported by old linkers. - llvm::Twine ProfileRT = - llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a"; + Twine ProfileRT = + Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a"; - if (Triple.getOS() == llvm::Triple::Darwin) { + if (Triple.isOSDarwin()) { // On Darwin, if the static library doesn't exist try the dylib. bool Exists; if (llvm::sys::fs::exists(ProfileRT.str(), Exists) || !Exists) ProfileRT = - llvm::Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib"; + Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib"; } CmdArgs.push_back(Args.MakeArgString(ProfileRT)); } +static void AddIncludeDirectoryList(const ArgList &Args, + ArgStringList &CmdArgs, + const char *ArgName, + const char *DirList) { + if (!DirList) + return; // Nothing to do. + + StringRef Dirs(DirList); + if (Dirs.empty()) // Empty string should not add '.'. + return; + + StringRef::size_type Delim; + while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) { + if (Delim == 0) { // Leading colon. + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); + } + Dirs = Dirs.substr(Delim + 1); + } + + if (Dirs.empty()) { // Trailing colon. + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } else { // Add the last path. + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs)); + } +} + void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -245,7 +266,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, if (Args.hasArg(options::OPT_MG)) { if (!A || A->getOption().matches(options::OPT_MD) || A->getOption().matches(options::OPT_MMD)) - D.Diag(clang::diag::err_drv_mg_requires_m_or_mm); + D.Diag(diag::err_drv_mg_requires_m_or_mm); CmdArgs.push_back("-MG"); } @@ -328,7 +349,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, continue; } else { // Ignore the PCH if not first on command line and emit warning. - D.Diag(clang::diag::warn_drv_pch_not_first_include) + D.Diag(diag::warn_drv_pch_not_first_include) << P.str() << A->getAsString(Args); } } @@ -340,14 +361,15 @@ void Clang::AddPreprocessingOptions(const Driver &D, } Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); - Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F); + Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F, + options::OPT_index_header_map); // Add C++ include arguments, if needed. types::ID InputType = Inputs[0].getType(); if (types::isCXX(InputType)) { bool ObjCXXAutoRefCount = types::isObjC(InputType) && isObjCAutoRefCount(Args); - getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs, + getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs, ObjCXXAutoRefCount); Args.AddAllArgs(CmdArgs, options::OPT_stdlib_EQ); } @@ -363,7 +385,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, // -I- is a deprecated GCC feature, reject it. if (Arg *A = Args.getLastArg(options::OPT_I_)) - D.Diag(clang::diag::err_drv_I_dash_not_supported) << A->getAsString(Args); + D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); // If we have a --sysroot, and don't have an explicit -isysroot flag, add an // -isysroot to the CC1 invocation. @@ -373,6 +395,39 @@ void Clang::AddPreprocessingOptions(const Driver &D, CmdArgs.push_back(A->getValue(Args)); } } + + // If a module path was provided, pass it along. Otherwise, use a temporary + // directory. + if (Arg *A = Args.getLastArg(options::OPT_fmodule_cache_path)) { + A->claim(); + A->render(Args, CmdArgs); + } else { + llvm::SmallString<128> DefaultModuleCache; + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, + DefaultModuleCache); + llvm::sys::path::append(DefaultModuleCache, "clang-module-cache"); + CmdArgs.push_back("-fmodule-cache-path"); + CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); + } + + Args.AddAllArgs(CmdArgs, options::OPT_fauto_module_import); + + // Parse additional include paths from environment variables. + // CPATH - included following the user specified includes (but prior to + // builtin and standard includes). + AddIncludeDirectoryList(Args, CmdArgs, "-I", ::getenv("CPATH")); + // C_INCLUDE_PATH - system includes enabled when compiling C. + AddIncludeDirectoryList(Args, CmdArgs, "-c-isystem", + ::getenv("C_INCLUDE_PATH")); + // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. + AddIncludeDirectoryList(Args, CmdArgs, "-cxx-isystem", + ::getenv("CPLUS_INCLUDE_PATH")); + // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. + AddIncludeDirectoryList(Args, CmdArgs, "-objc-isystem", + ::getenv("OBJC_INCLUDE_PATH")); + // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. + AddIncludeDirectoryList(Args, CmdArgs, "-objcxx-isystem", + ::getenv("OBJCPLUS_INCLUDE_PATH")); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. @@ -386,7 +441,7 @@ static const char *getARMTargetCPU(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(Args); - llvm::StringRef MArch; + StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(Args); @@ -395,45 +450,27 @@ static const char *getARMTargetCPU(const ArgList &Args, MArch = Triple.getArchName(); } - if (MArch == "armv2" || MArch == "armv2a") - return "arm2"; - if (MArch == "armv3") - return "arm6"; - if (MArch == "armv3m") - return "arm7m"; - if (MArch == "armv4" || MArch == "armv4t") - return "arm7tdmi"; - if (MArch == "armv5" || MArch == "armv5t") - return "arm10tdmi"; - if (MArch == "armv5e" || MArch == "armv5te") - return "arm1026ejs"; - if (MArch == "armv5tej") - return "arm926ej-s"; - if (MArch == "armv6" || MArch == "armv6k") - return "arm1136jf-s"; - if (MArch == "armv6j") - return "arm1136j-s"; - if (MArch == "armv6z" || MArch == "armv6zk") - return "arm1176jzf-s"; - if (MArch == "armv6t2") - return "arm1156t2-s"; - if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") - return "cortex-a8"; - if (MArch == "armv7r" || MArch == "armv7-r") - return "cortex-r4"; - if (MArch == "armv7m" || MArch == "armv7-m") - return "cortex-m3"; - if (MArch == "ep9312") - return "ep9312"; - if (MArch == "iwmmxt") - return "iwmmxt"; - if (MArch == "xscale") - return "xscale"; - if (MArch == "armv6m" || MArch == "armv6-m") - return "cortex-m0"; - - // If all else failed, return the most base CPU LLVM supports. - return "arm7tdmi"; + return llvm::StringSwitch<const char *>(MArch) + .Cases("armv2", "armv2a","arm2") + .Case("armv3", "arm6") + .Case("armv3m", "arm7m") + .Cases("armv4", "armv4t", "arm7tdmi") + .Cases("armv5", "armv5t", "arm10tdmi") + .Cases("armv5e", "armv5te", "arm1026ejs") + .Case("armv5tej", "arm926ej-s") + .Cases("armv6", "armv6k", "arm1136jf-s") + .Case("armv6j", "arm1136j-s") + .Cases("armv6z", "armv6zk", "arm1176jzf-s") + .Case("armv6t2", "arm1156t2-s") + .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") + .Cases("armv7r", "armv7-r", "cortex-r4") + .Cases("armv7m", "armv7-m", "cortex-m3") + .Case("ep9312", "ep9312") + .Case("iwmmxt", "iwmmxt") + .Case("xscale", "xscale") + .Cases("armv6m", "armv6-m", "cortex-m0") + // If all else failed, return the most base CPU LLVM supports. + .Default("arm7tdmi"); } /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular @@ -441,33 +478,21 @@ static const char *getARMTargetCPU(const ArgList &Args, // // FIXME: This is redundant with -mcpu, why does LLVM use this. // FIXME: tblgen this, or kill it! -static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { - if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" || - CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" || - CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" || - CPU == "arm940t" || CPU == "ep9312") - return "v4t"; - - if (CPU == "arm10tdmi" || CPU == "arm1020t") - return "v5"; - - if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" || - CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" || - CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" || - CPU == "iwmmxt") - return "v5e"; - - if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" || - CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore") - return "v6"; - - if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s") - return "v6t2"; - - if (CPU == "cortex-a8" || CPU == "cortex-a9") - return "v7"; - - return ""; +static const char *getLLVMArchSuffixForARM(StringRef CPU) { + return llvm::StringSwitch<const char *>(CPU) + .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t") + .Cases("arm720t", "arm9", "arm9tdmi", "v4t") + .Cases("arm920", "arm920t", "arm922t", "v4t") + .Cases("arm940t", "ep9312","v4t") + .Cases("arm10tdmi", "arm1020t", "v5") + .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e") + .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e") + .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e") + .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") + .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") + .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") + .Cases("cortex-a8", "cortex-a9", "v7") + .Default(""); } // FIXME: Move to target hook. @@ -479,7 +504,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { case llvm::Triple::arm: case llvm::Triple::ppc: case llvm::Triple::ppc64: - if (Triple.getOS() == llvm::Triple::Darwin) + if (Triple.isOSDarwin()) return true; return false; @@ -494,12 +519,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, const Driver &D = getToolChain().getDriver(); llvm::Triple Triple = getToolChain().getTriple(); - // Disable movt generation, if requested. -#ifdef DISABLE_ARM_DARWIN_USE_MOVT - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-darwin-use-movt=0"); -#endif - // Select the ABI to use. // // FIXME: Support -meabi. @@ -528,7 +547,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. - llvm::StringRef FloatABI; + StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { @@ -539,7 +558,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, else { FloatABI = A->getValue(Args); if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { - D.Diag(clang::diag::err_drv_invalid_mfloat_abi) + D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "soft"; } @@ -550,11 +569,13 @@ void Clang::AddARMTargetArgs(const ArgList &Args, if (FloatABI.empty()) { const llvm::Triple &Triple = getToolChain().getTriple(); switch (Triple.getOS()) { - case llvm::Triple::Darwin: { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: { // Darwin defaults to "softfp" for v6 and v7. // // FIXME: Factor out an ARM class so we can cache the arch somewhere. - llvm::StringRef ArchName = + StringRef ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); if (ArchName.startswith("v6") || ArchName.startswith("v7")) FloatABI = "softfp"; @@ -583,7 +604,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, default: // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; - D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; + D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } @@ -630,7 +651,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // FIXME: Centralize feature selection, defaulting shouldn't be also in the // frontend target. if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { - llvm::StringRef FPU = A->getValue(Args); + StringRef FPU = A->getValue(Args); // Set the target features based on the FPU. if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { @@ -651,7 +672,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+neon"); } else - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } // Setting -msoft-float effectively disables NEON because of the GCC @@ -670,42 +691,84 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-arm-strict-align"); // The kext linker doesn't know how to deal with movw/movt. -#ifndef DISABLE_ARM_DARWIN_USE_MOVT CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-darwin-use-movt=0"); -#endif + } + + // Setting -mno-global-merge disables the codegen global merge pass. Setting + // -mglobal-merge has no effect as the pass is enabled by default. + if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, + options::OPT_mno_global_merge)) { + if (A->getOption().matches(options::OPT_mno_global_merge)) + CmdArgs.push_back("-mno-global-merge"); } } +// Get default architecture. +static const char* getMipsArchFromCPU(StringRef CPUName) { + if (CPUName == "mips32r1" || CPUName == "4ke") + return "mips"; + + assert((CPUName == "mips64r1" || CPUName == "mips64r2") && + "Unexpected cpu name."); + + return "mips64"; +} + +// Get default target cpu. +static const char* getMipsCPUFromArch(StringRef ArchName, const Driver &D) { + if (ArchName == "mips" || ArchName == "mipsel") + return "mips32r1"; + else if (ArchName == "mips64" || ArchName == "mips64el") + return "mips64r1"; + else + D.Diag(diag::err_drv_invalid_arch_name) << ArchName; + + return 0; +} + +// Get default ABI. +static const char* getMipsABIFromArch(StringRef ArchName) { + if (ArchName == "mips" || ArchName == "mipsel") + return "o32"; + + assert((ArchName == "mips64" || ArchName == "mips64el") && + "Unexpected arch name."); + return "n64"; +} + void Clang::AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); + StringRef ArchName; + const char *CPUName; + + // Set target cpu and architecture. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + CPUName = A->getValue(Args); + ArchName = getMipsArchFromCPU(CPUName); + } + else { + ArchName = Args.MakeArgString(getToolChain().getArchName()); + CPUName = getMipsCPUFromArch(ArchName, D); + } + + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(CPUName); + // Select the ABI to use. const char *ABIName = 0; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) ABIName = A->getValue(Args); - } else { - ABIName = "o32"; - } + else + ABIName = getMipsABIFromArch(ArchName); CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - llvm::StringRef MArch = A->getValue(Args); - CmdArgs.push_back("-target-cpu"); - - if ((MArch == "r2000") || (MArch == "r3000")) - CmdArgs.push_back("mips1"); - else if (MArch == "r6000") - CmdArgs.push_back("mips2"); - else - CmdArgs.push_back(Args.MakeArgString(MArch)); - } - // Select the float ABI as determined by -msoft-float, -mhard-float, and - llvm::StringRef FloatABI; + StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) @@ -718,7 +781,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, if (FloatABI.empty()) { // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; - D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; + D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; } if (FloatABI == "soft") { @@ -737,13 +800,13 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, const Driver &D = getToolChain().getDriver(); if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - llvm::StringRef MArch = A->getValue(Args); + StringRef MArch = A->getValue(Args); CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(MArch.str().c_str()); } // Select the float ABI as determined by -msoft-float, -mhard-float, and - llvm::StringRef FloatABI; + StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) @@ -758,7 +821,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, default: // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; - D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; + D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } @@ -792,7 +855,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, const char *CPUName = 0; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (llvm::StringRef(A->getValue(Args)) == "native") { + if (StringRef(A->getValue(Args)) == "native") { // FIXME: Reject attempts to use -march=native unless the target matches // the host. // @@ -808,7 +871,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, // Select the default CPU if none was given (or detection failed). if (!CPUName) { // FIXME: Need target hooks. - if (getToolChain().getOS().startswith("darwin")) { + if (getToolChain().getTriple().isOSDarwin()) { if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "core2"; else if (getToolChain().getArch() == llvm::Triple::x86) @@ -856,7 +919,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, std::vector<const char*> Features; for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), ie = Args.filtered_end(); it != ie; ++it) { - llvm::StringRef Name = (*it)->getOption().getName(); + StringRef Name = (*it)->getOption().getName(); (*it)->claim(); // Skip over "-m". @@ -881,7 +944,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } } -static bool +static bool shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion, const llvm::Triple &Triple) { // We use the zero-cost exception tables for Objective-C if the non-fragile @@ -891,12 +954,12 @@ shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion, if (objcABIVersion >= 2) return true; - if (Triple.getOS() != llvm::Triple::Darwin) + if (!Triple.isOSDarwin()) return false; return (!Triple.isMacOSXVersionLT(10,5) && (Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::arm)); + Triple.getArch() == llvm::Triple::arm)); } /// addExceptionArgs - Adds exception related arguments to the driver command @@ -922,7 +985,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, options::OPT_fno_exceptions)) { if (A->getOption().matches(options::OPT_fexceptions)) ExceptionsEnabled = true; - else + else ExceptionsEnabled = false; DidHaveExplicitExceptionFlag = true; @@ -938,20 +1001,20 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, // Obj-C exceptions are enabled by default, regardless of -fexceptions. This // is not necessarily sensible, but follows GCC. if (types::isObjC(InputType) && - Args.hasFlag(options::OPT_fobjc_exceptions, + Args.hasFlag(options::OPT_fobjc_exceptions, options::OPT_fno_objc_exceptions, true)) { CmdArgs.push_back("-fobjc-exceptions"); - ShouldUseExceptionTables |= + ShouldUseExceptionTables |= shouldUseExceptionTablesForObjCExceptions(objcABIVersion, Triple); } if (types::isCXX(InputType)) { bool CXXExceptionsEnabled = ExceptionsEnabled; - if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, - options::OPT_fno_cxx_exceptions, + if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, + options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions)) { if (A->getOption().matches(options::OPT_fcxx_exceptions)) @@ -973,7 +1036,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, static bool ShouldDisableCFI(const ArgList &Args, const ToolChain &TC) { - if (TC.getTriple().getOS() == llvm::Triple::Darwin) { + if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support cfi directives, so // we disable them if we think the .s file will be passed to it. @@ -1079,7 +1142,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { - llvm::StringRef Value = A->getValue(Args, i); + StringRef Value = A->getValue(Args, i); if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. @@ -1091,7 +1154,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (Value == "--noexecstack") { CmdArgs.push_back("-mnoexecstack"); } else { - D.Diag(clang::diag::err_drv_unsupported_option_argument) + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } } @@ -1217,7 +1280,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else Model = getToolChain().GetDefaultRelocationModel(); } - if (llvm::StringRef(Model) != "pic") { + if (StringRef(Model) != "pic") { CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back(Model); } @@ -1275,13 +1338,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable -mconstructor-aliases except on darwin, where we have to // work around a linker bug; see <rdar://problem/7651567>. - if (getToolChain().getTriple().getOS() != llvm::Triple::Darwin) + if (!getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we // try to use them. - if (KernelOrKext && - getToolChain().getTriple().getOS() == llvm::Triple::Darwin) + if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasArg(options::OPT_mms_bitfields)) { @@ -1325,6 +1387,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips: case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: AddMIPSTargetArgs(Args, CmdArgs); break; @@ -1347,7 +1411,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -mno-omit-leaf-frame-pointer is the default on Darwin. if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, - getToolChain().getTriple().getOS() != llvm::Triple::Darwin)) + !getToolChain().getTriple().isOSDarwin())) CmdArgs.push_back("-momit-leaf-frame-pointer"); // -fno-math-errno is default. @@ -1362,21 +1426,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_iframework))) - D.Diag(clang::diag::err_drv_clang_unsupported) + D.Diag(diag::err_drv_clang_unsupported) << Unsupported->getOption().getName(); if (types::isCXX(InputType) && - getToolChain().getTriple().getOS() == llvm::Triple::Darwin && + getToolChain().getTriple().isOSDarwin() && getToolChain().getTriple().getArch() == llvm::Triple::x86) { - if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext))) - D.Diag(clang::diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) + if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || + (Unsupported = Args.getLastArg(options::OPT_mkernel))) + D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) << Unsupported->getOption().getName(); } } Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_H); - if (D.CCPrintHeaders) { + if (D.CCPrintHeaders && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename : "-"); @@ -1384,7 +1449,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); - if (D.CCLogDiagnostics) { + if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { CmdArgs.push_back("-diagnostic-log-file"); CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename : "-"); @@ -1417,9 +1482,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddLastArg(CmdArgs, options::OPT_nostdinc); - Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); - Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); + // Pass options for controlling the default header search paths. + if (Args.hasArg(options::OPT_nostdinc)) { + CmdArgs.push_back("-nostdsysteminc"); + CmdArgs.push_back("-nobuiltininc"); + } else { + if (Args.hasArg(options::OPT_nostdlibinc)) + CmdArgs.push_back("-nostdsysteminc"); + Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); + Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); + } // Pass the path to compiler resource files. CmdArgs.push_back("-resource-dir"); @@ -1444,11 +1516,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arcmt-migrate"); CmdArgs.push_back("-arcmt-migrate-directory"); CmdArgs.push_back(A->getValue(Args)); + + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); break; } } } - + // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. // @@ -1456,6 +1531,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs); + // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes + // that "The compiler can only warn and ignore the option if not recognized". + // When building with ccache, it will pass -D options to clang even on + // preprocessed inputs and configure concludes that -fPIC is not supported. + Args.ClaimAllArgs(options::OPT_D); + // Manually translate -O to -O2 and -O4 to -O3; let clang reject // others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -1584,7 +1665,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. unsigned N = llvm::sys::Process::StandardErrColumns(); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); + CmdArgs.push_back(Args.MakeArgString(Twine(N))); } if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { @@ -1630,7 +1711,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -ftrap_function= options to the backend. if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) { - llvm::StringRef FuncName = A->getValue(Args); + StringRef FuncName = A->getValue(Args); CmdArgs.push_back("-backend-option"); CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName)); } @@ -1660,11 +1741,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StackProtectorLevel = 1; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = 2; - } else - StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel(); + } else { + StackProtectorLevel = + getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); + } if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector"); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel))); + CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); } // Translate -mstackrealign @@ -1672,7 +1755,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-force-align-stack"); } - + // Forward -f options with positive and negative forms; we translate // these by hand. @@ -1697,6 +1780,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasArg(options::OPT_fobjc_nonfragile_abi) && !Args.hasArg(options::OPT_fno_blocks))) { CmdArgs.push_back("-fblocks"); + + if (!Args.hasArg(options::OPT_fgnu_runtime) && + !getToolChain().hasBlocksRuntime()) + CmdArgs.push_back("-fblocks-runtime-optional"); } // -faccess-control is default. @@ -1744,11 +1831,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); + // -fms-compatibility=0 is default. + if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, + getToolChain().getTriple().getOS() == llvm::Triple::Win32)) + CmdArgs.push_back("-fms-compatibility"); + // -fmsc-version=1300 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32) || Args.hasArg(options::OPT_fmsc_version)) { - llvm::StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version); + StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version); if (msc_ver.empty()) CmdArgs.push_back("-fmsc-version=1300"); else @@ -1761,10 +1853,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); - // -fno-delayed-template-parsing is default. + // -fno-delayed-template-parsing is default, except for Windows where MSVC STL + // needs it. if (Args.hasFlag(options::OPT_fdelayed_template_parsing, options::OPT_fno_delayed_template_parsing, - false)) + getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fdelayed-template-parsing"); // -fgnu-keywords default varies depending on language; only pass if @@ -1781,96 +1874,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fobjc-nonfragile-abi=0 is default. ObjCRuntime objCRuntime; unsigned objcABIVersion = 0; - if (types::isObjC(InputType)) { - bool NeXTRuntimeIsDefault - = (IsRewriter || getToolChain().getTriple().isOSDarwin()); - if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, - NeXTRuntimeIsDefault)) { - objCRuntime.setKind(ObjCRuntime::NeXT); - } else { - CmdArgs.push_back("-fgnu-runtime"); - objCRuntime.setKind(ObjCRuntime::GNU); - } - getToolChain().configureObjCRuntime(objCRuntime); - if (objCRuntime.HasARC) - CmdArgs.push_back("-fobjc-runtime-has-arc"); - if (objCRuntime.HasWeak) - CmdArgs.push_back("-fobjc-runtime-has-weak"); - if (objCRuntime.HasTerminate) - CmdArgs.push_back("-fobjc-runtime-has-terminate"); - - // Compute the Objective-C ABI "version" to use. Version numbers are - // slightly confusing for historical reasons: - // 1 - Traditional "fragile" ABI - // 2 - Non-fragile ABI, version 1 - // 3 - Non-fragile ABI, version 2 - objcABIVersion = 1; - // If -fobjc-abi-version= is present, use that to set the version. - if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { - if (llvm::StringRef(A->getValue(Args)) == "1") - objcABIVersion = 1; - else if (llvm::StringRef(A->getValue(Args)) == "2") - objcABIVersion = 2; - else if (llvm::StringRef(A->getValue(Args)) == "3") - objcABIVersion = 3; - else - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); - } else { - // Otherwise, determine if we are using the non-fragile ABI. - if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi, - options::OPT_fno_objc_nonfragile_abi, - getToolChain().IsObjCNonFragileABIDefault())) { - // Determine the non-fragile ABI version to use. + bool NeXTRuntimeIsDefault + = (IsRewriter || getToolChain().getTriple().isOSDarwin()); + if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, + NeXTRuntimeIsDefault)) { + objCRuntime.setKind(ObjCRuntime::NeXT); + } else { + CmdArgs.push_back("-fgnu-runtime"); + objCRuntime.setKind(ObjCRuntime::GNU); + } + getToolChain().configureObjCRuntime(objCRuntime); + if (objCRuntime.HasARC) + CmdArgs.push_back("-fobjc-runtime-has-arc"); + if (objCRuntime.HasWeak) + CmdArgs.push_back("-fobjc-runtime-has-weak"); + if (objCRuntime.HasTerminate) + CmdArgs.push_back("-fobjc-runtime-has-terminate"); + + // Compute the Objective-C ABI "version" to use. Version numbers are + // slightly confusing for historical reasons: + // 1 - Traditional "fragile" ABI + // 2 - Non-fragile ABI, version 1 + // 3 - Non-fragile ABI, version 2 + objcABIVersion = 1; + // If -fobjc-abi-version= is present, use that to set the version. + if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { + if (StringRef(A->getValue(Args)) == "1") + objcABIVersion = 1; + else if (StringRef(A->getValue(Args)) == "2") + objcABIVersion = 2; + else if (StringRef(A->getValue(Args)) == "3") + objcABIVersion = 3; + else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + } else { + // Otherwise, determine if we are using the non-fragile ABI. + bool NonFragileABIIsDefault + = (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault()); + if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi, + options::OPT_fno_objc_nonfragile_abi, + NonFragileABIIsDefault)) { + // Determine the non-fragile ABI version to use. #ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO - unsigned NonFragileABIVersion = 1; + unsigned NonFragileABIVersion = 1; #else - unsigned NonFragileABIVersion = 2; + unsigned NonFragileABIVersion = 2; #endif - if (Arg *A = Args.getLastArg( - options::OPT_fobjc_nonfragile_abi_version_EQ)) { - if (llvm::StringRef(A->getValue(Args)) == "1") - NonFragileABIVersion = 1; - else if (llvm::StringRef(A->getValue(Args)) == "2") - NonFragileABIVersion = 2; - else - D.Diag(clang::diag::err_drv_clang_unsupported) - << A->getAsString(Args); - } - - objcABIVersion = 1 + NonFragileABIVersion; - } else { - objcABIVersion = 1; - } - } - - if (objcABIVersion == 2 || objcABIVersion == 3) { - CmdArgs.push_back("-fobjc-nonfragile-abi"); - - // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. - if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, - options::OPT_fno_objc_legacy_dispatch, - getToolChain().IsObjCLegacyDispatchDefault())) { - if (getToolChain().UseObjCMixedDispatch()) - CmdArgs.push_back("-fobjc-dispatch-method=mixed"); + if (Arg *A = Args.getLastArg( + options::OPT_fobjc_nonfragile_abi_version_EQ)) { + if (StringRef(A->getValue(Args)) == "1") + NonFragileABIVersion = 1; + else if (StringRef(A->getValue(Args)) == "2") + NonFragileABIVersion = 2; else - CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); + D.Diag(diag::err_drv_clang_unsupported) + << A->getAsString(Args); } + + objcABIVersion = 1 + NonFragileABIVersion; + } else { + objcABIVersion = 1; } + } - // FIXME: Don't expose -fobjc-default-synthesize-properties as a top-level - // driver flag yet. This feature is still under active development - // and shouldn't be exposed as a user visible feature (which may change). - // Clang still supports this as a -cc1 option for development and testing. -#if 0 - // -fobjc-default-synthesize-properties=0 is default. - if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties, - options::OPT_fno_objc_default_synthesize_properties, - getToolChain().IsObjCDefaultSynthPropertiesDefault())) { - CmdArgs.push_back("-fobjc-default-synthesize-properties"); + if (objcABIVersion == 1) { + CmdArgs.push_back("-fobjc-fragile-abi"); + } else { + // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and + // legacy is the default. + if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, + options::OPT_fno_objc_legacy_dispatch, + getToolChain().IsObjCLegacyDispatchDefault())) { + if (getToolChain().UseObjCMixedDispatch()) + CmdArgs.push_back("-fobjc-dispatch-method=mixed"); + else + CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); } -#endif + } + + // -fobjc-default-synthesize-properties=0 is default. + if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties, + options::OPT_fno_objc_default_synthesize_properties, + getToolChain().IsObjCDefaultSynthPropertiesDefault())) { + CmdArgs.push_back("-fobjc-default-synthesize-properties"); } // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. @@ -1891,7 +1978,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // rewriter. if (IsRewriter) CmdArgs.push_back("-fno-objc-infer-related-result-type"); - + // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only // takes precedence. const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); @@ -1899,13 +1986,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, GCArg = Args.getLastArg(options::OPT_fobjc_gc); if (GCArg) { if (ARC) { - D.Diag(clang::diag::err_drv_objc_gc_arr) + D.Diag(diag::err_drv_objc_gc_arr) << GCArg->getAsString(Args); } else if (getToolChain().SupportsObjCGC()) { GCArg->render(Args, CmdArgs); } else { // FIXME: We should move this to a hard error. - D.Diag(clang::diag::warn_drv_objc_gc_unsupported) + D.Diag(diag::warn_drv_objc_gc_unsupported) << GCArg->getAsString(Args); } } @@ -1948,11 +2035,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fpascal-strings"); + // Honor -fpack-struct= and -fpack-struct, if given. Note that + // -fno-pack-struct doesn't apply to -fpack-struct=. + if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { + CmdArgs.push_back("-fpack-struct"); + CmdArgs.push_back(A->getValue(Args)); + } else if (Args.hasFlag(options::OPT_fpack_struct, + options::OPT_fno_pack_struct, false)) { + CmdArgs.push_back("-fpack-struct"); + CmdArgs.push_back("1"); + } + if (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); } + // -fcommon is default, only pass non-default. else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common)) CmdArgs.push_back("-fno-common"); @@ -1961,13 +2060,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, options::OPT_funsigned_bitfields)) - D.Diag(clang::diag::warn_drv_clang_unsupported) + D.Diag(diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) - D.Diag(clang::diag::err_drv_clang_unsupported) + D.Diag(diag::err_drv_clang_unsupported) << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); // -fcaret-diagnostics is default. @@ -1979,7 +2078,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); - + // Enable -fdiagnostics-show-name by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_name, options::OPT_fno_diagnostics_show_name, false)) @@ -2055,14 +2154,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, options::OPT_fno_unit_at_a_time)) { if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) - D.Diag(clang::diag::warn_drv_clang_unsupported) << A->getAsString(Args); + D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); } // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 - if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin && + if (getToolChain().getTriple().isOSDarwin() && (getToolChain().getTriple().getArch() == llvm::Triple::arm || getToolChain().getTriple().getArch() == llvm::Triple::thumb)) { if (!Args.hasArg(options::OPT_fbuiltin_strcat)) @@ -2077,8 +2176,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_traditional_cpp)) { if (isa<PreprocessJobAction>(JA)) CmdArgs.push_back("-traditional-cpp"); - else - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } Args.AddLastArg(CmdArgs, options::OPT_dM); @@ -2093,7 +2192,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We translate this by hand to the -cc1 argument, since nightly test uses // it and developers have been trained to spell it with -mllvm. - if (llvm::StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns") + if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns") CmdArgs.push_back("-disable-llvm-optzns"); else (*it)->render(Args, CmdArgs); @@ -2145,7 +2244,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) + D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" << A->getAsString(Args); // Claim some arguments which clang supports automatically. @@ -2189,7 +2288,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); - std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + std::string TripleStr = + getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Set the output mode, we currently only expect to be used as a real @@ -2252,7 +2352,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // If using a driver driver, force the arch. const std::string &Arch = getToolChain().getArchName(); - if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin) { + if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); // FIXME: Remove these special cases. @@ -2298,10 +2398,10 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // Don't try to pass LLVM or AST inputs to a generic gcc. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) - D.Diag(clang::diag::err_drv_no_linker_llvm_support) + D.Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) - D.Diag(clang::diag::err_drv_no_ast_support) + D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { @@ -2364,7 +2464,7 @@ void gcc::Compile::RenderExtraToolArgs(const JobAction &JA, CmdArgs.push_back("-c"); else { if (JA.getType() != types::TY_PP_Asm) - D.Diag(clang::diag::err_drv_invalid_gcc_output_type) + D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); CmdArgs.push_back("-S"); @@ -2384,19 +2484,21 @@ void gcc::Link::RenderExtraToolArgs(const JobAction &JA, const char *darwin::CC1::getCC1Name(types::ID Type) const { switch (Type) { default: - assert(0 && "Unexpected type for Darwin CC1 tool."); + llvm_unreachable("Unexpected type for Darwin CC1 tool."); case types::TY_Asm: case types::TY_C: case types::TY_CHeader: case types::TY_PP_C: case types::TY_PP_CHeader: return "cc1"; case types::TY_ObjC: case types::TY_ObjCHeader: - case types::TY_PP_ObjC: case types::TY_PP_ObjCHeader: + case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias: + case types::TY_PP_ObjCHeader: return "cc1obj"; case types::TY_CXX: case types::TY_CXXHeader: case types::TY_PP_CXX: case types::TY_PP_CXXHeader: return "cc1plus"; case types::TY_ObjCXX: case types::TY_ObjCXXHeader: - case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXXHeader: + case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias: + case types::TY_PP_ObjCXXHeader: return "cc1objplus"; } } @@ -2425,14 +2527,145 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { std::string Str(OutputOpt->getValue(Args)); - Res = Str.substr(0, Str.rfind('.')); - } else + } else { Res = darwin::CC1::getBaseInputStem(Args, Inputs); - + } return Args.MakeArgString(Res + ".d"); } +void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const { + for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end(); + it != ie;) { + + StringRef Option = *it; + bool RemoveOption = false; + + // Remove -faltivec + if (Option.equals("-faltivec")) { + it = CmdArgs.erase(it); + ie = CmdArgs.end(); + continue; + } + + // Handle machine specific options. + if (Option.startswith("-m")) { + RemoveOption = llvm::StringSwitch<bool>(Option) + .Case("-mthumb", true) + .Case("-mno-thumb", true) + .Case("-mno-fused-madd", true) + .Case("-mlong-branch", true) + .Case("-mlongcall", true) + .Case("-mcpu=G4", true) + .Case("-mcpu=G5", true) + .Default(false); + } + + // Handle warning options. + if (Option.startswith("-W")) { + // Remove -W/-Wno- to reduce the number of cases. + if (Option.startswith("-Wno-")) + Option = Option.substr(5); + else + Option = Option.substr(2); + + RemoveOption = llvm::StringSwitch<bool>(Option) + .Case("address-of-temporary", true) + .Case("ambiguous-member-template", true) + .Case("analyzer-incompatible-plugin", true) + .Case("array-bounds", true) + .Case("array-bounds-pointer-arithmetic", true) + .Case("bind-to-temporary-copy", true) + .Case("bitwise-op-parentheses", true) + .Case("bool-conversions", true) + .Case("builtin-macro-redefined", true) + .Case("c++-hex-floats", true) + .Case("c++0x-compat", true) + .Case("c++0x-extensions", true) + .Case("c++0x-narrowing", true) + .Case("c++11-compat", true) + .Case("c++11-extensions", true) + .Case("c++11-narrowing", true) + .Case("conditional-uninitialized", true) + .Case("constant-conversion", true) + .Case("CFString-literal", true) + .Case("constant-logical-operand", true) + .Case("custom-atomic-properties", true) + .Case("default-arg-special-member", true) + .Case("delegating-ctor-cycles", true) + .Case("delete-non-virtual-dtor", true) + .Case("deprecated-implementations", true) + .Case("deprecated-writable-strings", true) + .Case("distributed-object-modifiers", true) + .Case("duplicate-method-arg", true) + .Case("dynamic-class-memaccess", true) + .Case("enum-compare", true) + .Case("exit-time-destructors", true) + .Case("gnu", true) + .Case("gnu-designator", true) + .Case("header-hygiene", true) + .Case("idiomatic-parentheses", true) + .Case("ignored-qualifiers", true) + .Case("implicit-atomic-properties", true) + .Case("incompatible-pointer-types", true) + .Case("incomplete-implementation", true) + .Case("initializer-overrides", true) + .Case("invalid-noreturn", true) + .Case("invalid-token-paste", true) + .Case("language-extension-token", true) + .Case("literal-conversion", true) + .Case("literal-range", true) + .Case("local-type-template-args", true) + .Case("logical-op-parentheses", true) + .Case("method-signatures", true) + .Case("microsoft", true) + .Case("mismatched-tags", true) + .Case("missing-method-return-type", true) + .Case("non-pod-varargs", true) + .Case("nonfragile-abi2", true) + .Case("null-arithmetic", true) + .Case("null-dereference", true) + .Case("out-of-line-declaration", true) + .Case("overriding-method-mismatch", true) + .Case("readonly-setter-attrs", true) + .Case("return-stack-address", true) + .Case("self-assign", true) + .Case("semicolon-before-method-body", true) + .Case("sentinel", true) + .Case("shift-overflow", true) + .Case("shift-sign-overflow", true) + .Case("sign-conversion", true) + .Case("sizeof-array-argument", true) + .Case("sizeof-pointer-memaccess", true) + .Case("string-compare", true) + .Case("super-class-method-mismatch", true) + .Case("tautological-compare", true) + .Case("typedef-redefinition", true) + .Case("typename-missing", true) + .Case("undefined-reinterpret-cast", true) + .Case("unknown-warning-option", true) + .Case("unnamed-type-template-args", true) + .Case("unneeded-internal-declaration", true) + .Case("unneeded-member-function", true) + .Case("unused-comparison", true) + .Case("unused-exception-parameter", true) + .Case("unused-member-function", true) + .Case("unused-result", true) + .Case("vector-conversions", true) + .Case("vla", true) + .Case("used-but-marked-unused", true) + .Case("weak-vtables", true) + .Default(false); + } // if (Option.startswith("-W")) + if (RemoveOption) { + it = CmdArgs.erase(it); + ie = CmdArgs.end(); + } else { + ++it; + } + } +} + void darwin::CC1::AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); @@ -2470,7 +2703,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-fomit-frame-pointer"; AddCC1Args(Args, CmdArgs); @@ -2742,6 +2975,8 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_d_Group); + RemoveCC1UnsupportedArgs(CmdArgs); + const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); @@ -2761,7 +2996,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, types::ID InputType = Inputs[0].getType(); const Arg *A; if ((A = Args.getLastArg(options::OPT_traditional))) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; if (JA.getType() == types::TY_LLVM_IR || @@ -2771,11 +3006,11 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, JA.getType() == types::TY_LTO_BC) CmdArgs.push_back("-emit-llvm-bc"); else if (Output.getType() == types::TY_AST) - D.Diag(clang::diag::err_drv_no_ast_support) + D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); else if (JA.getType() != types::TY_PP_Asm && JA.getType() != types::TY_PCH) - D.Diag(clang::diag::err_drv_invalid_gcc_output_type) + D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); ArgStringList OutputArgs; @@ -2809,7 +3044,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, // Reject AST inputs. if (II.getType() == types::TY_AST) { - D.Diag(clang::diag::err_drv_no_ast_support) + D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); return; } @@ -2831,12 +3066,23 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); // NOTE: gcc uses a temp .s file for this, but there doesn't seem // to be a good reason. - CmdArgs.push_back("/dev/null"); + const char *TmpPath = C.getArgs().MakeArgString( + D.GetTemporaryPath("cc", "s")); + C.addTempFile(TmpPath); + CmdArgs.push_back(TmpPath); - CmdArgs.push_back("--output-pch="); - CmdArgs.push_back(Output.getFilename()); + // If we're emitting a pch file with the last 4 characters of ".pth" + // and falling back to llvm-gcc we want to use ".gch" instead. + std::string OutputFile(Output.getFilename()); + size_t loc = OutputFile.rfind(".pth"); + if (loc != std::string::npos) + OutputFile.replace(loc, 4, ".gch"); + const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile); + CmdArgs.push_back(Tmp); } + RemoveCC1UnsupportedArgs(CmdArgs); + const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); @@ -2861,7 +3107,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } // Forward -g, assuming we are dealing with an actual assembly file. - if (SourceAction->getType() == types::TY_Asm || + if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { if (Args.hasArg(options::OPT_gstabs)) CmdArgs.push_back("--gstabs"); @@ -2903,7 +3149,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const { - llvm::StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args); + StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args); // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); @@ -2926,7 +3172,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0], Version[1], Version[2], HadExtra) || HadExtra) - D.Diag(clang::diag::err_drv_invalid_version_number) + D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); } @@ -2950,7 +3196,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - if (llvm::StringRef(A->getValue(Args, i)) == "-kext") + if (StringRef(A->getValue(Args, i)) == "-kext") UsesLdClassic = true; } } @@ -2963,7 +3209,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, // dsymutil step. if (Version[0] >= 116 && D.IsUsingLTO(Args)) { const char *TmpPath = C.getArgs().MakeArgString( - D.GetTemporaryPath(types::getTypeTempSuffix(types::TY_Object))); + D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); CmdArgs.push_back("-object_path_lto"); CmdArgs.push_back(TmpPath); @@ -2991,7 +3237,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, if ((A = Args.getLastArg(options::OPT_compatibility__version)) || (A = Args.getLastArg(options::OPT_current__version)) || (A = Args.getLastArg(options::OPT_install__name))) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); @@ -3007,7 +3253,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, (A = Args.getLastArg(options::OPT_force__flat__namespace)) || (A = Args.getLastArg(options::OPT_keep__private__externs)) || (A = Args.getLastArg(options::OPT_private__bundle))) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, @@ -3054,9 +3300,9 @@ void darwin::Link::AddLinkArgs(Compilation &C, CmdArgs.push_back("-iphoneos_version_min"); else CmdArgs.push_back("-macosx_version_min"); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine(TargetVersion[0]) + "." + - llvm::Twine(TargetVersion[1]) + "." + - llvm::Twine(TargetVersion[2]))); + CmdArgs.push_back(Args.MakeArgString(Twine(TargetVersion[0]) + "." + + Twine(TargetVersion[1]) + "." + + Twine(TargetVersion[2]))); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); @@ -3139,6 +3385,18 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // more information. ArgStringList CmdArgs; + /// Hack(tm) to ignore linking errors when we are doing ARC migration. + if (Args.hasArg(options::OPT_ccc_arcmt_check, + options::OPT_ccc_arcmt_migrate)) { + for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) + (*I)->claim(); + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("touch")); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + return; + } + // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs); @@ -3346,6 +3604,26 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } +void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + CmdArgs.push_back("--verify"); + + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Unexpected verify input"); + + // Grabbing the output of the earlier dsymutil run. + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} + void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -3664,9 +3942,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("gcrt1.o"))); - else + else { + const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o"; CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crt1.o"))); + getToolChain().GetFilePath(crt))); + } CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( @@ -3683,7 +3963,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const ToolChain::path_list Paths = getToolChain().getFilePaths(); for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) - CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i)); + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); @@ -3798,9 +4078,7 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); } - const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), - ToolTriple.getTriple(), - "as")); + const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3916,9 +4194,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); - const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), - ToolTriple.getTriple(), - "ld")); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3936,7 +4212,7 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } else if (getToolChain().getArch() == llvm::Triple::x86_64) { CmdArgs.push_back("--64"); } else if (getToolChain().getArch() == llvm::Triple::arm) { - llvm::StringRef MArch = getToolChain().getArchName(); + StringRef MArch = getToolChain().getArchName(); if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") CmdArgs.push_back("-mfpu=neon"); } @@ -4000,7 +4276,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-m"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("elf_i386"); - else if (ToolChain.getArch() == llvm::Triple::arm + else if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("armelf_linux_eabi"); else if (ToolChain.getArch() == llvm::Triple::ppc) @@ -4071,7 +4347,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) - CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i)); + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 1741d05..a4f732e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -178,6 +178,7 @@ namespace darwin { const char *getCC1Name(types::ID Type) const; void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const; + void RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const; void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, const ArgStringList &OutputArgs) const; @@ -276,6 +277,21 @@ namespace darwin { const ArgList &TCArgs, const char *LinkingOutput) const; }; + + class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool { + public: + VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug", + "dwarfdump", TC) {} + + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; + } /// openbsd -- Directly call GNU Binutils assembler and linker diff --git a/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp index 4a4312b..d61ab68 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Types.cpp @@ -79,10 +79,11 @@ bool types::isAcceptedByClang(ID Id) { case TY_C: case TY_PP_C: case TY_CL: case TY_CUDA: - case TY_ObjC: case TY_PP_ObjC: + case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: case TY_CXX: case TY_PP_CXX: - case TY_ObjCXX: case TY_PP_ObjCXX: + case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CHeader: case TY_PP_CHeader: + case TY_CLHeader: case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: @@ -110,10 +111,10 @@ bool types::isObjC(ID Id) { default: return false; - case TY_ObjC: case TY_PP_ObjC: + case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: case TY_ObjCXX: case TY_PP_ObjCXX: case TY_ObjCHeader: case TY_PP_ObjCHeader: - case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_PP_ObjCXX_Alias: return true; } } @@ -144,6 +145,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("F", TY_Fortran) .Case("s", TY_PP_Asm) .Case("S", TY_Asm) + .Case("o", TY_Object) .Case("ii", TY_PP_CXX) .Case("mi", TY_PP_ObjC) .Case("mm", TY_ObjCXX) diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp index 28d312a..54bb282 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -31,22 +31,23 @@ using namespace clang; namespace { class ASTPrinter : public ASTConsumer { - llvm::raw_ostream &Out; + raw_ostream &Out; bool Dump; public: - ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false) + ASTPrinter(raw_ostream* o = NULL, bool Dump = false) : Out(o? *o : llvm::outs()), Dump(Dump) { } virtual void HandleTranslationUnit(ASTContext &Context) { - PrintingPolicy Policy = Context.PrintingPolicy; + PrintingPolicy Policy = Context.getPrintingPolicy(); Policy.Dump = Dump; - Context.getTranslationUnitDecl()->print(Out, Policy); + Context.getTranslationUnitDecl()->print(Out, Policy, /*Indentation=*/0, + /*PrintInstantiation=*/true); } }; } // end anonymous namespace -ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) { +ASTConsumer *clang::CreateASTPrinter(raw_ostream* out) { return new ASTPrinter(out); } @@ -95,7 +96,7 @@ ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); } namespace { class DeclContextPrinter : public ASTConsumer { - llvm::raw_ostream& Out; + raw_ostream& Out; public: DeclContextPrinter() : Out(llvm::errs()) {} @@ -117,34 +118,34 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, case Decl::Namespace: { Out << "[namespace] "; const NamespaceDecl* ND = cast<NamespaceDecl>(DC); - Out << ND; + Out << *ND; break; } case Decl::Enum: { const EnumDecl* ED = cast<EnumDecl>(DC); - if (ED->isDefinition()) + if (ED->isCompleteDefinition()) Out << "[enum] "; else Out << "<enum> "; - Out << ED; + Out << *ED; break; } case Decl::Record: { const RecordDecl* RD = cast<RecordDecl>(DC); - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) Out << "[struct] "; else Out << "<struct> "; - Out << RD; + Out << *RD; break; } case Decl::CXXRecord: { const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC); - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) Out << "[class] "; else Out << "<class> "; - Out << RD << ' ' << DC; + Out << *RD << ' ' << DC; break; } case Decl::ObjCMethod: @@ -177,7 +178,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[function] "; else Out << "<function> "; - Out << FD; + Out << *FD; // Print the parameters. Out << "("; bool PrintComma = false; @@ -187,7 +188,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; break; @@ -200,7 +201,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ method) "; else Out << "<c++ method> "; - Out << D; + Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -210,7 +211,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; @@ -230,7 +231,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ ctor) "; else Out << "<c++ ctor> "; - Out << D; + Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -240,7 +241,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; @@ -259,7 +260,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ dtor) "; else Out << "<c++ dtor> "; - Out << D; + Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -275,7 +276,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ conversion) "; else Out << "<c++ conversion> "; - Out << D; + Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -285,7 +286,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } default: - assert(0 && "a decl that inherits DeclContext isn't handled"); + llvm_unreachable("a decl that inherits DeclContext isn't handled"); } Out << "\n"; @@ -322,53 +323,53 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::IndirectField: { IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I); - Out << "<IndirectField> " << IFD << '\n'; + Out << "<IndirectField> " << *IFD << '\n'; break; } case Decl::Label: { LabelDecl *LD = cast<LabelDecl>(*I); - Out << "<Label> " << LD << '\n'; + Out << "<Label> " << *LD << '\n'; break; } case Decl::Field: { FieldDecl *FD = cast<FieldDecl>(*I); - Out << "<field> " << FD << '\n'; + Out << "<field> " << *FD << '\n'; break; } case Decl::Typedef: case Decl::TypeAlias: { TypedefNameDecl* TD = cast<TypedefNameDecl>(*I); - Out << "<typedef> " << TD << '\n'; + Out << "<typedef> " << *TD << '\n'; break; } case Decl::EnumConstant: { EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I); - Out << "<enum constant> " << ECD << '\n'; + Out << "<enum constant> " << *ECD << '\n'; break; } case Decl::Var: { VarDecl* VD = cast<VarDecl>(*I); - Out << "<var> " << VD << '\n'; + Out << "<var> " << *VD << '\n'; break; } case Decl::ImplicitParam: { ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I); - Out << "<implicit parameter> " << IPD << '\n'; + Out << "<implicit parameter> " << *IPD << '\n'; break; } case Decl::ParmVar: { ParmVarDecl* PVD = cast<ParmVarDecl>(*I); - Out << "<parameter> " << PVD << '\n'; + Out << "<parameter> " << *PVD << '\n'; break; } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); - Out << "<objc property> " << OPD << '\n'; + Out << "<objc property> " << *OPD << '\n'; break; } case Decl::FunctionTemplate: { FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); - Out << "<function template> " << FTD << '\n'; + Out << "<function template> " << *FTD << '\n'; break; } case Decl::FileScopeAsm: { @@ -381,17 +382,17 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::NamespaceAlias: { NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I); - Out << "<namespace alias> " << NAD << '\n'; + Out << "<namespace alias> " << *NAD << '\n'; break; } case Decl::ClassTemplate: { ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); - Out << "<class template> " << CTD << '\n'; + Out << "<class template> " << *CTD << '\n'; break; } default: Out << "DeclKind: " << DK << '"' << *I << "\"\n"; - assert(0 && "decl unhandled"); + llvm_unreachable("decl unhandled"); } } } @@ -404,10 +405,10 @@ ASTConsumer *clang::CreateDeclContextPrinter() { namespace { class ASTDumpXML : public ASTConsumer { - llvm::raw_ostream &OS; + raw_ostream &OS; public: - ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {} + ASTDumpXML(raw_ostream &OS) : OS(OS) {} void HandleTranslationUnit(ASTContext &C) { C.getTranslationUnitDecl()->dumpXML(OS); @@ -415,6 +416,6 @@ public: }; } -ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) { +ASTConsumer *clang::CreateASTDumperXML(raw_ostream &OS) { return new ASTDumpXML(OS); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp index 3905b99..cb195d1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp @@ -17,12 +17,12 @@ using namespace clang; ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return AdaptedAction->CreateASTConsumer(CI, InFile); } bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, - llvm::StringRef Filename) { + StringRef Filename) { // FIXME: This is a hack. We need a better way to communicate the // AST file, compiler instance, and file name than member variables // of FrontendAction. @@ -41,8 +41,8 @@ void ASTMergeAction::ExecuteAction() { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(CI.getDiagnostics().getDiagnosticIDs()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { - llvm::IntrusiveRefCntPtr<Diagnostic> - Diags(new Diagnostic(DiagIDs, CI.getDiagnostics().getClient(), + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(), /*ShouldOwnClient=*/false)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); @@ -93,8 +93,8 @@ bool ASTMergeAction::usesPreprocessorOnly() const { return AdaptedAction->usesPreprocessorOnly(); } -bool ASTMergeAction::usesCompleteTranslationUnit() { - return AdaptedAction->usesCompleteTranslationUnit(); +TranslationUnitKind ASTMergeAction::getTranslationUnitKind() { + return AdaptedAction->getTranslationUnitKind(); } bool ASTMergeAction::hasPCHSupport() const { diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 5b0a52c..032adf3 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -29,7 +29,6 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/ASTSerializationListener.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -45,6 +44,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Mutex.h" #include "llvm/Support/CrashRecoveryContext.h" #include <cstdlib> #include <cstdio> @@ -65,7 +66,7 @@ namespace { Start = TimeRecord::getCurrentTime(); } - void setOutput(const llvm::Twine &Output) { + void setOutput(const Twine &Output) { if (WantTiming) this->Output = Output.str(); } @@ -96,10 +97,9 @@ static llvm::sys::cas_flag ActiveASTUnitObjects; ASTUnit::ASTUnit(bool _MainFileIsAST) : OnlyLocalDecls(false), CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), - CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")), + TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")), OwnsRemappedFileBuffers(true), NumStoredDiagnosticsFromDriver(0), - ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), ShouldCacheCodeCompletionResults(false), NestedMacroExpansions(true), @@ -114,7 +114,6 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) } ASTUnit::~ASTUnit() { - ConcurrencyCheckValue = CheckLocked; CleanTemporaryFiles(); if (!PreambleFile.empty()) llvm::sys::Path(PreambleFile).eraseFromDisk(); @@ -185,7 +184,7 @@ static unsigned getDeclShowContexts(NamedDecl *ND, // In Objective-C, you can only be a subclass of another Objective-C class if (isa<ObjCInterfaceDecl>(ND)) - Contexts |= (1 << (CodeCompletionContext::CCC_ObjCSuperclass - 1)); + Contexts |= (1 << (CodeCompletionContext::CCC_ObjCInterfaceName - 1)); // Deal with tag names. if (isa<EnumDecl>(ND)) { @@ -236,7 +235,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Gather the set of global code completions. typedef CodeCompletionResult Result; - llvm::SmallVector<Result, 8> Results; + SmallVector<Result, 8> Results; CachedCompletionAllocator = new GlobalCodeCompletionAllocator; TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results); @@ -375,33 +374,61 @@ namespace { /// \brief Gathers information from ASTReader that will be used to initialize /// a Preprocessor. class ASTInfoCollector : public ASTReaderListener { + Preprocessor &PP; + ASTContext &Context; LangOptions &LangOpt; HeaderSearch &HSI; - std::string &TargetTriple; + llvm::IntrusiveRefCntPtr<TargetInfo> &Target; std::string &Predefines; unsigned &Counter; unsigned NumHeaderInfos; + bool InitializedLanguage; public: - ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, - std::string &TargetTriple, std::string &Predefines, + ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, + HeaderSearch &HSI, + llvm::IntrusiveRefCntPtr<TargetInfo> &Target, + std::string &Predefines, unsigned &Counter) - : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), - Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} + : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target), + Predefines(Predefines), Counter(Counter), NumHeaderInfos(0), + InitializedLanguage(false) {} virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + if (InitializedLanguage) + return false; + LangOpt = LangOpts; + + // Initialize the preprocessor. + PP.Initialize(*Target); + + // Initialize the ASTContext + Context.InitBuiltinTypes(*Target); + + InitializedLanguage = true; return false; } - virtual bool ReadTargetTriple(llvm::StringRef Triple) { - TargetTriple = Triple; + virtual bool ReadTargetTriple(StringRef Triple) { + // If we've already initialized the target, don't do it again. + if (Target) + return false; + + // FIXME: This is broken, we should store the TargetOptions in the AST file. + TargetOptions TargetOpts; + TargetOpts.ABI = ""; + TargetOpts.CXXABI = ""; + TargetOpts.CPU = ""; + TargetOpts.Features.clear(); + TargetOpts.Triple = Triple; + Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts); return false; } virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - llvm::StringRef OriginalFileName, + StringRef OriginalFileName, std::string &SuggestedPredefines, FileManager &FileMgr) { Predefines = Buffers[0].Data; @@ -420,28 +447,34 @@ public: } }; -class StoredDiagnosticClient : public DiagnosticClient { - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags; +class StoredDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl<StoredDiagnostic> &StoredDiags; public: - explicit StoredDiagnosticClient( - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + explicit StoredDiagnosticConsumer( + SmallVectorImpl<StoredDiagnostic> &StoredDiags) : StoredDiags(StoredDiags) { } - virtual void HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info); + virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; /// \brief RAII object that optionally captures diagnostics, if /// there is no diagnostic client to capture them already. class CaptureDroppedDiagnostics { - Diagnostic &Diags; - StoredDiagnosticClient Client; - DiagnosticClient *PreviousClient; + DiagnosticsEngine &Diags; + StoredDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient; public: - CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, + SmallVectorImpl<StoredDiagnostic> &StoredDiags) : Diags(Diags), Client(StoredDiags), PreviousClient(0) { if (RequestCapture || Diags.getClient() == 0) { @@ -460,10 +493,10 @@ public: } // anonymous namespace -void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); StoredDiags.push_back(StoredDiagnostic(Level, Info)); } @@ -472,37 +505,32 @@ const std::string &ASTUnit::getOriginalSourceFileName() { return OriginalSourceFile; } -const std::string &ASTUnit::getASTFileName() { - assert(isMainFileAST() && "Not an ASTUnit from an AST file!"); - return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName(); -} - -llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename, +llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename, std::string *ErrorStr) { assert(FileMgr); return FileMgr->getBufferForFile(Filename, ErrorStr); } /// \brief Configure the diagnostics object for use with ASTUnit. -void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags, +void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, const char **ArgBegin, const char **ArgEnd, ASTUnit &AST, bool CaptureDiagnostics) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. DiagnosticOptions DiagOpts; - DiagnosticClient *Client = 0; + DiagnosticConsumer *Client = 0; if (CaptureDiagnostics) - Client = new StoredDiagnosticClient(AST.StoredDiagnostics); + Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin, ArgBegin, Client); } else if (CaptureDiagnostics) { - Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics)); + Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } } ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls, RemappedFile *RemappedFiles, @@ -513,8 +541,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); @@ -576,25 +604,41 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Gather Info for preprocessor construction later on. - LangOptions LangInfo; HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); - std::string TargetTriple; std::string Predefines; unsigned Counter; llvm::OwningPtr<ASTReader> Reader; - Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(), - AST->getDiagnostics())); + AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts, + /*Target=*/0, AST->getSourceManager(), HeaderInfo, + *AST, + /*IILookup=*/0, + /*OwnsHeaderSearch=*/false, + /*DelayInitialization=*/true); + Preprocessor &PP = *AST->PP; + + AST->Ctx = new ASTContext(AST->ASTFileLangOpts, + AST->getSourceManager(), + /*Target=*/0, + PP.getIdentifierTable(), + PP.getSelectorTable(), + PP.getBuiltinInfo(), + /* size_reserve = */0, + /*DelayInitialization=*/true); + ASTContext &Context = *AST->Ctx; + + Reader.reset(new ASTReader(PP, Context)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTReader> ReaderCleanup(Reader.get()); - Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple, - Predefines, Counter)); + Reader->setListener(new ASTInfoCollector(*AST->PP, Context, + AST->ASTFileLangOpts, HeaderInfo, + AST->Target, Predefines, Counter)); - switch (Reader->ReadAST(Filename, ASTReader::MainFile)) { + switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) { case ASTReader::Success: break; @@ -606,39 +650,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->OriginalSourceFile = Reader->getOriginalSourceFile(); - // AST file loaded successfully. Now create the preprocessor. - - // Get information about the target being compiled for. - // - // FIXME: This is broken, we should store the TargetOptions in the AST file. - TargetOptions TargetOpts; - TargetOpts.ABI = ""; - TargetOpts.CXXABI = ""; - TargetOpts.CPU = ""; - TargetOpts.Features.clear(); - TargetOpts.Triple = TargetTriple; - AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(), - TargetOpts); - AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target, - AST->getSourceManager(), HeaderInfo); - Preprocessor &PP = *AST->PP; - PP.setPredefines(Reader->getSuggestedPredefines()); PP.setCounterValue(Counter); - Reader->setPreprocessor(PP); - - // Create and initialize the ASTContext. - - AST->Ctx = new ASTContext(LangInfo, - AST->getSourceManager(), - *AST->Target, - PP.getIdentifierTable(), - PP.getSelectorTable(), - PP.getBuiltinInfo(), - /* size_reserve = */0); - ASTContext &Context = *AST->Ctx; - - Reader->InitializeContext(Context); // Attach the AST reader to the AST context as an external AST // source, so that declarations will be deserialized from the @@ -710,10 +723,8 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) { return; } - if (ObjCClassDecl *Class = llvm::dyn_cast<ObjCClassDecl>(D)) { - for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); - I != IEnd; ++I) - AddTopLevelDeclarationToHash(I->getInterface(), Hash); + if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(D)) { + AddTopLevelDeclarationToHash(Class->getForwardInterfaceDecl(), Hash); return; } } @@ -752,7 +763,7 @@ public: ASTUnit &Unit; virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { CI.getPreprocessor().addPPCallbacks( new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); return new TopLevelDeclTrackerConsumer(Unit, @@ -763,22 +774,20 @@ public: TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} virtual bool hasCodeCompletionSupport() const { return false; } - virtual bool usesCompleteTranslationUnit() { - return Unit.isCompleteTranslationUnit(); + virtual TranslationUnitKind getTranslationUnitKind() { + return Unit.getTranslationUnitKind(); } }; -class PrecompilePreambleConsumer : public PCHGenerator, - public ASTSerializationListener { +class PrecompilePreambleConsumer : public PCHGenerator { ASTUnit &Unit; unsigned &Hash; std::vector<Decl *> TopLevelDecls; public: - PrecompilePreambleConsumer(ASTUnit &Unit, - const Preprocessor &PP, bool Chaining, - const char *isysroot, llvm::raw_ostream *Out) - : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit), + PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, + StringRef isysroot, raw_ostream *Out) + : PCHGenerator(PP, "", /*IsModule=*/false, isysroot, Out), Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()) { Hash = 0; } @@ -809,15 +818,6 @@ public: getWriter().getDeclID(TopLevelDecls[I])); } } - - virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity, - uint64_t Offset) { - Unit.addPreprocessedEntityFromPreamble(Offset); - } - - virtual ASTSerializationListener *GetASTSerializationListener() { - return this; - } }; class PrecompilePreambleAction : public ASTFrontendAction { @@ -827,27 +827,27 @@ public: explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {} virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { std::string Sysroot; std::string OutputFile; - llvm::raw_ostream *OS = 0; - bool Chaining; + raw_ostream *OS = 0; if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, - OS, Chaining)) + OS)) return 0; - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + CI.getPreprocessor().addPPCallbacks( new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); - return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining, - isysroot, OS); + return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot, + OS); } virtual bool hasCodeCompletionSupport() const { return false; } virtual bool hasASTFileSupport() const { return false; } - virtual bool usesCompleteTranslationUnit() { return false; } + virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; } }; } @@ -873,7 +873,10 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(Clang.get()); - Clang->setInvocation(&*Invocation); + llvm::IntrusiveRefCntPtr<CompilerInvocation> + CCInvocation(new CompilerInvocation(*Invocation)); + + Clang->setInvocation(CCInvocation.getPtr()); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; // Set up diagnostics, capturing any diagnostics that would @@ -913,16 +916,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Clear out old caches and data. TopLevelDecls.clear(); - PreprocessedEntities.clear(); CleanTemporaryFiles(); - PreprocessedEntitiesByFile.clear(); if (!OverrideMainBuffer) { StoredDiagnostics.erase( StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, StoredDiagnostics.end()); TopLevelDeclsInPreamble.clear(); - PreprocessedEntitiesInPreamble.clear(); } // Create a file manager object to provide access to and cache the filesystem. @@ -936,13 +936,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); PreprocessorOpts.DetailedRecordIncludesNestedMacroExpansions = NestedMacroExpansions; - std::string PriorImplicitPCHInclude; if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; - PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude; PreprocessorOpts.ImplicitPCHInclude = PreambleFile; PreprocessorOpts.DisablePCHValidation = true; @@ -961,9 +959,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Keep track of the override buffer; SavedMainFileBuffer = OverrideMainBuffer; - } else { - PreprocessorOpts.PrecompiledPreambleBytes.first = 0; - PreprocessorOpts.PrecompiledPreambleBytes.second = false; } llvm::OwningPtr<TopLevelDeclTrackerAction> Act( @@ -976,7 +971,14 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, Clang->getFrontendOpts().Inputs[0].first)) goto error; - + + if (OverrideMainBuffer) { + std::string ModName = PreambleFile; + TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, + getSourceManager(), PreambleDiagnostics, + StoredDiagnostics); + } + Act->Execute(); // Steal the created target, context, and preprocessor. @@ -990,21 +992,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Act->EndSourceFile(); - // Remove the overridden buffer we used for the preamble. - if (OverrideMainBuffer) { - PreprocessorOpts.eraseRemappedFile( - PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; - } - return false; error: // Remove the overridden buffer we used for the preamble. if (OverrideMainBuffer) { - PreprocessorOpts.eraseRemappedFile( - PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; delete OverrideMainBuffer; SavedMainFileBuffer = 0; } @@ -1041,7 +1033,7 @@ static std::string GetPreamblePCHPath() { P.createDirectoryOnDisk(true); P.appendComponent("preamble"); P.appendSuffix("pch"); - if (P.createTemporaryFileOnDisk()) + if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0)) return std::string(); return P.str(); @@ -1118,12 +1110,14 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, CreatedBuffer = true; } - return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines)); + return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, + Invocation.getLangOpts(), + MaxLines)); } static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, unsigned NewSize, - llvm::StringRef NewName) { + StringRef NewName) { llvm::MemoryBuffer *Result = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName); memcpy(const_cast<char*>(Result->getBufferStart()), @@ -1170,7 +1164,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer); - // If ComputePreamble() Take ownership of the + // If ComputePreamble() Take ownership of the preamble buffer. llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer; if (CreatedPreambleBuffer) OwnedPreambleBuffer.reset(NewPreamble.first); @@ -1197,7 +1191,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( if (Preamble.size() == NewPreamble.second.first && PreambleEndsAtStartOfLine == NewPreamble.second.second && NewPreamble.first->getBufferSize() < PreambleReservedSize-2 && - memcmp(&Preamble[0], NewPreamble.first->getBufferStart(), + memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(), NewPreamble.second.first) == 0) { // The preamble has not changed. We may be able to re-use the precompiled // preamble. @@ -1271,10 +1265,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( ProcessWarningOptions(getDiagnostics(), PreambleInvocation->getDiagnosticOpts()); getDiagnostics().setNumWarnings(NumWarningsInPreamble); - if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble) - StoredDiagnostics.erase( - StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble, - StoredDiagnostics.end()); // Create a version of the main file buffer that is padded to // buffer size we reserved when creating the preamble. @@ -1291,6 +1281,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // We can't reuse the previously-computed preamble. Build a new one. Preamble.clear(); + PreambleDiagnostics.clear(); llvm::sys::Path(PreambleFile).eraseFromDisk(); PreambleRebuildCounter = 1; } else if (!AllowRebuild) { @@ -1332,7 +1323,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. - Preamble.assign(NewPreamble.first->getBufferStart(), + StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].second; + Preamble.assign(FileMgr->getFile(MainFilename), + NewPreamble.first->getBufferStart(), NewPreamble.first->getBufferStart() + NewPreamble.second.first); PreambleEndsAtStartOfLine = NewPreamble.second.second; @@ -1353,7 +1346,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Tell the compiler invocation to generate a temporary precompiled header. FrontendOpts.ProgramAction = frontend::GeneratePCH; - FrontendOpts.ChainedPCH = true; // FIXME: Generate the precompiled header into memory? FrontendOpts.OutputFile = PreamblePCHPath; PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -1406,8 +1398,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( StoredDiagnostics.end()); TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); - PreprocessedEntities.clear(); - PreprocessedEntitiesInPreamble.clear(); // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); @@ -1438,17 +1428,24 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); TopLevelDeclsInPreamble.clear(); - PreprocessedEntities.clear(); - PreprocessedEntitiesInPreamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); return 0; } + // Transfer any diagnostics generated when parsing the preamble into the set + // of preamble diagnostics. + PreambleDiagnostics.clear(); + PreambleDiagnostics.insert(PreambleDiagnostics.end(), + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + StoredDiagnostics.end()); + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + StoredDiagnostics.end()); + // Keep track of the preamble we precompiled. PreambleFile = FrontendOpts.OutputFile; - NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); NumWarningsInPreamble = getDiagnostics().getNumWarnings(); // Keep track of all of the files that the source manager knows about, @@ -1501,69 +1498,12 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() { TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); } -void ASTUnit::RealizePreprocessedEntitiesFromPreamble() { - if (!PP) - return; - - PreprocessingRecord *PPRec = PP->getPreprocessingRecord(); - if (!PPRec) - return; - - ExternalPreprocessingRecordSource *External = PPRec->getExternalSource(); - if (!External) - return; - - for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) { - if (PreprocessedEntity *PE - = External->ReadPreprocessedEntityAtOffset( - PreprocessedEntitiesInPreamble[I])) - PreprocessedEntities.push_back(PE); - } - - if (PreprocessedEntities.empty()) - return; - - PreprocessedEntities.insert(PreprocessedEntities.end(), - PPRec->begin(true), PPRec->end(true)); -} - -ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() { - if (!PreprocessedEntitiesInPreamble.empty() && - PreprocessedEntities.empty()) - RealizePreprocessedEntitiesFromPreamble(); - - if (PreprocessedEntities.empty()) - if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) - return PPRec->begin(true); - - return PreprocessedEntities.begin(); -} - -ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() { - if (!PreprocessedEntitiesInPreamble.empty() && - PreprocessedEntities.empty()) - RealizePreprocessedEntitiesFromPreamble(); - - if (PreprocessedEntities.empty()) - if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) - return PPRec->end(true); - - return PreprocessedEntities.end(); -} - -unsigned ASTUnit::getMaxPCHLevel() const { - if (!getOnlyLocalDecls()) - return Decl::MaxPCHLevel; - - return 0; -} - -llvm::StringRef ASTUnit::getMainFileName() const { +StringRef ASTUnit::getMainFileName() const { return Invocation->getFrontendOpts().Inputs[0].second; } ASTUnit *ASTUnit::create(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false); @@ -1571,33 +1511,35 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, AST->Invocation = CI; AST->FileSystemOpts = CI->getFileSystemOpts(); AST->FileMgr = new FileManager(AST->FileSystemOpts); - AST->SourceMgr = new SourceManager(*Diags, *AST->FileMgr); + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); return AST.take(); } ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, - ASTFrontendAction *Action) { + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + ASTFrontendAction *Action, + ASTUnit *Unit) { assert(CI && "A CompilerInvocation is required"); - // Create the AST unit. - llvm::OwningPtr<ASTUnit> AST; - AST.reset(new ASTUnit(false)); - ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false); - AST->Diagnostics = Diags; + llvm::OwningPtr<ASTUnit> OwnAST; + ASTUnit *AST = Unit; + if (!AST) { + // Create the AST unit. + OwnAST.reset(create(CI, Diags)); + AST = OwnAST.get(); + } + AST->OnlyLocalDecls = false; AST->CaptureDiagnostics = false; - AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit() - : true; + AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = false; - AST->Invocation = CI; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> - ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + ASTUnitCleanup(OwnAST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); // We'll manage file buffers ourselves. @@ -1643,9 +1585,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, "IR inputs not supported here!"); // Configure the various subsystems. - AST->FileSystemOpts = Clang->getFileSystemOpts(); - AST->FileMgr = new FileManager(AST->FileSystemOpts); - AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); AST->TheSema.reset(); AST->Ctx = 0; AST->PP = 0; @@ -1686,7 +1625,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, Act->EndSourceFile(); - return AST.take(); + if (OwnAST) + return OwnAST.take(); + else + return AST; } bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { @@ -1719,11 +1661,11 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { } ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool NestedMacroExpansions) { // Create the AST unit. @@ -1733,7 +1675,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->Diagnostics = Diags; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation = CI; AST->NestedMacroExpansions = NestedMacroExpansions; @@ -1741,8 +1683,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take(); @@ -1750,18 +1692,16 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, const char **ArgEnd, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, - llvm::StringRef ResourceFilesPath, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool RemappedFilesKeepOriginalName, bool PrecompilePreamble, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool CXXPrecompilePreamble, - bool CXXChainedPCH, bool NestedMacroExpansions) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object @@ -1771,17 +1711,18 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, ArgBegin); } - llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + SmallVector<StoredDiagnostic, 4> StoredDiagnostics; llvm::IntrusiveRefCntPtr<CompilerInvocation> CI; { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, StoredDiagnostics); CI = clang::createInvocationFromCommandLine( - llvm::ArrayRef<const char *>(ArgBegin, ArgEnd-ArgBegin), - Diags); + llvm::makeArrayRef(ArgBegin, ArgEnd), + Diags); if (!CI) return 0; } @@ -1803,16 +1744,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - // Check whether we should precompile the preamble and/or use chained PCH. - // FIXME: This is a temporary hack while we debug C++ chained PCH. - if (CI->getLangOpts().CPlusPlus) { - PrecompilePreamble = PrecompilePreamble && CXXPrecompilePreamble; - - if (PrecompilePreamble && !CXXChainedPCH && - !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) - PrecompilePreamble = false; - } - // Create the AST unit. llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); @@ -1823,10 +1754,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->FileMgr = new FileManager(AST->FileSystemOpts); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; AST->NestedMacroExpansions = NestedMacroExpansions; @@ -1837,8 +1767,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > CICleanup(CI.getPtr()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take(); @@ -1896,6 +1826,10 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue) CacheCodeCompletionResults(); + // We now need to clear out the completion allocator for + // clang_getCursorCompletionString; it'll be recreated if necessary. + CursorCompletionAllocator = 0; + return Result; } @@ -1985,7 +1919,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_Name: case CodeCompletionContext::CCC_PotentiallyQualifiedName: case CodeCompletionContext::CCC_ParenthesizedExpression: - case CodeCompletionContext::CCC_ObjCSuperclass: + case CodeCompletionContext::CCC_ObjCInterfaceName: break; case CodeCompletionContext::CCC_EnumTag: @@ -2052,12 +1986,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, bool AddedResult = false; unsigned InContexts = (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts - : (1 << (Context.getKind() - 1))); - + : (1ULL << (Context.getKind() - 1))); // Contains the set of names that are hidden by "local" completion results. llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; typedef CodeCompletionResult Result; - llvm::SmallVector<Result, 8> AllResults; + SmallVector<Result, 8> AllResults; for (ASTUnit::cached_completion_iterator C = AST.cached_completion_begin(), CEnd = AST.cached_completion_end(); @@ -2139,22 +2072,22 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, -void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, +void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, CodeCompleteConsumer &Consumer, - Diagnostic &Diag, LangOptions &LangOpts, + DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, - llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { + SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { if (!Invocation) return; SimpleTimer CompletionTimer(WantTiming); CompletionTimer.setOutput("Code completion @ " + File + ":" + - llvm::Twine(Line) + ":" + llvm::Twine(Column)); + Twine(Line) + ":" + Twine(Column)); llvm::IntrusiveRefCntPtr<CompilerInvocation> CCInvocation(new CompilerInvocation(*Invocation)); @@ -2252,7 +2185,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, llvm::sys::PathWithStatus MainPath(OriginalSourceFile); if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus()) if (const FileStatus *MainStatus = MainPath.getFileStatus()) - if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID()) + if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() && + Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*CCInvocation, false, Line - 1); @@ -2272,17 +2206,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.ImplicitPCHInclude = PreambleFile; PreprocessorOpts.DisablePCHValidation = true; - // The stored diagnostics have the old source manager. Copy them - // to our output set of stored diagnostics, updating the source - // manager to the one we were given. - for (unsigned I = NumStoredDiagnosticsFromDriver, - N = this->StoredDiagnostics.size(); - I < N; ++I) { - StoredDiagnostics.push_back(this->StoredDiagnostics[I]); - FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr); - StoredDiagnostics[I].setLocation(Loc); - } - OwnedBuffers.push_back(OverrideMainBuffer); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -2296,36 +2219,58 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, Clang->getFrontendOpts().Inputs[0].first)) { + if (OverrideMainBuffer) { + std::string ModName = PreambleFile; + TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, + getSourceManager(), PreambleDiagnostics, + StoredDiagnostics); + } Act->Execute(); Act->EndSourceFile(); } } -CXSaveError ASTUnit::Save(llvm::StringRef File) { +CXSaveError ASTUnit::Save(StringRef File) { if (getDiagnostics().hasUnrecoverableErrorOccurred()) return CXSaveError_TranslationErrors; - + + // Write to a temporary file and later rename it to the actual file, to avoid + // possible race conditions. + llvm::SmallString<128> TempPath; + TempPath = File; + TempPath += "-%%%%%%%%"; + int fd; + if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, + /*makeAbsolute=*/false)) + return CXSaveError_Unknown; + // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? - std::string ErrorInfo; - llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!ErrorInfo.empty() || Out.has_error()) - return CXSaveError_Unknown; + llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true); serialize(Out); Out.close(); - return Out.has_error()? CXSaveError_Unknown : CXSaveError_None; + if (Out.has_error()) + return CXSaveError_Unknown; + + if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) { + bool exists; + llvm::sys::fs::remove(TempPath.str(), exists); + return CXSaveError_Unknown; + } + + return CXSaveError_None; } -bool ASTUnit::serialize(llvm::raw_ostream &OS) { +bool ASTUnit::serialize(raw_ostream &OS) { if (getDiagnostics().hasErrorOccurred()) return true; std::vector<unsigned char> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); - Writer.WriteAST(getSema(), 0, std::string(), 0); + // FIXME: Handle modules + Writer.WriteAST(getSema(), 0, std::string(), /*IsModule=*/false, ""); // Write the generated bitstream to "Out". if (!Buffer.empty()) @@ -2333,3 +2278,168 @@ bool ASTUnit::serialize(llvm::raw_ostream &OS) { return false; } + +typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap; + +static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) { + unsigned Raw = L.getRawEncoding(); + const unsigned MacroBit = 1U << 31; + L = SourceLocation::getFromRawEncoding((Raw & MacroBit) | + ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second)); +} + +void ASTUnit::TranslateStoredDiagnostics( + ASTReader *MMan, + StringRef ModName, + SourceManager &SrcMgr, + const SmallVectorImpl<StoredDiagnostic> &Diags, + SmallVectorImpl<StoredDiagnostic> &Out) { + // The stored diagnostic has the old source manager in it; update + // the locations to refer into the new source manager. We also need to remap + // all the locations to the new view. This includes the diag location, any + // associated source ranges, and the source ranges of associated fix-its. + // FIXME: There should be a cleaner way to do this. + + SmallVector<StoredDiagnostic, 4> Result; + Result.reserve(Diags.size()); + assert(MMan && "Don't have a module manager"); + serialization::Module *Mod = MMan->ModuleMgr.lookup(ModName); + assert(Mod && "Don't have preamble module"); + SLocRemap &Remap = Mod->SLocRemap; + for (unsigned I = 0, N = Diags.size(); I != N; ++I) { + // Rebuild the StoredDiagnostic. + const StoredDiagnostic &SD = Diags[I]; + SourceLocation L = SD.getLocation(); + TranslateSLoc(L, Remap); + FullSourceLoc Loc(L, SrcMgr); + + SmallVector<CharSourceRange, 4> Ranges; + Ranges.reserve(SD.range_size()); + for (StoredDiagnostic::range_iterator I = SD.range_begin(), + E = SD.range_end(); + I != E; ++I) { + SourceLocation BL = I->getBegin(); + TranslateSLoc(BL, Remap); + SourceLocation EL = I->getEnd(); + TranslateSLoc(EL, Remap); + Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange())); + } + + SmallVector<FixItHint, 2> FixIts; + FixIts.reserve(SD.fixit_size()); + for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(), + E = SD.fixit_end(); + I != E; ++I) { + FixIts.push_back(FixItHint()); + FixItHint &FH = FixIts.back(); + FH.CodeToInsert = I->CodeToInsert; + SourceLocation BL = I->RemoveRange.getBegin(); + TranslateSLoc(BL, Remap); + SourceLocation EL = I->RemoveRange.getEnd(); + TranslateSLoc(EL, Remap); + FH.RemoveRange = CharSourceRange(SourceRange(BL, EL), + I->RemoveRange.isTokenRange()); + } + + Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(), + SD.getMessage(), Loc, Ranges, FixIts)); + } + Result.swap(Out); +} + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const { + const SourceManager &SM = getSourceManager(); + SourceLocation Loc = SM.translateFileLineCol(File, Line, Col); + return SM.getMacroArgExpandedLocation(Loc); +} + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Offset) const { + const SourceManager &SM = getSourceManager(); + SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1); + return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset)); +} + +/// \brief If \arg Loc is a loaded location from the preamble, returns +/// the corresponding local location of the main file, otherwise it returns +/// \arg Loc. +SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { + FileID PreambleID; + if (SourceMgr) + PreambleID = SourceMgr->getPreambleFileID(); + + if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + return Loc; + + unsigned Offs; + if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { + SourceLocation FileLoc + = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); + return FileLoc.getLocWithOffset(Offs); + } + + return Loc; +} + +/// \brief If \arg Loc is a local location of the main file but inside the +/// preamble chunk, returns the corresponding loaded location from the +/// preamble, otherwise it returns \arg Loc. +SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { + FileID PreambleID; + if (SourceMgr) + PreambleID = SourceMgr->getPreambleFileID(); + + if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + return Loc; + + unsigned Offs; + if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && + Offs < Preamble.size()) { + SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); + return FileLoc.getLocWithOffset(Offs); + } + + return Loc; +} + +void ASTUnit::PreambleData::countLines() const { + NumLines = 0; + if (empty()) + return; + + for (std::vector<char>::const_iterator + I = Buffer.begin(), E = Buffer.end(); I != E; ++I) { + if (*I == '\n') + ++NumLines; + } + if (Buffer.back() != '\n') + ++NumLines; +} + +#ifndef NDEBUG +ASTUnit::ConcurrencyState::ConcurrencyState() { + Mutex = new llvm::sys::MutexImpl(/*recursive=*/true); +} + +ASTUnit::ConcurrencyState::~ConcurrencyState() { + delete static_cast<llvm::sys::MutexImpl *>(Mutex); +} + +void ASTUnit::ConcurrencyState::start() { + bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire(); + assert(acquired && "Concurrent access to ASTUnit!"); +} + +void ASTUnit::ConcurrencyState::finish() { + static_cast<llvm::sys::MutexImpl *>(Mutex)->release(); +} + +#else // NDEBUG + +ASTUnit::ConcurrencyState::ConcurrencyState() {} +ASTUnit::ConcurrencyState::~ConcurrencyState() {} +void ASTUnit::ConcurrencyState::start() {} +void ASTUnit::ConcurrencyState::finish() {} + +#endif diff --git a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp index 20b5189..8195445 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp @@ -71,13 +71,13 @@ public: bool isFile() const { return Kind == IsFE; } - llvm::StringRef getString() const { + StringRef getString() const { return Kind == IsFE ? FE->getName() : Path; } unsigned getKind() const { return (unsigned) Kind; } - void EmitData(llvm::raw_ostream& Out) { + void EmitData(raw_ostream& Out) { switch (Kind) { case IsFE: // Emit stat information. @@ -119,7 +119,7 @@ public: } static std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + EmitKeyDataLength(raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E) { unsigned n = V.getString().size() + 1 + 1; @@ -131,14 +131,14 @@ public: return std::make_pair(n, m); } - static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ + static void EmitKey(raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ // Emit the entry kind. ::Emit8(Out, (unsigned) V.getKind()); // Emit the string. Out.write(V.getString().data(), n - 1); } - static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + static void EmitData(raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E, unsigned) { @@ -197,7 +197,7 @@ class PTHWriter { Out.write(Ptr, NumBytes); } - void EmitString(llvm::StringRef V) { + void EmitString(StringRef V) { ::Emit16(Out, V.size()); EmitBuf(V.data(), V.size()); } @@ -247,7 +247,7 @@ void PTHWriter::EmitToken(const Token& T) { } else { // We cache *un-cleaned* spellings. This gives us 100% fidelity with the // source code. - llvm::StringRef s(T.getLiteralData(), T.getLength()); + StringRef s(T.getLiteralData(), T.getLength()); // Get the string entry. llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s); @@ -584,20 +584,20 @@ public: } static std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { + EmitKeyDataLength(raw_ostream& Out, const PTHIdKey* key, uint32_t) { unsigned n = key->II->getLength() + 1; ::Emit16(Out, n); return std::make_pair(n, sizeof(uint32_t)); } - static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) { + static void EmitKey(raw_ostream& Out, PTHIdKey* key, unsigned n) { // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. key->FileOffset = Out.tell(); Out.write(key->II->getNameStart(), n); } - static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, + static void EmitData(raw_ostream& Out, PTHIdKey*, uint32_t pID, unsigned) { ::Emit32(Out, pID); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index c58e3af..5526487 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -19,12 +19,13 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PTHManager.h" -#include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" #include "clang/Sema/CodeCompleteConsumer.h" @@ -38,11 +39,25 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Config/config.h" + +// Support for FileLockManager +#include <fstream> +#include <sys/types.h> +#include <sys/stat.h> + +#if LLVM_ON_WIN32 +#include <windows.h> +#endif +#if LLVM_ON_UNIX +#include <unistd.h> +#endif + using namespace clang; CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()) { + : Invocation(new CompilerInvocation()), ModuleManager(0) { } CompilerInstance::~CompilerInstance() { @@ -52,7 +67,7 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) { Invocation = Value; } -void CompilerInstance::setDiagnostics(Diagnostic *Value) { +void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) { Diagnostics = Value; } @@ -64,7 +79,7 @@ void CompilerInstance::setFileManager(FileManager *Value) { FileMgr = Value; } -void CompilerInstance::setSourceManager(SourceManager *Value) { +void CompilerInstance::setSourceManager(SourceManager *Value) { SourceMgr = Value; } @@ -87,9 +102,9 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { // Diagnostics static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, unsigned argc, const char* const *argv, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { std::string ErrorInfo; - llvm::OwningPtr<llvm::raw_ostream> OS( + llvm::OwningPtr<raw_ostream> OS( new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); if (!ErrorInfo.empty()) { Diags.Report(diag::err_fe_unable_to_open_logfile) @@ -103,17 +118,17 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, (*OS) << '\n'; // Chain in a diagnostic client which will log the diagnostics. - DiagnosticClient *Logger = + DiagnosticConsumer *Logger = new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); - Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); + Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, const CodeGenOptions *CodeGenOpts, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { std::string ErrorInfo; bool OwnsStream = false; - llvm::raw_ostream *OS = &llvm::errs(); + raw_ostream *OS = &llvm::errs(); if (DiagOpts.DiagnosticLogFile != "-") { // Create the output stream. llvm::raw_fd_ostream *FileOS( @@ -135,38 +150,47 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, OwnsStream); if (CodeGenOpts) Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags); - Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); + Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, - DiagnosticClient *Client) { + DiagnosticConsumer *Client, + bool ShouldOwnClient, + bool ShouldCloneClient) { Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, + ShouldOwnClient, ShouldCloneClient, &getCodeGenOpts()); } -llvm::IntrusiveRefCntPtr<Diagnostic> +llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, int Argc, const char* const *Argv, - DiagnosticClient *Client, + DiagnosticConsumer *Client, + bool ShouldOwnClient, + bool ShouldCloneClient, const CodeGenOptions *CodeGenOpts) { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(new DiagnosticsEngine(DiagID)); // Create the diagnostic client for reporting errors or for // implementing -verify. - if (Client) - Diags->setClient(Client); - else + if (Client) { + if (ShouldCloneClient) + Diags->setClient(Client->clone(*Diags), ShouldOwnClient); + else + Diags->setClient(Client, ShouldOwnClient); + } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. if (Opts.VerifyDiagnostics) - Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); + Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. if (!Opts.DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - + if (!Opts.DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); @@ -191,49 +215,47 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) { // Preprocessor void CompilerInstance::createPreprocessor() { - PP = createPreprocessor(getDiagnostics(), getLangOpts(), - getPreprocessorOpts(), getHeaderSearchOpts(), - getDependencyOutputOpts(), getTarget(), - getFrontendOpts(), getSourceManager(), - getFileManager()); -} - -Preprocessor * -CompilerInstance::createPreprocessor(Diagnostic &Diags, - const LangOptions &LangInfo, - const PreprocessorOptions &PPOpts, - const HeaderSearchOptions &HSOpts, - const DependencyOutputOptions &DepOpts, - const TargetInfo &Target, - const FrontendOptions &FEOpts, - SourceManager &SourceMgr, - FileManager &FileMgr) { + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + // Create a PTH manager if we are using some form of a token cache. PTHManager *PTHMgr = 0; if (!PPOpts.TokenCache.empty()) - PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); + PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); // Create the Preprocessor. - HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); - Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, - SourceMgr, *HeaderInfo, PTHMgr, - /*OwnsHeaderSearch=*/true); + HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager()); + PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(), + getSourceManager(), *HeaderInfo, *this, PTHMgr, + /*OwnsHeaderSearch=*/true); // Note that this is different then passing PTHMgr to Preprocessor's ctor. // That argument is used as the IdentifierInfoLookup argument to // IdentifierTable's ctor. if (PTHMgr) { - PTHMgr->setPreprocessor(PP); + PTHMgr->setPreprocessor(&*PP); PP->setPTHManager(PTHMgr); } if (PPOpts.DetailedRecord) PP->createPreprocessingRecord( - PPOpts.DetailedRecordIncludesNestedMacroExpansions); - - InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); + PPOpts.DetailedRecordIncludesNestedMacroExpansions); + + InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts()); + + // Set up the module path, including the hash for the + // module-creation options. + llvm::SmallString<256> SpecificModuleCache( + getHeaderSearchOpts().ModuleCachePath); + if (!getHeaderSearchOpts().DisableModuleHash) + llvm::sys::path::append(SpecificModuleCache, + getInvocation().getModuleHash()); + PP->getHeaderSearchInfo().configureModules(SpecificModuleCache, + getPreprocessorOpts().ModuleBuildPath.empty() + ? std::string() + : getPreprocessorOpts().ModuleBuildPath.back()); // Handle generating dependencies, if requested. + const DependencyOutputOptions &DepOpts = getDependencyOutputOpts(); if (!DepOpts.OutputFile.empty()) AttachDependencyFileGen(*PP, DepOpts); @@ -241,14 +263,12 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, if (DepOpts.ShowHeaderIncludes) AttachHeaderIncludeGen(*PP); if (!DepOpts.HeaderIncludeOutputFile.empty()) { - llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; + StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; if (OutputPath == "-") OutputPath = ""; AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath, /*ShowDepth=*/false); } - - return PP; } // ASTContext @@ -256,30 +276,31 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); Context = new ASTContext(getLangOpts(), PP.getSourceManager(), - getTarget(), PP.getIdentifierTable(), + &getTarget(), PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), /*size_reserve=*/ 0); } // ExternalASTSource -void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, +void CompilerInstance::createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, bool DisableStatCache, void *DeserializationListener){ llvm::OwningPtr<ExternalASTSource> Source; bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, - DisablePCHValidation, + DisablePCHValidation, DisableStatCache, getPreprocessor(), getASTContext(), DeserializationListener, Preamble)); + ModuleManager = static_cast<ASTReader*>(Source.get()); getASTContext().setExternalSource(Source); } ExternalASTSource * -CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, +CompilerInstance::createPCHExternalASTSource(StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, bool DisableStatCache, @@ -288,14 +309,15 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, void *DeserializationListener, bool Preamble) { llvm::OwningPtr<ASTReader> Reader; - Reader.reset(new ASTReader(PP, &Context, - Sysroot.empty() ? 0 : Sysroot.c_str(), + Reader.reset(new ASTReader(PP, Context, + Sysroot.empty() ? "" : Sysroot.c_str(), DisablePCHValidation, DisableStatCache)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); switch (Reader->ReadAST(Path, - Preamble ? ASTReader::Preamble : ASTReader::PCH)) { + Preamble ? serialization::MK_Preamble + : serialization::MK_PCH)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. @@ -316,7 +338,7 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, // Code Completion -static bool EnableCodeCompletion(Preprocessor &PP, +static bool EnableCodeCompletion(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column) { @@ -371,19 +393,19 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, bool ShowMacros, bool ShowCodePatterns, bool ShowGlobals, - llvm::raw_ostream &OS) { + raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) return 0; // Set up the creation routine for code-completion. - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, ShowGlobals, OS); } -void CompilerInstance::createSema(bool CompleteTranslationUnit, +void CompilerInstance::createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer) { TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), - CompleteTranslationUnit, CompletionConsumer)); + TUKind, CompletionConsumer)); } // Output Files @@ -418,28 +440,30 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { } } else if (!it->Filename.empty() && EraseFiles) llvm::sys::Path(it->Filename).eraseFromDisk(); - + } OutputFiles.clear(); } llvm::raw_fd_ostream * CompilerInstance::createDefaultOutputFile(bool Binary, - llvm::StringRef InFile, - llvm::StringRef Extension) { + StringRef InFile, + StringRef Extension) { return createOutputFile(getFrontendOpts().OutputFile, Binary, /*RemoveFileOnSignal=*/true, InFile, Extension); } llvm::raw_fd_ostream * -CompilerInstance::createOutputFile(llvm::StringRef OutputPath, +CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, - llvm::StringRef InFile, - llvm::StringRef Extension) { + StringRef InFile, + StringRef Extension, + bool UseTemporary) { std::string Error, OutputPathName, TempPathName; llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, RemoveFileOnSignal, InFile, Extension, + UseTemporary, &OutputPathName, &TempPathName); if (!OS) { @@ -457,12 +481,13 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } llvm::raw_fd_ostream * -CompilerInstance::createOutputFile(llvm::StringRef OutputPath, +CompilerInstance::createOutputFile(StringRef OutputPath, std::string &Error, bool Binary, bool RemoveFileOnSignal, - llvm::StringRef InFile, - llvm::StringRef Extension, + StringRef InFile, + StringRef Extension, + bool UseTemporary, std::string *ResultPathName, std::string *TempPathName) { std::string OutFile, TempFile; @@ -478,8 +503,11 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } else { OutFile = "-"; } - - if (OutFile != "-") { + + llvm::OwningPtr<llvm::raw_fd_ostream> OS; + std::string OSFile; + + if (UseTemporary && OutFile != "-") { llvm::sys::Path OutPath(OutFile); // Only create the temporary if we can actually write to OutPath, otherwise // we want to fail early. @@ -487,21 +515,26 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) || (OutPath.isRegularFile() && OutPath.canWrite())) { // Create a temporary file. - llvm::sys::Path TempPath(OutFile); - if (!TempPath.createTemporaryFileOnDisk()) - TempFile = TempPath.str(); + llvm::SmallString<128> TempPath; + TempPath = OutFile; + TempPath += "-%%%%%%%%"; + int fd; + if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, + /*makeAbsolute=*/false) == llvm::errc::success) { + OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); + OSFile = TempFile = TempPath.str(); + } } } - std::string OSFile = OutFile; - if (!TempFile.empty()) - OSFile = TempFile; - - llvm::OwningPtr<llvm::raw_fd_ostream> OS( - new llvm::raw_fd_ostream(OSFile.c_str(), Error, - (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); - if (!Error.empty()) - return 0; + if (!OS) { + OSFile = OutFile; + OS.reset( + new llvm::raw_fd_ostream(OSFile.c_str(), Error, + (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); + if (!Error.empty()) + return 0; + } // Make sure the out stream file gets removed if we crash. if (RemoveFileOnSignal) @@ -517,21 +550,18 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, // Initialization Utilities -bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { +bool CompilerInstance::InitializeSourceManager(StringRef InputFile) { return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), getSourceManager(), getFrontendOpts()); } -bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, - Diagnostic &Diags, +bool CompilerInstance::InitializeSourceManager(StringRef InputFile, + DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { - // Figure out where to get and map in the main file, unless it's already - // been created (e.g., by a precompiled preamble). - if (!SourceMgr.getMainFileID().isInvalid()) { - // Do nothing: the main file has already been set. - } else if (InputFile != "-") { + // Figure out where to get and map in the main file. + if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; @@ -565,7 +595,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // FIXME: Take this as an argument, once all the APIs we used have moved to // taking it as an input instead of hard-coding llvm::errs. - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); // Create the target instance. setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); @@ -589,7 +619,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (getFrontendOpts().ShowStats) llvm::EnableStatistics(); - + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { const std::string &InFile = getFrontendOpts().Inputs[i].second; @@ -608,7 +638,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // Get the total number of warnings/errors from the client. unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings(); unsigned NumErrors = getDiagnostics().getClient()->getNumErrors(); - + if (NumWarnings) OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); if (NumWarnings && NumErrors) @@ -627,4 +657,456 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { return !getDiagnostics().getClient()->getNumErrors(); } +/// \brief Determine the appropriate source input kind based on language +/// options. +static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { + if (LangOpts.OpenCL) + return IK_OpenCL; + if (LangOpts.CUDA) + return IK_CUDA; + if (LangOpts.ObjC1) + return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC; + return LangOpts.CPlusPlus? IK_CXX : IK_C; +} + +namespace { + struct CompileModuleData { + CompilerInstance &Instance; + GeneratePCHAction &CreateModuleAction; + }; +} + +/// \brief Helper function that executes the module-generating action under +/// a crash recovery context. +static void doCompileModule(void *UserData) { + CompileModuleData &Data = *reinterpret_cast<CompileModuleData *>(UserData); + Data.Instance.ExecuteAction(Data.CreateModuleAction); +} + +namespace { + /// \brief Class that manages the creation of a lock file to aid + /// implicit coordination between different processes. + /// + /// The implicit coordination works by creating a ".lock" file alongside + /// the file that we're coordinating for, using the atomicity of the file + /// system to ensure that only a single process can create that ".lock" file. + /// When the lock file is removed, the owning process has finished the + /// operation. + class LockFileManager { + public: + /// \brief Describes the state of a lock file. + enum LockFileState { + /// \brief The lock file has been created and is owned by this instance + /// of the object. + LFS_Owned, + /// \brief The lock file already exists and is owned by some other + /// instance. + LFS_Shared, + /// \brief An error occurred while trying to create or find the lock + /// file. + LFS_Error + }; + + private: + llvm::SmallString<128> LockFileName; + llvm::SmallString<128> UniqueLockFileName; + + llvm::Optional<std::pair<std::string, int> > Owner; + llvm::Optional<llvm::error_code> Error; + + LockFileManager(const LockFileManager &); + LockFileManager &operator=(const LockFileManager &); + + static llvm::Optional<std::pair<std::string, int> > + readLockFile(StringRef LockFileName); + + static bool processStillExecuting(StringRef Hostname, int PID); + + public: + + LockFileManager(StringRef FileName); + ~LockFileManager(); + + /// \brief Determine the state of the lock file. + LockFileState getState() const; + + operator LockFileState() const { return getState(); } + + /// \brief For a shared lock, wait until the owner releases the lock. + void waitForUnlock(); + }; +} + +/// \brief Attempt to read the lock file with the given name, if it exists. +/// +/// \param LockFileName The name of the lock file to read. +/// +/// \returns The process ID of the process that owns this lock file +llvm::Optional<std::pair<std::string, int> > +LockFileManager::readLockFile(StringRef LockFileName) { + // Check whether the lock file exists. If not, clearly there's nothing + // to read, so we just return. + bool Exists = false; + if (llvm::sys::fs::exists(LockFileName, Exists) || !Exists) + return llvm::Optional<std::pair<std::string, int> >(); + + // Read the owning host and PID out of the lock file. If it appears that the + // owning process is dead, the lock file is invalid. + int PID = 0; + std::string Hostname; + std::ifstream Input(LockFileName.str().c_str()); + if (Input >> Hostname >> PID && PID > 0 && + processStillExecuting(Hostname, PID)) + return std::make_pair(Hostname, PID); + + // Delete the lock file. It's invalid anyway. + bool Existed; + llvm::sys::fs::remove(LockFileName, Existed); + return llvm::Optional<std::pair<std::string, int> >(); +} + +bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { +#if LLVM_ON_UNIX + char MyHostname[256]; + MyHostname[255] = 0; + MyHostname[0] = 0; + gethostname(MyHostname, 255); + // Check whether the process is dead. If so, we're done. + if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH) + return false; +#endif + + return true; +} + +LockFileManager::LockFileManager(StringRef FileName) +{ + LockFileName = FileName; + LockFileName += ".lock"; + + // If the lock file already exists, don't bother to try to create our own + // lock file; it won't work anyway. Just figure out who owns this lock file. + if ((Owner = readLockFile(LockFileName))) + return; + + // Create a lock file that is unique to this instance. + UniqueLockFileName = LockFileName; + UniqueLockFileName += "-%%%%%%%%"; + int UniqueLockFileID; + if (llvm::error_code EC + = llvm::sys::fs::unique_file(UniqueLockFileName.str(), + UniqueLockFileID, + UniqueLockFileName, + /*makeAbsolute=*/false)) { + Error = EC; + return; + } + + // Write our process ID to our unique lock file. + { + llvm::raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); + +#if LLVM_ON_UNIX + // FIXME: move getpid() call into LLVM + char hostname[256]; + hostname[255] = 0; + hostname[0] = 0; + gethostname(hostname, 255); + Out << hostname << ' ' << getpid(); +#else + Out << "localhost 1"; +#endif + Out.close(); + + if (Out.has_error()) { + // We failed to write out PID, so make up an excuse, remove the + // unique lock file, and fail. + Error = llvm::make_error_code(llvm::errc::no_space_on_device); + bool Existed; + llvm::sys::fs::remove(UniqueLockFileName.c_str(), Existed); + return; + } + } + + // Create a hard link from the lock file name. If this succeeds, we're done. + llvm::error_code EC + = llvm::sys::fs::create_hard_link(UniqueLockFileName.str(), + LockFileName.str()); + if (EC == llvm::errc::success) + return; + + // Creating the hard link failed. + +#ifdef LLVM_ON_UNIX + // The creation of the hard link may appear to fail, but if stat'ing the + // unique file returns a link count of 2, then we can still declare success. + struct stat StatBuf; + if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 && + StatBuf.st_nlink == 2) + return; +#endif + + // Someone else managed to create the lock file first. Wipe out our unique + // lock file (it's useless now) and read the process ID from the lock file. + bool Existed; + llvm::sys::fs::remove(UniqueLockFileName.str(), Existed); + if ((Owner = readLockFile(LockFileName))) + return; + + // There is a lock file that nobody owns; try to clean it up and report + // an error. + llvm::sys::fs::remove(LockFileName.str(), Existed); + Error = EC; +} + +LockFileManager::LockFileState LockFileManager::getState() const { + if (Owner) + return LFS_Shared; + + if (Error) + return LFS_Error; + + return LFS_Owned; +} + +LockFileManager::~LockFileManager() { + if (getState() != LFS_Owned) + return; + + // Since we own the lock, remove the lock file and our own unique lock file. + bool Existed; + llvm::sys::fs::remove(LockFileName.str(), Existed); + llvm::sys::fs::remove(UniqueLockFileName.str(), Existed); +} + +void LockFileManager::waitForUnlock() { + if (getState() != LFS_Shared) + return; + +#if LLVM_ON_WIN32 + unsigned long Interval = 1; +#else + struct timespec Interval; + Interval.tv_sec = 0; + Interval.tv_nsec = 1000000; +#endif + // Don't wait more than an hour for the file to appear. + const unsigned MaxSeconds = 3600; + do { + // Sleep for the designated interval, to allow the owning process time to + // finish up and + // FIXME: Should we hook in to system APIs to get a notification when the + // lock file is deleted? +#if LLVM_ON_WIN32 + Sleep(Interval); +#else + nanosleep(&Interval, NULL); +#endif + // If the file no longer exists, we're done. + bool Exists = false; + if (!llvm::sys::fs::exists(LockFileName.str(), Exists) && !Exists) + return; + + if (!processStillExecuting((*Owner).first, (*Owner).second)) + return; + + // Exponentially increase the time we wait for the lock to be removed. +#if LLVM_ON_WIN32 + Interval *= 2; +#else + Interval.tv_sec *= 2; + Interval.tv_nsec *= 2; + if (Interval.tv_nsec >= 1000000000) { + ++Interval.tv_sec; + Interval.tv_nsec -= 1000000000; + } +#endif + } while ( +#if LLVM_ON_WIN32 + Interval < MaxSeconds * 1000 +#else + Interval.tv_sec < (time_t)MaxSeconds +#endif + ); + + // Give up. +} + +/// \brief Compile a module file for the given module name with the given +/// umbrella header, using the options provided by the importing compiler +/// instance. +static void compileModule(CompilerInstance &ImportingInstance, + StringRef ModuleName, + StringRef ModuleFileName, + StringRef UmbrellaHeader) { + LockFileManager Locked(ModuleFileName); + switch (Locked) { + case LockFileManager::LFS_Error: + return; + + case LockFileManager::LFS_Owned: + // We're responsible for building the module ourselves. Do so below. + break; + + case LockFileManager::LFS_Shared: + // Someone else is responsible for building the module. Wait for them to + // finish. + Locked.waitForUnlock(); + break; + } + + // Construct a compiler invocation for creating this module. + llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation + (new CompilerInvocation(ImportingInstance.getInvocation())); + + // For any options that aren't intended to affect how a module is built, + // reset them to their default values. + Invocation->getLangOpts().resetNonModularOptions(); + Invocation->getPreprocessorOpts().resetNonModularOptions(); + + // Note that this module is part of the module build path, so that we + // can detect cycles in the module graph. + Invocation->getPreprocessorOpts().ModuleBuildPath.push_back(ModuleName); + + // Set up the inputs/outputs so that we build the module from its umbrella + // header. + FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); + FrontendOpts.OutputFile = ModuleFileName.str(); + FrontendOpts.DisableFree = false; + FrontendOpts.Inputs.clear(); + FrontendOpts.Inputs.push_back( + std::make_pair(getSourceInputKindFromOptions(Invocation->getLangOpts()), + UmbrellaHeader)); + + Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; + + + assert(ImportingInstance.getInvocation().getModuleHash() == + Invocation->getModuleHash() && "Module hash mismatch!"); + + // Construct a compiler instance that will be used to actually create the + // module. + CompilerInstance Instance; + Instance.setInvocation(&*Invocation); + Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, + &ImportingInstance.getDiagnosticClient(), + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/true); + + // Construct a module-generating action. + GeneratePCHAction CreateModuleAction(true); + + // Execute the action to actually build the module in-place. Use a separate + // thread so that we get a stack large enough. + const unsigned ThreadStackSize = 8 << 20; + llvm::CrashRecoveryContext CRC; + CompileModuleData Data = { Instance, CreateModuleAction }; + CRC.RunSafelyOnThread(&doCompileModule, &Data, ThreadStackSize); +} + +ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc, + IdentifierInfo &ModuleName, + SourceLocation ModuleNameLoc) { + // Determine what file we're searching from. + SourceManager &SourceMgr = getSourceManager(); + SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc); + const FileEntry *CurFile + = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc)); + if (!CurFile) + CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); + + // Search for a module with the given name. + std::string UmbrellaHeader; + std::string ModuleFileName; + const FileEntry *ModuleFile + = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(), + &ModuleFileName, + &UmbrellaHeader); + + bool BuildingModule = false; + if (!ModuleFile && !UmbrellaHeader.empty()) { + // We didn't find the module, but there is an umbrella header that + // can be used to create the module file. Create a separate compilation + // module to do so. + + // Check whether there is a cycle in the module graph. + SmallVectorImpl<std::string> &ModuleBuildPath + = getPreprocessorOpts().ModuleBuildPath; + SmallVectorImpl<std::string>::iterator Pos + = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(), + ModuleName.getName()); + if (Pos != ModuleBuildPath.end()) { + llvm::SmallString<256> CyclePath; + for (; Pos != ModuleBuildPath.end(); ++Pos) { + CyclePath += *Pos; + CyclePath += " -> "; + } + CyclePath += ModuleName.getName(); + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) + << ModuleName.getName() << CyclePath; + return 0; + } + + getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build) + << ModuleName.getName(); + BuildingModule = true; + compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader); + ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName()); + } + + if (!ModuleFile) { + getDiagnostics().Report(ModuleNameLoc, + BuildingModule? diag::err_module_not_built + : diag::err_module_not_found) + << ModuleName.getName() + << SourceRange(ImportLoc, ModuleNameLoc); + return 0; + } + + // If we don't already have an ASTReader, create one now. + if (!ModuleManager) { + if (!hasASTContext()) + createASTContext(); + + std::string Sysroot = getHeaderSearchOpts().Sysroot; + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + ModuleManager = new ASTReader(getPreprocessor(), *Context, + Sysroot.empty() ? "" : Sysroot.c_str(), + PPOpts.DisablePCHValidation, + PPOpts.DisableStatCache); + if (hasASTConsumer()) { + ModuleManager->setDeserializationListener( + getASTConsumer().GetASTDeserializationListener()); + getASTContext().setASTMutationListener( + getASTConsumer().GetASTMutationListener()); + } + llvm::OwningPtr<ExternalASTSource> Source; + Source.reset(ModuleManager); + getASTContext().setExternalSource(Source); + if (hasSema()) + ModuleManager->InitializeSema(getSema()); + if (hasASTConsumer()) + ModuleManager->StartTranslationUnit(&getASTConsumer()); + } + + // Try to load the module we found. + switch (ModuleManager->ReadAST(ModuleFile->getName(), + serialization::MK_Module)) { + case ASTReader::Success: + break; + + case ASTReader::IgnorePCH: + // FIXME: The ASTReader will already have complained, but can we showhorn + // that diagnostic information into a more useful form? + return 0; + + case ASTReader::Failure: + // Already complained. + return 0; + } + + // FIXME: The module file's FileEntry makes a poor key indeed! + return (ModuleKey)ModuleFile; +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 0371dae..432407a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -60,6 +60,16 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { } } +static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis client!"); +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ + case NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + //===----------------------------------------------------------------------===// // Serialization (to args) //===----------------------------------------------------------------------===// @@ -68,7 +78,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector<std::string> &Res) { if (Opts.ShowCheckerHelp) Res.push_back("-analyzer-checker-help"); - if (Opts.AnalysisStoreOpt != BasicStoreModel) { + if (Opts.AnalysisStoreOpt != RegionStoreModel) { Res.push_back("-analyzer-store"); Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); } @@ -80,6 +90,10 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-output"); Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); } + if (Opts.AnalysisPurgeOpt != PurgeStmt) { + Res.push_back("-analyzer-purge"); + Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); + } if (!Opts.AnalyzeSpecificFunction.empty()) { Res.push_back("-analyze-function"); Res.push_back(Opts.AnalyzeSpecificFunction); @@ -92,8 +106,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); - if (!Opts.PurgeDead) - Res.push_back("-analyzer-no-purge-dead"); if (Opts.TrimGraph) Res.push_back("-trim-egraph"); if (Opts.VisualizeEGDot) @@ -171,6 +183,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mcode-model"); Res.push_back(Opts.CodeModel); } + if (Opts.CUDAIsDevice) + Res.push_back("-fcuda-is-device"); if (!Opts.CXAAtExit) Res.push_back("-fno-use-cxa-atexit"); if (Opts.CXXCtorDtorAliases) @@ -207,6 +221,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mregparm"); Res.push_back(llvm::utostr(Opts.NumRegisterParameters)); } + if (Opts.NoGlobalMerge) + Res.push_back("-mno-global-merge"); if (Opts.NoExecStack) Res.push_back("-mnoexecstack"); if (Opts.RelaxAll) @@ -361,7 +377,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; case frontend::ASTView: return "-ast-view"; - case frontend::CreateModule: return "-create-module"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; @@ -372,6 +387,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; case frontend::EmitObj: return "-emit-obj"; case frontend::FixIt: return "-fixit"; + case frontend::GenerateModule: return "-emit-module"; case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; case frontend::InitOnly: return "-init-only"; @@ -404,8 +420,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-disable-free"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); - if (Opts.ChainedPCH) - Res.push_back("-chained-pch"); if (Opts.ShowHelp) Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) @@ -439,6 +453,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-arcmt-migrate-directory"); Res.push_back(Opts.ARCMTMigrateDir); } + if (!Opts.ARCMTMigrateReportOut.empty()) { + Res.push_back("-arcmt-migrate-report-output"); + Res.push_back(Opts.ARCMTMigrateReportOut); + } + if (Opts.ARCMTMigrateEmitARCErrors) + Res.push_back("-arcmt-migrate-emit-errors"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -491,10 +511,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); } - for (unsigned i = 0, e = Opts.Modules.size(); i != e; ++i) { - Res.push_back("-import-module"); - Res.push_back(Opts.Modules[i]); - } for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { Res.push_back("-mllvm"); Res.push_back(Opts.LLVMArgs[i]); @@ -514,17 +530,43 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) llvm::report_fatal_error("Invalid option set!"); if (E.IsUserSupplied) { - if (E.Group == frontend::After) { + switch (E.Group) { + case frontend::After: Res.push_back("-idirafter"); - } else if (E.Group == frontend::Quoted) { + break; + + case frontend::Quoted: Res.push_back("-iquote"); - } else if (E.Group == frontend::System) { + break; + + case frontend::System: Res.push_back("-isystem"); - } else if (E.Group == frontend::CXXSystem) { + break; + + case frontend::IndexHeaderMap: + Res.push_back("-index-header-map"); + Res.push_back(E.IsFramework? "-F" : "-I"); + break; + + case frontend::CSystem: + Res.push_back("-c-isystem"); + break; + + case frontend::CXXSystem: Res.push_back("-cxx-isystem"); - } else { - assert(E.Group == frontend::Angled && "Invalid group!"); + break; + + case frontend::ObjCSystem: + Res.push_back("-objc-isystem"); + break; + + case frontend::ObjCXXSystem: + Res.push_back("-objcxx-isystem"); + break; + + case frontend::Angled: Res.push_back(E.IsFramework ? "-F" : "-I"); + break; } } else { if (E.Group != frontend::Angled && E.Group != frontend::System) @@ -535,32 +577,16 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, Res.push_back(E.Path); } - if (!Opts.EnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.CEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.ObjCEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.CXXEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.ObjCXXEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } if (!Opts.ResourceDir.empty()) { Res.push_back("-resource-dir"); Res.push_back(Opts.ResourceDir); } - if (!Opts.UseStandardIncludes) - Res.push_back("-nostdinc"); + if (!Opts.ModuleCachePath.empty()) { + Res.push_back("-fmodule-cache-path"); + Res.push_back(Opts.ModuleCachePath); + } + if (!Opts.UseStandardSystemIncludes) + Res.push_back("-nostdsysteminc"); if (!Opts.UseStandardCXXIncludes) Res.push_back("-nostdinc++"); if (Opts.UseLibcxx) @@ -593,16 +619,14 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-gnu-keywords"); if (!Opts.GNUMode && Opts.GNUKeywords) Res.push_back("-fgnu-keywords"); - if (Opts.Microsoft) + if (Opts.MicrosoftExt) Res.push_back("-fms-extensions"); if (Opts.MSCVersion != 0) Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); if (Opts.Borland) Res.push_back("-fborland-extensions"); - if (Opts.ObjCNonFragileABI) - Res.push_back("-fobjc-nonfragile-abi"); - if (Opts.ObjCNonFragileABI2) - Res.push_back("-fobjc-nonfragile-abi"); + if (!Opts.ObjCNonFragileABI) + Res.push_back("-fobjc-fragile-abi"); if (Opts.ObjCDefaultSynthProperties) Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. @@ -650,6 +674,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-pthread"); if (Opts.Blocks) Res.push_back("-fblocks"); + if (Opts.BlocksRuntimeOptional) + Res.push_back("-fblocks-runtime-optional"); if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); if (Opts.MathErrno) @@ -692,11 +718,11 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fshort-wchar"); if (!Opts.ElideConstructors) Res.push_back("-fno-elide-constructors"); - if (Opts.getGCMode() != LangOptions::NonGC) { - if (Opts.getGCMode() == LangOptions::HybridGC) { + if (Opts.getGC() != LangOptions::NonGC) { + if (Opts.getGC() == LangOptions::HybridGC) { Res.push_back("-fobjc-gc"); } else { - assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!"); + assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!"); Res.push_back("-fobjc-gc-only"); } } @@ -723,9 +749,9 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.InlineVisibilityHidden) Res.push_back("-fvisibility-inlines-hidden"); - if (Opts.getStackProtectorMode() != 0) { + if (Opts.getStackProtector() != 0) { Res.push_back("-stack-protector"); - Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); + Res.push_back(llvm::utostr(Opts.getStackProtector())); } if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { Res.push_back("-ftemplate-depth"); @@ -860,7 +886,7 @@ using namespace clang::driver::cc1options; // static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; @@ -870,11 +896,11 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, } static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) @@ -889,7 +915,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) @@ -904,7 +930,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ .Case(CMDFLAG, PD_##NAME) @@ -918,6 +944,21 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalysisDiagOpt = Value; } + if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { + StringRef Name = A->getValue(Args); + AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name) +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ + .Case(CMDFLAG, NAME) +#include "clang/Frontend/Analyses.def" + .Default(NumPurgeModes); + // FIXME: Error handling. + if (Value == NumPurgeModes) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << Name; + else + Opts.AnalysisPurgeOpt = Value; + } + Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); @@ -925,7 +966,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); - Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); @@ -946,8 +986,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, bool enable = (A->getOption().getID() == OPT_analyzer_checker); // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' - llvm::StringRef checkerList = A->getValue(Args); - llvm::SmallVector<llvm::StringRef, 4> checkers; + StringRef checkerList = A->getValue(Args); + SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); @@ -955,7 +995,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags); @@ -992,6 +1032,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc); Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate); + Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model); @@ -1006,6 +1047,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); + Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); @@ -1030,7 +1072,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); unsigned Method = llvm::StringSwitch<unsigned>(Name) .Case("legacy", CodeGenOptions::Legacy) .Case("non-legacy", CodeGenOptions::NonLegacy) @@ -1056,7 +1098,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, } static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); Opts.IgnoreWarnings = Args.hasArg(OPT_w); @@ -1080,18 +1122,18 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) Opts.ShowNoteIncludeStack = true; - llvm::StringRef ShowOverloads = + StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") - Opts.ShowOverloads = Diagnostic::Ovl_Best; + Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; else if (ShowOverloads == "all") - Opts.ShowOverloads = Diagnostic::Ovl_All; + Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) << ShowOverloads; - llvm::StringRef ShowCategory = + StringRef ShowCategory = Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); if (ShowCategory == "none") Opts.ShowCategories = 0; @@ -1104,7 +1146,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; - llvm::StringRef Format = + StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") Opts.Format = DiagnosticOptions::Clang; @@ -1145,13 +1187,13 @@ static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { } static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { default: - assert(0 && "Invalid option in group!"); + llvm_unreachable("Invalid option in group!"); case OPT_ast_dump: Opts.ProgramAction = frontend::ASTDump; break; case OPT_ast_dump_xml: @@ -1183,6 +1225,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; + case OPT_emit_module: + Opts.ProgramAction = frontend::GenerateModule; break; case OPT_emit_pch: Opts.ProgramAction = frontend::GeneratePCH; break; case OPT_emit_pth: @@ -1207,8 +1251,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::RunAnalysis; break; case OPT_Eonly: Opts.ProgramAction = frontend::RunPreprocessorOnly; break; - case OPT_create_module: - Opts.ProgramAction = frontend::CreateModule; break; } } @@ -1246,7 +1288,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.OutputFile = Args.getLastArgValue(OPT_o); Opts.Plugins = Args.getAllArgValues(OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); - Opts.ChainedPCH = Args.hasArg(OPT_chained_pch); Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowCodePatternsInCodeCompletion @@ -1259,7 +1300,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); - Opts.Modules = Args.getAllArgValues(OPT_import_module); Opts.ARCMTAction = FrontendOptions::ARCMT_None; if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -1280,6 +1320,10 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } } Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory); + Opts.ARCMTMigrateReportOut + = Args.getLastArgValue(OPT_arcmt_migrate_report_output); + Opts.ARCMTMigrateEmitARCErrors + = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors); InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1296,7 +1340,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC) .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) + .Case("objc++-cpp-output", IK_PreprocessedObjCXX) .Case("c-header", IK_C) + .Case("cl-header", IK_OpenCL) .Case("objective-c-header", IK_ObjC) .Case("c++-header", IK_CXX) .Case("objective-c++-header", IK_ObjCXX) @@ -1317,7 +1363,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, InputKind IK = DashX; if (IK == IK_None) { IK = FrontendOptions::getInputKindForExtension( - llvm::StringRef(Inputs[i]).rsplit('.').second); + StringRef(Inputs[i]).rsplit('.').second); // FIXME: Remove this hack. if (i == 0) DashX = IK; @@ -1350,20 +1396,35 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); - Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); - - // Add -I... and -F... options in order. - for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), - ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::Angled, true, + Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); + Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); + + // Add -I..., -F..., and -index-header-map options in order. + bool IsIndexHeaderMap = false; + for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, + OPT_index_header_map), + ie = Args.filtered_end(); it != ie; ++it) { + if ((*it)->getOption().matches(OPT_index_header_map)) { + // -index-header-map applies to the next -I or -F. + IsIndexHeaderMap = true; + continue; + } + + frontend::IncludeDirGroup Group + = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; + + Opts.AddPath((*it)->getValue(Args), Group, true, /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); + IsIndexHeaderMap = false; + } // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. - llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. + StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore), ie = Args.filtered_end(); it != ie; ++it) { @@ -1384,14 +1445,25 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false); - for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem, OPT_isystem, + for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), - ((*it)->getOption().matches(OPT_cxx_isystem) ? - frontend::CXXSystem : frontend::System), - true, false, !(*it)->getOption().matches(OPT_iwithsysroot)); - - // FIXME: Need options for the various environment variables! + Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, + !(*it)->getOption().matches(OPT_iwithsysroot)); + + // Add the paths for the various language specific isystem flags. + for (arg_iterator it = Args.filtered_begin(OPT_c_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true); + for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true); + for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true); + for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false, + true); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, @@ -1414,7 +1486,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, case IK_None: case IK_AST: case IK_LLVM_IR: - assert(0 && "Invalid input kind!"); + llvm_unreachable("Invalid input kind!"); case IK_OpenCL: LangStd = LangStandard::lang_opencl; break; @@ -1452,9 +1524,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // OpenCL has some additional defaults. if (LangStd == LangStandard::lang_opencl) { Opts.OpenCL = 1; - Opts.AltiVec = 1; + Opts.AltiVec = 0; Opts.CXXOperatorNames = 1; - Opts.LaxVectorConversions = 1; + Opts.LaxVectorConversions = 0; Opts.DefaultFPContract = 1; } @@ -1475,7 +1547,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { @@ -1545,12 +1617,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Opts.ObjC1) { if (Args.hasArg(OPT_fobjc_gc_only)) - Opts.setGCMode(LangOptions::GCOnly); + Opts.setGC(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) - Opts.setGCMode(LangOptions::HybridGC); + Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (!Args.hasArg(OPT_fobjc_nonfragile_abi)) + if (Args.hasArg(OPT_fobjc_fragile_abi)) Diags.Report(diag::err_arc_nonfragile_abi); } @@ -1585,7 +1657,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fdelayed_template_parsing)) Opts.DelayedTemplateParsing = 1; - llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); + StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") Opts.setVisibilityMode(DefaultVisibility); else if (Vis == "hidden") @@ -1615,7 +1687,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, OPT_fno_dollars_in_identifiers, Opts.DollarIdents); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); - Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions); + Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility); Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); @@ -1633,6 +1706,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); + Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); @@ -1653,13 +1727,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = Args.getLastArgValue(OPT_fconstant_string_class); - Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi); if (Opts.ObjCNonFragileABI) Opts.ObjCNonFragileABI2 = true; Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); + Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); @@ -1696,15 +1771,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; break; - case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; - case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; - case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; + case 0: Opts.setStackProtector(LangOptions::SSPOff); break; + case 1: Opts.setStackProtector(LangOptions::SSPOn); break; + case 2: Opts.setStackProtector(LangOptions::SSPReq); break; } } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); @@ -1714,6 +1789,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); + Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); @@ -1724,12 +1800,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { - llvm::StringRef Value(A->getValue(Args)); + StringRef Value(A->getValue(Args)); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; - if (Comma == llvm::StringRef::npos || + if (Comma == StringRef::npos || Value.substr(0, Comma).getAsInteger(10, Bytes) || Value.substr(Comma + 1).getAsInteger(10, EndOfLine)) Diags.Report(diag::err_drv_preamble_format); @@ -1780,8 +1856,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_remap_file), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - std::pair<llvm::StringRef,llvm::StringRef> Split = - llvm::StringRef(A->getValue(Args)).split(';'); + std::pair<StringRef,StringRef> Split = + StringRef(A->getValue(Args)).split(';'); if (Split.second.empty()) { Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args); @@ -1792,7 +1868,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); unsigned Library = llvm::StringSwitch<unsigned>(Name) .Case("libc++", ARCXX_libcxx) .Case("libstdc++", ARCXX_libstdcxx) @@ -1834,7 +1910,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char *const *ArgBegin, const char *const *ArgEnd, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); unsigned MissingArgIndex, MissingArgCount; @@ -1873,3 +1949,105 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } + +namespace { + + class ModuleSignature { + llvm::SmallVector<uint64_t, 16> Data; + unsigned CurBit; + uint64_t CurValue; + + public: + ModuleSignature() : CurBit(0), CurValue(0) { } + + void add(uint64_t Value, unsigned Bits); + void add(StringRef Value); + void flush(); + + llvm::APInt getAsInteger() const; + }; +} + +void ModuleSignature::add(uint64_t Value, unsigned int NumBits) { + CurValue |= Value << CurBit; + if (CurBit + NumBits < 64) { + CurBit += NumBits; + return; + } + + // Add the current word. + Data.push_back(CurValue); + + if (CurBit) + CurValue = Value >> (64-CurBit); + else + CurValue = 0; + CurBit = (CurBit+NumBits) & 63; +} + +void ModuleSignature::flush() { + if (CurBit == 0) + return; + + Data.push_back(CurValue); + CurBit = 0; + CurValue = 0; +} + +void ModuleSignature::add(StringRef Value) { + for (StringRef::iterator I = Value.begin(), IEnd = Value.end(); I != IEnd;++I) + add(*I, 8); +} + +llvm::APInt ModuleSignature::getAsInteger() const { + return llvm::APInt(Data.size() * 64, Data); +} + +std::string CompilerInvocation::getModuleHash() const { + ModuleSignature Signature; + + // Start the signature with the compiler version. + Signature.add(getClangFullRepositoryVersion()); + + // Extend the signature with the language options +#define LANGOPT(Name, Bits, Default, Description) \ + Signature.add(LangOpts.Name, Bits); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Signature.add(static_cast<unsigned>(LangOpts.get##Name()), Bits); +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + + // Extend the signature with the target triple + llvm::Triple T(TargetOpts.Triple); + Signature.add((unsigned)T.getArch(), 5); + Signature.add((unsigned)T.getVendor(), 4); + Signature.add((unsigned)T.getOS(), 5); + Signature.add((unsigned)T.getEnvironment(), 4); + + // Extend the signature with preprocessor options. + Signature.add(getPreprocessorOpts().UsePredefines, 1); + Signature.add(getPreprocessorOpts().DetailedRecord, 1); + + // Hash the preprocessor defines. + // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines. + std::vector<StringRef> MacroDefs; + for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator + I = getPreprocessorOpts().Macros.begin(), + IEnd = getPreprocessorOpts().Macros.end(); + I != IEnd; ++I) { + if (!I->second) + MacroDefs.push_back(I->first); + } + llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end()); + + unsigned PPHashResult = 0; + for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I) + PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult); + Signature.add(PPHashResult, 32); + + // We've generated the signature. Treat it as one large APInt that we'll + // encode in base-36 and return. + Signature.flush(); + return Signature.getAsInteger().toString(36, /*Signed=*/false); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 42b648a..fc15081 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -29,8 +29,8 @@ using namespace clang; /// \return A CompilerInvocation, or 0 if none was built for the given /// argument vector. CompilerInvocation * -clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { +clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -39,7 +39,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, ArgList.begin()); } - llvm::SmallVector<const char *, 16> Args; + SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgList.begin(), ArgList.end()); @@ -49,7 +49,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), - "a.out", false, false, *Diags); + "a.out", false, *Diags); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); @@ -74,7 +74,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, } const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + if (StringRef(Cmd->getCreator().getName()) != "clang") { Diags->Report(diag::err_fe_expected_clang_command); return 0; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp index 1edd09b..ff3a123 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp @@ -32,19 +32,19 @@ class DependencyFileCallback : public PPCallbacks { llvm::StringSet<> FilesSet; const Preprocessor *PP; std::vector<std::string> Targets; - llvm::raw_ostream *OS; + raw_ostream *OS; bool IncludeSystemHeaders; bool PhonyTarget; bool AddMissingHeaderDeps; private: bool FileMatchesDepCriteria(const char *Filename, SrcMgr::CharacteristicKind FileType); - void AddFilename(llvm::StringRef Filename); + void AddFilename(StringRef Filename); void OutputDependencyFile(); public: DependencyFileCallback(const Preprocessor *_PP, - llvm::raw_ostream *_OS, + raw_ostream *_OS, const DependencyOutputOptions &Opts) : PP(_PP), Targets(Opts.Targets), OS(_OS), IncludeSystemHeaders(Opts.IncludeSystemHeaders), @@ -52,15 +52,16 @@ public: AddMissingHeaderDeps(Opts.AddMissingHeaderDeps) {} virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); virtual void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - llvm::StringRef FileName, + StringRef FileName, bool IsAngled, const FileEntry *File, SourceLocation EndLoc, - llvm::StringRef SearchPath, - llvm::StringRef RelativePath); + StringRef SearchPath, + StringRef RelativePath); virtual void EndOfMainFile() { OutputDependencyFile(); @@ -78,7 +79,7 @@ void clang::AttachDependencyFileGen(Preprocessor &PP, } std::string Err; - llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); + raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); if (!Err.empty()) { PP.getDiagnostics().Report(diag::err_fe_error_opening) << Opts.OutputFile << Err; @@ -86,14 +87,8 @@ void clang::AttachDependencyFileGen(Preprocessor &PP, } // Disable the "file not found" diagnostic if the -MG option was given. - // FIXME: Ideally this would live in the driver, but we don't have the ability - // to remap individual diagnostics there without creating a DiagGroup, in - // which case we would need to prevent the group name from showing up in - // diagnostics. - if (Opts.AddMissingHeaderDeps) { - PP.getDiagnostics().setDiagnosticMapping(diag::warn_pp_file_not_found, - diag::MAP_IGNORE, SourceLocation()); - } + if (Opts.AddMissingHeaderDeps) + PP.SetSuppressIncludeNotFoundError(true); PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); } @@ -113,7 +108,8 @@ bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, void DependencyFileCallback::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType) { + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { if (Reason != PPCallbacks::EnterFile) return; @@ -123,10 +119,10 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, SourceManager &SM = PP->getSourceManager(); const FileEntry *FE = - SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc))); + SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); if (FE == 0) return; - llvm::StringRef Filename = FE->getName(); + StringRef Filename = FE->getName(); if (!FileMatchesDepCriteria(Filename.data(), FileType)) return; @@ -143,24 +139,24 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - llvm::StringRef FileName, + StringRef FileName, bool IsAngled, const FileEntry *File, SourceLocation EndLoc, - llvm::StringRef SearchPath, - llvm::StringRef RelativePath) { + StringRef SearchPath, + StringRef RelativePath) { if (AddMissingHeaderDeps && !File) AddFilename(FileName); } -void DependencyFileCallback::AddFilename(llvm::StringRef Filename) { +void DependencyFileCallback::AddFilename(StringRef Filename) { if (FilesSet.insert(Filename)) Files.push_back(Filename); } /// PrintFilename - GCC escapes spaces, but apparently not ' or " or other /// scary characters. -static void PrintFilename(llvm::raw_ostream &OS, llvm::StringRef Filename) { +static void PrintFilename(raw_ostream &OS, StringRef Filename) { for (unsigned i = 0, e = Filename.size(); i != e; ++i) { if (Filename[i] == ' ') OS << '\\'; diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 0128d6e..ba2d63b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -20,6 +20,7 @@ #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ChainedIncludesSource.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" @@ -65,7 +66,7 @@ public: if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { unsigned DiagID - = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error, + = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0 was deserialized"); Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) << ND->getNameAsString(); @@ -82,7 +83,7 @@ FrontendAction::FrontendAction() : Instance(0) {} FrontendAction::~FrontendAction() {} -void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, +void FrontendAction::setCurrentFile(StringRef Value, InputKind Kind, ASTUnit *AST) { CurrentFile = Value; CurrentFileKind = Kind; @@ -90,7 +91,7 @@ void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, } ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { ASTConsumer* Consumer = CreateASTConsumer(CI, InFile); if (!Consumer) return 0; @@ -123,7 +124,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, } bool FrontendAction::BeginSourceFile(CompilerInstance &CI, - llvm::StringRef Filename, + StringRef Filename, InputKind InputKind) { assert(!Instance && "Already processing a source file!"); assert(!Filename.empty() && "Unexpected empty filename!"); @@ -141,7 +142,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, assert(hasASTFileSupport() && "This action does not have AST file support!"); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::string Error; ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags, CI.getFileSystemOpts()); @@ -224,9 +225,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { // Use PCH. assert(hasPCHSupport() && "This action does not have PCH support!"); - ASTDeserializationListener *DeserialListener - = CI.getInvocation().getFrontendOpts().ChainedPCH ? - Consumer->GetASTDeserializationListener() : 0; + ASTDeserializationListener *DeserialListener = + Consumer->GetASTDeserializationListener(); if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) DeserialListener = new DeserializedDeclsDumper(DeserialListener); if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) @@ -247,7 +247,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; } - // Initialize builtin info as long as we aren't using an external AST + // Initialize built-in info as long as we aren't using an external AST // source. if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); @@ -374,26 +374,26 @@ void ASTFrontendAction::ExecuteAction() { CompletionConsumer = &CI.getCodeCompletionConsumer(); if (!CI.hasSema()) - CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer); + CI.createSema(getTranslationUnitKind(), CompletionConsumer); ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats); } ASTConsumer * PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); } ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return WrappedAction->CreateASTConsumer(CI, InFile); } bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { return WrappedAction->BeginInvocation(CI); } bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, - llvm::StringRef Filename) { + StringRef Filename) { WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind()); WrappedAction->setCompilerInstance(&CI); return WrappedAction->BeginSourceFileAction(CI, Filename); @@ -408,8 +408,8 @@ void WrapperFrontendAction::EndSourceFileAction() { bool WrapperFrontendAction::usesPreprocessorOnly() const { return WrappedAction->usesPreprocessorOnly(); } -bool WrapperFrontendAction::usesCompleteTranslationUnit() { - return WrappedAction->usesCompleteTranslationUnit(); +TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() { + return WrappedAction->getTranslationUnitKind(); } bool WrapperFrontendAction::hasPCHSupport() const { return WrappedAction->hasPCHSupport(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index 7b06c7e..6f84da9 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -22,6 +22,8 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -29,7 +31,7 @@ using namespace clang; //===----------------------------------------------------------------------===// ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return new ASTConsumer(); } @@ -41,20 +43,20 @@ void InitOnlyAction::ExecuteAction() { //===----------------------------------------------------------------------===// ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) return CreateASTPrinter(OS); return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateASTDumper(); } ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - llvm::raw_ostream *OS; + StringRef InFile) { + raw_ostream *OS; if (CI.getFrontendOpts().OutputFile.empty()) OS = &llvm::outs(); else @@ -64,35 +66,34 @@ ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, } ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateASTViewer(); } ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateDeclContextPrinter(); } ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { std::string Sysroot; std::string OutputFile; - llvm::raw_ostream *OS = 0; - bool Chaining; - if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining)) + raw_ostream *OS = 0; + if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS)) return 0; - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; - return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS); + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + return new PCHGenerator(CI.getPreprocessor(), OutputFile, MakeModule, + Sysroot, OS); } bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, - llvm::StringRef InFile, + StringRef InFile, std::string &Sysroot, std::string &OutputFile, - llvm::raw_ostream *&OS, - bool &Chaining) { + raw_ostream *&OS) { Sysroot = CI.getHeaderSearchOpts().Sysroot; if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); @@ -101,19 +102,19 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, // We use createOutputFile here because this is exposed via libclang, and we // must disable the RemoveFileOnSignal behavior. + // We use a temporary to avoid race conditions. OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, - /*RemoveFileOnSignal=*/false, InFile); + /*RemoveFileOnSignal=*/false, InFile, + /*Extension=*/"", /*useTemporary=*/true); if (!OS) return true; OutputFile = CI.getFrontendOpts().OutputFile; - Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && - !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); return false; } ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return new ASTConsumer(); } @@ -182,9 +183,48 @@ void PreprocessOnlyAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - // Output file needs to be set to 'Binary', to avoid converting Unix style + // Output file may need to be set to 'Binary', to avoid converting Unix style // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + // + // Look to see what type of line endings the file uses. If there's a + // CRLF, then we won't open the file up in binary mode. If there is + // just an LF or CR, then we will open the file up in binary mode. + // In this fashion, the output format should match the input format, unless + // the input format has inconsistent line endings. + // + // This should be a relatively fast operation since most files won't have + // all of their source code on a single line. However, that is still a + // concern, so if we scan for too long, we'll just assume the file should + // be opened in binary mode. + bool BinaryMode = true; + bool InvalidFile = false; + const SourceManager& SM = CI.getSourceManager(); + const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getMainFileID(), + &InvalidFile); + if (!InvalidFile) { + const char *cur = Buffer->getBufferStart(); + const char *end = Buffer->getBufferEnd(); + const char *next = (cur != end) ? cur + 1 : end; + + // Limit ourselves to only scanning 256 characters into the source + // file. This is mostly a sanity check in case the file has no + // newlines whatsoever. + if (end - cur > 256) end = cur + 256; + + while (next < end) { + if (*cur == 0x0D) { // CR + if (*next == 0x0A) // CRLF + BinaryMode = false; + + break; + } else if (*cur == 0x0A) // LF + break; + + ++cur, ++next; + } + } + + raw_ostream *OS = CI.createDefaultOutputFile(BinaryMode, getCurrentFile()); if (!OS) return; DoPrintPreprocessedInput(CI.getPreprocessor(), OS, @@ -217,7 +257,7 @@ void PrintPreambleAction::ExecuteAction() { llvm::MemoryBuffer *Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { - unsigned Preamble = Lexer::ComputePreamble(Buffer).first; + unsigned Preamble = Lexer::ComputePreamble(Buffer, CI.getLangOpts()).first; llvm::outs().write(Buffer->getBufferStart(), Preamble); delete Buffer; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp index 0a20051..ea4005f 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/StringSwitch.h" using namespace clang; -InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { +InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) .Case("ast", IK_AST) .Case("c", IK_C) diff --git a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp index 51dec96..3b41d89 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -17,7 +17,7 @@ using namespace clang; namespace { class HeaderIncludesCallback : public PPCallbacks { SourceManager &SM; - llvm::raw_ostream *OutputFile; + raw_ostream *OutputFile; unsigned CurrentIncludeDepth; bool HasProcessedPredefines; bool OwnsOutputFile; @@ -26,7 +26,7 @@ class HeaderIncludesCallback : public PPCallbacks { public: HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_, - llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_, + raw_ostream *OutputFile_, bool OwnsOutputFile_, bool ShowDepth_) : SM(PP->getSourceManager()), OutputFile(OutputFile_), CurrentIncludeDepth(0), HasProcessedPredefines(false), @@ -39,13 +39,14 @@ public: } virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); }; } void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, - llvm::StringRef OutputPath, bool ShowDepth) { - llvm::raw_ostream *OutputFile = &llvm::errs(); + StringRef OutputPath, bool ShowDepth) { + raw_ostream *OutputFile = &llvm::errs(); bool OwnsOutputFile = false; // Open the output file, if used. @@ -72,7 +73,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, void HeaderIncludesCallback::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType) { + SrcMgr::CharacteristicKind NewFileType, + FileID PrevFID) { // Unless we are exiting a #include, make sure to skip ahead to the line the // #include directive was at. PresumedLoc UserLoc = SM.getPresumedLoc(Loc); diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index ae38a19..43b6d4c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -56,38 +56,34 @@ class InitHeaderSearch { public: - InitHeaderSearch(HeaderSearch &HS, bool verbose, llvm::StringRef sysroot) + InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot), IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) { } /// AddPath - Add the specified path to the specified group list. - void AddPath(const llvm::Twine &Path, IncludeDirGroup Group, + void AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. - void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef ArchDir, - llvm::StringRef Dir32, - llvm::StringRef Dir64, + void AddGnuCPlusPlusIncludePaths(StringRef Base, + StringRef ArchDir, + StringRef Dir32, + StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW /// libstdc++. - void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef Arch, - llvm::StringRef Version); + void AddMinGWCPlusPlusIncludePaths(StringRef Base, + StringRef Arch, + StringRef Version); /// AddMinGW64CXXPaths - Add the necessary paths to support /// libstdc++ of x86_64-w64-mingw32 aka mingw-w64. - void AddMinGW64CXXPaths(llvm::StringRef Base, - llvm::StringRef Version); - - /// AddDelimitedPaths - Add a list of paths delimited by the system PATH - /// separator. The processing follows that of the CPATH variable for gcc. - void AddDelimitedPaths(llvm::StringRef String); + void AddMinGW64CXXPaths(StringRef Base, + StringRef Version); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple, @@ -100,9 +96,9 @@ public: /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. - void AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple, - const HeaderSearchOptions &HSOpts); + void AddDefaultIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. @@ -111,7 +107,7 @@ public: } // end anonymous namespace. -void InitHeaderSearch::AddPath(const llvm::Twine &Path, +void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { @@ -120,7 +116,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // Compute the actual path, taking into consideration -isysroot. llvm::SmallString<256> MappedPathStorage; - llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); + StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // Handle isysroot. if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot && @@ -138,7 +134,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; - if (Group == Quoted || Group == Angled) + if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) Type = SrcMgr::C_User; else if (isCXXAware) Type = SrcMgr::C_System; @@ -160,7 +156,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { // It is a headermap, add it to the search path. IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type, - isUserSupplied))); + isUserSupplied, Group == IndexHeaderMap))); return; } } @@ -171,30 +167,10 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, << MappedPathStr << "\"\n"; } - -void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { - if (at.empty()) // Empty string should not add '.' path. - return; - - llvm::StringRef::size_type delim; - while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { - if (delim == 0) - AddPath(".", Angled, false, true, false); - else - AddPath(at.substr(0, delim), Angled, false, true, false); - at = at.substr(delim + 1); - } - - if (at.empty()) - AddPath(".", Angled, false, true, false); - else - AddPath(at, Angled, false, true, false); -} - -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef ArchDir, - llvm::StringRef Dir32, - llvm::StringRef Dir64, +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, + StringRef ArchDir, + StringRef Dir32, + StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, CXXSystem, true, false, false); @@ -211,9 +187,9 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, AddPath(Base + "/backward", CXXSystem, true, false, false); } -void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef Arch, - llvm::StringRef Version) { +void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, + StringRef Arch, + StringRef Version) { AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", CXXSystem, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, @@ -222,8 +198,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, CXXSystem, true, false, false); } -void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base, - llvm::StringRef Version) { +void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base, + StringRef Version) { // Assumes Base is HeaderSearchOpts' ResourceDir AddPath(Base + "/../../../include/c++/" + Version, CXXSystem, true, false, false); @@ -452,14 +428,16 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); - switch (os) { - case llvm::Triple::FreeBSD: - case llvm::Triple::NetBSD: - break; - default: - // FIXME: temporary hack: hard-coded paths. - AddPath("/usr/local/include", System, true, false, false); - break; + if (HSOpts.UseStandardSystemIncludes) { + switch (os) { + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + break; + default: + // FIXME: temporary hack: hard-coded paths. + AddPath("/usr/local/include", System, true, false, false); + break; + } } // Builtin includes use #include_next directives and should be positioned @@ -472,12 +450,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } + // All remaining additions are for system include directories, early exit if + // we aren't using them. + if (!HSOpts.UseStandardSystemIncludes) + return; + // Add dirs specified via 'configure --with-c-include-dirs'. - llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); + StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { - llvm::SmallVector<llvm::StringRef, 5> dirs; + SmallVector<StringRef, 5> dirs; CIncludeDirs.split(dirs, ":"); - for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); + for (SmallVectorImpl<StringRef>::iterator i = dirs.begin(); i != dirs.end(); ++i) AddPath(*i, System, false, false, false); @@ -605,9 +588,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, void InitHeaderSearch:: AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); - llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); if (CxxIncludeRoot != "") { - llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); if (CxxIncludeArch == "") AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, @@ -745,7 +728,12 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp //===------------------------------------------------------------------===// // Redhat based distros. //===------------------------------------------------------------------===// - // Fedora 15 + // Fedora 15 (GCC 4.6.1) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", + "i686-redhat-linux", "", "", triple); + // Fedora 15 (GCC 4.6.0) AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", "x86_64-redhat-linux", "32", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", @@ -848,6 +836,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", "x86_64-unknown-linux-gnu", "", "", triple); + // Slackware gcc 4.5.2 (13.37) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", + "i486-slackware-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", + "x86_64-slackware-linux", "", "", triple); + // Slackware gcc 4.5.3 (-current) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", + "i486-slackware-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", + "x86_64-slackware-linux", "", "", triple); + // Gentoo x86 gcc 4.5.2 AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4", @@ -897,6 +896,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4", "x86_64-pc-linux-gnu", "32", "", triple); + // Gentoo amd64 gcc 4.3.4 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4", + "x86_64-pc-linux-gnu", "", "", triple); // Gentoo amd64 gcc 4.3.2 AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", @@ -947,32 +950,53 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp } } -void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple, +void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { - if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) { - if (HSOpts.UseLibcxx) + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes && + HSOpts.UseStandardSystemIncludes) { + if (HSOpts.UseLibcxx) { + if (triple.isOSDarwin()) { + // On Darwin, libc++ may be installed alongside the compiler in + // lib/c++/v1. + llvm::sys::Path P(HSOpts.ResourceDir); + if (!P.isEmpty()) { + P.eraseComponent(); // Remove version from foo/lib/clang/version + P.eraseComponent(); // Remove clang from foo/lib/clang + + // Get foo/lib/c++/v1 + P.appendComponent("c++"); + P.appendComponent("v1"); + AddPath(P.str(), CXXSystem, true, false, false, true); + } + } + AddPath("/usr/include/c++/v1", CXXSystem, true, false, false); - else + } else { AddDefaultCPlusPlusIncludePaths(triple, HSOpts); + } } AddDefaultCIncludePaths(triple, HSOpts); // Add the default framework include paths on Darwin. - if (triple.isOSDarwin()) { - AddPath("/System/Library/Frameworks", System, true, false, true); - AddPath("/Library/Frameworks", System, true, false, true); + if (HSOpts.UseStandardSystemIncludes) { + if (triple.isOSDarwin()) { + AddPath("/System/Library/Frameworks", System, true, false, true); + AddPath("/Library/Frameworks", System, true, false, true); + } } } /// RemoveDuplicates - If there are duplicate directory entries in the specified -/// search list, remove the later (dead) ones. -static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, - unsigned First, bool Verbose) { +/// search list, remove the later (dead) ones. Returns the number of non-system +/// headers removed, which is used to update NumAngled. +static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, + unsigned First, bool Verbose) { llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs; llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs; llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps; + unsigned NonSystemRemoved = 0; for (unsigned i = First; i != SearchList.size(); ++i) { unsigned DirToRemove = i; @@ -1039,12 +1063,15 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, llvm::errs() << " as it is a non-system directory that duplicates " << "a system directory\n"; } + if (DirToRemove != i) + ++NonSystemRemoved; // This is reached if the current entry is a duplicate. Remove the // DirToRemove (usually the current dir). SearchList.erase(SearchList.begin()+DirToRemove); --i; } + return NonSystemRemoved; } @@ -1065,7 +1092,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { - if (it->first == Angled) + if (it->first == Angled || it->first == IndexHeaderMap) SearchList.push_back(it->second); } @@ -1074,7 +1101,11 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { - if (it->first == System || (Lang.CPlusPlus && it->first == CXXSystem)) + if (it->first == System || + (!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) || + (/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) || + (Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) || + (Lang.ObjC1 && Lang.CPlusPlus && it->first == ObjCXXSystem)) SearchList.push_back(it->second); } @@ -1087,7 +1118,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { // Remove duplicates across both the Angled and System directories. GCC does // this and failing to remove duplicates across these two groups breaks // #include_next. - RemoveDuplicates(SearchList, NumQuoted, Verbose); + unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); + NumAngled -= NonSystemRemoved; bool DontSearchCurDir = false; // TODO: set to true if -I- is set? Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir); @@ -1127,19 +1159,7 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, E.IgnoreSysRoot); } - // Add entries from CPATH and friends. - Init.AddDelimitedPaths(HSOpts.EnvIncPath); - if (Lang.CPlusPlus && Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); - else if (Lang.CPlusPlus) - Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); - else if (Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); - else - Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - - if (HSOpts.UseStandardIncludes) - Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts); + Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); Init.Realize(Lang); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 9428cd5..6f49ec4 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -30,15 +30,15 @@ using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, - Diagnostic &Diags) { - std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('='); - llvm::StringRef MacroName = MacroPair.first; - llvm::StringRef MacroBody = MacroPair.second; +static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro, + DiagnosticsEngine &Diags) { + std::pair<StringRef, StringRef> MacroPair = Macro.split('='); + StringRef MacroName = MacroPair.first; + StringRef MacroBody = MacroPair.second; if (MacroName.size() != Macro.size()) { // Per GCC -D semantics, the macro ends at \n if it exists. - llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r"); - if (End != llvm::StringRef::npos) + StringRef::size_type End = MacroBody.find_first_of("\n\r"); + if (End != StringRef::npos) Diags.Report(diag::warn_fe_macro_contains_embedded_newline) << MacroName; Builder.defineMacro(MacroName, MacroBody.substr(0, End)); @@ -48,7 +48,7 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, } } -std::string clang::NormalizeDashIncludePath(llvm::StringRef File, +std::string clang::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) { // Implicit include paths should be resolved relative to the current // working directory first, and then use the regular header search @@ -70,17 +70,17 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File, /// AddImplicitInclude - Add an implicit #include of the specified file to the /// predefines buffer. -static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File, +static void AddImplicitInclude(MacroBuilder &Builder, StringRef File, FileManager &FileMgr) { Builder.append("#include \"" + - llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); + Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); } static void AddImplicitIncludeMacros(MacroBuilder &Builder, - llvm::StringRef File, + StringRef File, FileManager &FileMgr) { Builder.append("#__include_macros \"" + - llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); + Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); // Marker token to stop the __include_macros fetch loop. Builder.append("##"); // ##? } @@ -88,7 +88,7 @@ static void AddImplicitIncludeMacros(MacroBuilder &Builder, /// AddImplicitIncludePTH - Add an implicit #include using the original file /// used to generate a PTH cache. static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, - llvm::StringRef ImplicitIncludePTH) { + StringRef ImplicitIncludePTH) { PTHManager *P = PP.getPTHManager(); // Null check 'P' in the corner case where it couldn't be created. const char *OriginalFile = P ? P->getOriginalSourceFile() : 0; @@ -120,7 +120,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, return IEEEQuadVal; } -static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, +static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix, const llvm::fltSemantics *Sem) { const char *DenormMin, *Epsilon, *Max, *Min; DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", @@ -153,27 +153,27 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); - Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits)); - Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits)); + Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)); Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); - Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits)); + Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits)); - Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp)); - Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp)); - Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max)); + Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp)); + Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp)); + Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)); - Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")"); - Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")"); - Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min)); + Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")"); + Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")"); + Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)); } /// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro /// named MacroName with the max value for a type with width 'TypeWidth' a /// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL). -static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, - llvm::StringRef ValSuffix, bool isSigned, +static void DefineTypeSize(StringRef MacroName, unsigned TypeWidth, + StringRef ValSuffix, bool isSigned, MacroBuilder &Builder) { llvm::APInt MaxVal = isSigned ? llvm::APInt::getSignedMaxValue(TypeWidth) : llvm::APInt::getMaxValue(TypeWidth); @@ -182,26 +182,26 @@ static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, /// DefineTypeSize - An overloaded helper that uses TargetInfo to determine /// the width, suffix, and signedness of the given type -static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty, +static void DefineTypeSize(StringRef MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), TI.isTypeSigned(Ty), Builder); } -static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty, +static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty, MacroBuilder &Builder) { Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty)); } -static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty, +static void DefineTypeWidth(StringRef MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { - Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty))); + Builder.defineMacro(MacroName, Twine(TI.getTypeWidth(Ty))); } -static void DefineTypeSizeof(llvm::StringRef MacroName, unsigned BitWidth, +static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth, const TargetInfo &TI, MacroBuilder &Builder) { Builder.defineMacro(MacroName, - llvm::Twine(BitWidth / TI.getCharWidth())); + Twine(BitWidth / TI.getCharWidth())); } static void DefineExactWidthIntType(TargetInfo::IntType Ty, @@ -213,81 +213,15 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty, if (TypeWidth == 64) Ty = TI.getInt64Type(); - DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder); + DefineType("__INT" + Twine(TypeWidth) + "_TYPE__", Ty, Builder); - llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); + StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); if (!ConstSuffix.empty()) - Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__", + Builder.defineMacro("__INT" + Twine(TypeWidth) + "_C_SUFFIX__", ConstSuffix); } /// \brief Add definitions required for a smooth interaction between -/// Objective-C++ automatic reference counting and libc++. -static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts, - MacroBuilder &Builder) { - Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF"); - - std::string Result; - { - // Provide overloads of the function std::__1::addressof() that accept - // references to lifetime-qualified objects. libc++'s (more general) - // std::__1::addressof() template fails to instantiate with such types, - // because it attempts to convert the object to a char& before - // dereferencing. - llvm::raw_string_ostream Out(Result); - - Out << "#pragma clang diagnostic push\n" - << "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n" - << "namespace std { inline namespace __1 {\n" - << "\n"; - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\"), " - << "__always_inline__))\n" - << "__attribute__((objc_ownership(strong))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(strong))) _Tp& __x) {\n" - << " return &__x;\n" - << "}\n" - << "\n"; - - if (LangOpts.ObjCRuntimeHasWeak) { - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\")," - << "__always_inline__))\n" - << "__attribute__((objc_ownership(weak))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(weak))) _Tp& __x) {\n" - << " return &__x;\n" - << "};\n" - << "\n"; - } - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\")," - << "__always_inline__))\n" - << "__attribute__((objc_ownership(autoreleasing))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(autoreleasing))) _Tp& __x) " - << "{\n" - << " return &__x;\n" - << "}\n" - << "\n"; - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\"), " - << "__always_inline__))\n" - << "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)" - << " {\n" - << " return &__x;\n" - << "}\n"; - - Out << "\n" - << "} }\n" - << "#pragma clang diagnostic pop\n" - << "\n"; - } - Builder.append(Result); -} - -/// \brief Add definitions required for a smooth interaction between /// Objective-C++ automated reference counting and libstdc++ (4.2). static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, MacroBuilder &Builder) { @@ -344,7 +278,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, const FrontendOptions &FEOpts, MacroBuilder &Builder) { - if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP) + if (!LangOpts.MicrosoftExt && !LangOpts.TraditionalCPP) Builder.defineMacro("__STDC__"); if (LangOpts.Freestanding) Builder.defineMacro("__STDC_HOSTED__", "0"); @@ -412,7 +346,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // checks that it is necessary to report 4.2.1 (the base GCC version we claim // compatibility with) first. Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " + - llvm::Twine(getClangFullCPPVersion()) + "\""); + Twine(getClangFullCPPVersion()) + "\""); // Initialize language-specific preprocessor defines. @@ -426,10 +360,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.ObjC1) { if (LangOpts.ObjCNonFragileABI) { Builder.defineMacro("__OBJC2__"); - Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); + + if (LangOpts.ObjCExceptions) + Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); } - if (LangOpts.getGCMode() != LangOptions::NonGC) + if (LangOpts.getGC() != LangOptions::NonGC) Builder.defineMacro("__OBJC_GC__"); if (LangOpts.NeXTRuntime) @@ -452,7 +388,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__BLOCKS__"); } - if (LangOpts.Exceptions) + if (LangOpts.CXXExceptions) Builder.defineMacro("__EXCEPTIONS"); if (LangOpts.RTTI) Builder.defineMacro("__GXX_RTTI"); @@ -468,7 +404,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__private_extern__", "extern"); } - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); @@ -546,7 +482,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", - llvm::Twine((int)TI.getPointerWidth(0))); + Twine((int)TI.getPointerWidth(0))); if (!LangOpts.CharIsSigned) Builder.defineMacro("__CHAR_UNSIGNED__"); @@ -555,7 +491,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__WINT_UNSIGNED__"); // Define exact-width integer types for stdint.h - Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__", + Builder.defineMacro("__INT" + Twine(TI.getCharWidth()) + "_TYPE__", "char"); if (TI.getShortWidth() > TI.getCharWidth()) @@ -589,19 +525,19 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__NO_INLINE__"); if (unsigned PICLevel = LangOpts.PICLevel) { - Builder.defineMacro("__PIC__", llvm::Twine(PICLevel)); - Builder.defineMacro("__pic__", llvm::Twine(PICLevel)); + Builder.defineMacro("__PIC__", Twine(PICLevel)); + Builder.defineMacro("__pic__", Twine(PICLevel)); } // Macros to control C99 numerics and <float.h> Builder.defineMacro("__FLT_EVAL_METHOD__", "0"); Builder.defineMacro("__FLT_RADIX__", "2"); int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36); - Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig)); + Builder.defineMacro("__DECIMAL_DIG__", Twine(Dig)); - if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn) + if (LangOpts.getStackProtector() == LangOptions::SSPOn) Builder.defineMacro("__SSP__"); - else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq) + else if (LangOpts.getStackProtector() == LangOptions::SSPReq) Builder.defineMacro("__SSP_ALL__", "2"); if (FEOpts.ProgramAction == frontend::RewriteObjC) @@ -629,7 +565,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Initialize the remapping of files to alternative contents, e.g., // those specified through other files. -static void InitializeFileRemapping(Diagnostic &Diags, +static void InitializeFileRemapping(DiagnosticsEngine &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { @@ -705,6 +641,10 @@ void clang::InitializePreprocessor(Preprocessor &PP, InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); + // Specify whether the preprocessor should replace #include/#import with + // module imports when plausible. + PP.setAutoModuleImport(InitOpts.AutoModuleImport); + // Emit line markers for various builtin sections of the file. We don't do // this in asm preprocessor mode, because "# 4" is not a line marker directive // in this mode. @@ -720,10 +660,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) { switch (InitOpts.ObjCXXARCStandardLibrary) { case ARCXX_nolib: - break; - - case ARCXX_libcxx: - AddObjCXXARCLibcxxDefines(LangOpts, Builder); + case ARCXX_libcxx: break; case ARCXX_libstdcxx: @@ -778,7 +715,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); - + // Initialize the header search object. ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, PP.getLangOptions(), diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp index af1721d..abb521b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp @@ -29,7 +29,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { } } -const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) { +const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch<Kind>(Name) #define LANGSTANDARD(id, name, desc, features) \ .Case(name, lang_##id) diff --git a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp index 78eb1b2..8b585be 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp @@ -14,7 +14,7 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os, +LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), @@ -26,15 +26,30 @@ LogDiagnosticPrinter::~LogDiagnosticPrinter() { delete &OS; } -static llvm::StringRef getLevelName(Diagnostic::Level Level) { +static StringRef getLevelName(DiagnosticsEngine::Level Level) { switch (Level) { default: return "<unknown>"; - case Diagnostic::Ignored: return "ignored"; - case Diagnostic::Note: return "note"; - case Diagnostic::Warning: return "warning"; - case Diagnostic::Error: return "error"; - case Diagnostic::Fatal: return "fatal error"; + case DiagnosticsEngine::Ignored: return "ignored"; + case DiagnosticsEngine::Note: return "note"; + case DiagnosticsEngine::Warning: return "warning"; + case DiagnosticsEngine::Error: return "error"; + case DiagnosticsEngine::Fatal: return "fatal error"; + } +} + +// Escape XML characters inside the raw string. +static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) { + for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) { + char c = *I; + switch (c) { + default: OS << c; break; + case '&': OS << "&"; break; + case '<': OS << "<"; break; + case '>': OS << ">"; break; + case '\'': OS << "'"; break; + case '\"': OS << """; break; + } } } @@ -42,9 +57,9 @@ void LogDiagnosticPrinter::EndSourceFile() { // We emit all the diagnostics in EndSourceFile. However, we don't emit any // entry if no diagnostics were present. // - // Note that DiagnosticClient has no "end-of-compilation" callback, so we will - // miss any diagnostics which are emitted after and outside the translation - // unit processing. + // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we + // will miss any diagnostics which are emitted after and outside the + // translation unit processing. if (Entries.empty()) return; @@ -55,11 +70,15 @@ void LogDiagnosticPrinter::EndSourceFile() { OS << "<dict>\n"; if (!MainFilename.empty()) { OS << " <key>main-file</key>\n" - << " <string>" << MainFilename << "</string>\n"; + << " <string>"; + emitString(OS, MainFilename); + OS << "</string>\n"; } if (!DwarfDebugFlags.empty()) { OS << " <key>dwarf-debug-flags</key>\n" - << " <string>" << DwarfDebugFlags << "</string>\n"; + << " <string>"; + emitString(OS, DwarfDebugFlags); + OS << "</string>\n"; } OS << " <key>diagnostics</key>\n"; OS << " <array>\n"; @@ -68,10 +87,14 @@ void LogDiagnosticPrinter::EndSourceFile() { OS << " <dict>\n"; OS << " <key>level</key>\n" - << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n"; + << " <string>"; + emitString(OS, getLevelName(DE.DiagnosticLevel)); + OS << "</string>\n"; if (!DE.Filename.empty()) { OS << " <key>filename</key>\n" - << " <string>" << DE.Filename << "</string>\n"; + << " <string>"; + emitString(OS, DE.Filename); + OS << "</string>\n"; } if (DE.Line != 0) { OS << " <key>line</key>\n" @@ -83,7 +106,9 @@ void LogDiagnosticPrinter::EndSourceFile() { } if (!DE.Message.empty()) { OS << " <key>message</key>\n" - << " <string>" << DE.Message << "</string>\n"; + << " <string>"; + emitString(OS, DE.Message); + OS << "</string>\n"; } OS << " </dict>\n"; } @@ -93,10 +118,10 @@ void LogDiagnosticPrinter::EndSourceFile() { this->OS << OS.str(); } -void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); // Initialize the main file name, if we haven't already fetched it. if (MainFilename.empty() && Info.hasSourceManager()) { @@ -144,3 +169,9 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // Record the diagnostic entry. Entries.push_back(DE); } + +DiagnosticConsumer * +LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} + diff --git a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp index 5aa65d7..8e746f6 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp @@ -37,7 +37,7 @@ public: virtual void TypeRead(serialization::TypeIdx Idx, QualType T); virtual void DeclRead(serialization::DeclID ID, const Decl *D); virtual void SelectorRead(serialization::SelectorID iD, Selector Sel); - virtual void MacroDefinitionRead(serialization::MacroID, + virtual void MacroDefinitionRead(serialization::PreprocessedEntityID, MacroDefinition *MD); private: std::vector<ASTDeserializationListener*> Listeners; @@ -79,7 +79,7 @@ void MultiplexASTDeserializationListener::SelectorRead( } void MultiplexASTDeserializationListener::MacroDefinitionRead( - serialization::MacroID ID, MacroDefinition *MD) { + serialization::PreprocessedEntityID ID, MacroDefinition *MD) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->MacroDefinitionRead(ID, MD); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index c892960..8a61f96 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -33,7 +33,7 @@ using namespace clang; /// PrintMacroDefinition - Print a macro definition in a form that will be /// properly accepted back as a definition. static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, - Preprocessor &PP, llvm::raw_ostream &OS) { + Preprocessor &PP, raw_ostream &OS) { OS << "#define " << II.getName(); if (MI.isFunctionLike()) { @@ -83,7 +83,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { SourceManager &SM; TokenConcatenation ConcatInfo; public: - llvm::raw_ostream &OS; + raw_ostream &OS; private: unsigned CurLine; @@ -96,7 +96,7 @@ private: bool DumpDefines; bool UseLineDirective; public: - PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, + PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers, bool defines) : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), @@ -109,7 +109,7 @@ public: Initialized = false; // If we're in microsoft mode, use normal #line instead of line markers. - UseLineDirective = PP.getLangOptions().Microsoft; + UseLineDirective = PP.getLangOptions().MicrosoftExt; } void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } @@ -118,17 +118,18 @@ public: bool StartNewLineIfNeeded(); virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); virtual void Ident(SourceLocation Loc, const std::string &str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); - virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str); + virtual void PragmaMessage(SourceLocation Loc, StringRef Str); virtual void PragmaDiagnosticPush(SourceLocation Loc, - llvm::StringRef Namespace); + StringRef Namespace); virtual void PragmaDiagnosticPop(SourceLocation Loc, - llvm::StringRef Namespace); - virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, - diag::Mapping Map, llvm::StringRef Str); + StringRef Namespace); + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping Map, StringRef Str); bool HandleFirstTokOnLine(Token &Tok); bool MoveToLine(SourceLocation Loc) { @@ -235,7 +236,8 @@ bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() { /// position. void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType) { + SrcMgr::CharacteristicKind NewFileType, + FileID PrevFID) { // Unless we are exiting a #include, make sure to skip ahead to the line the // #include directive was at. SourceManager &SourceMgr = SM; @@ -346,7 +348,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, } void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, - llvm::StringRef Str) { + StringRef Str) { MoveToLine(Loc); OS << "#pragma message("; @@ -369,22 +371,22 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, } void PrintPPOutputPPCallbacks:: -PragmaDiagnosticPush(SourceLocation Loc, llvm::StringRef Namespace) { +PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic push"; EmittedTokensOnThisLine = true; } void PrintPPOutputPPCallbacks:: -PragmaDiagnosticPop(SourceLocation Loc, llvm::StringRef Namespace) { +PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic pop"; EmittedTokensOnThisLine = true; } void PrintPPOutputPPCallbacks:: -PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, - diag::Mapping Map, llvm::StringRef Str) { +PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping Map, StringRef Str) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic "; switch (Map) { @@ -419,7 +421,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) { // Print out space characters so that the first token on a line is // indented for easy reading. - unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation()); + unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation()); // This hack prevents stuff like: // #define HASH # @@ -491,7 +493,7 @@ struct UnknownPragmaHandler : public PragmaHandler { static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks, - llvm::raw_ostream &OS) { + raw_ostream &OS) { char Buffer[256]; Token PrevPrevTok, PrevTok; PrevPrevTok.startToken(); @@ -550,7 +552,7 @@ static int MacroIDCompare(const void* a, const void* b) { return LHS->first->getName().compare(RHS->first->getName()); } -static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { +static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { // Ignore unknown pragmas. PP.AddPragmaHandler(new EmptyPragmaHandler()); @@ -562,7 +564,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - llvm::SmallVector<id_macro_pair, 128> + SmallVector<id_macro_pair, 128> MacrosByID(PP.macro_begin(), PP.macro_end()); llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); @@ -578,7 +580,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { /// DoPrintPreprocessedInput - This implements -E mode. /// -void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, +void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts) { // Show macros with no output is handled specially. if (!Opts.ShowCPP) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp index 069c86d..f8ea9f1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -13,39 +13,48 @@ #include "clang/Frontend/TextDiagnosticBuffer.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; /// HandleDiagnostic - Store the errors, warnings, and notes that are /// reported. /// -void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); llvm::SmallString<100> Buf; Info.FormatDiagnostic(Buf); switch (Level) { - default: assert(0 && "Diagnostic not handled during diagnostic buffering!"); - case Diagnostic::Note: + default: llvm_unreachable( + "Diagnostic not handled during diagnostic buffering!"); + case DiagnosticsEngine::Note: Notes.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; - case Diagnostic::Warning: + case DiagnosticsEngine::Warning: Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; - case Diagnostic::Error: - case Diagnostic::Fatal: + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: Errors.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; } } -void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const { +void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { // FIXME: Flush the diagnostics in order. for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, + it->second.c_str())); for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, + it->second.c_str())); for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, + it->second.c_str())); +} + +DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { + return new TextDiagnosticBuffer(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp index e49e19a..10e7238 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -18,29 +18,29 @@ #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" #include <algorithm> using namespace clang; -static const enum llvm::raw_ostream::Colors noteColor = - llvm::raw_ostream::BLACK; -static const enum llvm::raw_ostream::Colors fixitColor = - llvm::raw_ostream::GREEN; -static const enum llvm::raw_ostream::Colors caretColor = - llvm::raw_ostream::GREEN; -static const enum llvm::raw_ostream::Colors warningColor = - llvm::raw_ostream::MAGENTA; -static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; -static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; +static const enum raw_ostream::Colors noteColor = + raw_ostream::BLACK; +static const enum raw_ostream::Colors fixitColor = + raw_ostream::GREEN; +static const enum raw_ostream::Colors caretColor = + raw_ostream::GREEN; +static const enum raw_ostream::Colors warningColor = + raw_ostream::MAGENTA; +static const enum raw_ostream::Colors errorColor = raw_ostream::RED; +static const enum raw_ostream::Colors fatalColor = raw_ostream::RED; // Used for changing only the bold attribute. -static const enum llvm::raw_ostream::Colors savedColor = - llvm::raw_ostream::SAVEDCOLOR; +static const enum raw_ostream::Colors savedColor = + raw_ostream::SAVEDCOLOR; /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; -TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, +TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), @@ -53,105 +53,52 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { delete &OS; } -void TextDiagnosticPrinter::PrintIncludeStack(Diagnostic::Level Level, - SourceLocation Loc, - const SourceManager &SM) { - if (!DiagOpts->ShowNoteIncludeStack && Level == Diagnostic::Note) return; - - if (Loc.isInvalid()) return; +/// \brief Helper to recursivly walk up the include stack and print each layer +/// on the way back down. +static void PrintIncludeStackRecursively(raw_ostream &OS, + const SourceManager &SM, + SourceLocation Loc, + bool ShowLocation) { + if (Loc.isInvalid()) + return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid()) return; - + // Print out the other include frames first. - PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); + PrintIncludeStackRecursively(OS, SM, PLoc.getIncludeLoc(), ShowLocation); - if (DiagOpts->ShowLocation) + if (ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In included file:\n"; } -/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) -/// any characters in LineNo that intersect the SourceRange. -void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R, - const SourceManager &SM, - unsigned LineNo, FileID FID, - std::string &CaretLine, - const std::string &SourceLine) { - assert(CaretLine.size() == SourceLine.size() && - "Expect a correspondence between source and caret line!"); - if (!R.isValid()) return; - - SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); - SourceLocation End = SM.getInstantiationLoc(R.getEnd()); - - // If the End location and the start location are the same and are a macro - // location, then the range was something that came from a macro expansion - // or _Pragma. If this is an object-like macro, the best we can do is to - // highlight the range. If this is a function-like macro, we'd also like to - // highlight the arguments. - if (Begin == End && R.getEnd().isMacroID()) - End = SM.getInstantiationRange(R.getEnd()).second; - - unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); - if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) - return; // No intersection. - - unsigned EndLineNo = SM.getInstantiationLineNumber(End); - if (EndLineNo < LineNo || SM.getFileID(End) != FID) - return; // No intersection. - - // Compute the column number of the start. - unsigned StartColNo = 0; - if (StartLineNo == LineNo) { - StartColNo = SM.getInstantiationColumnNumber(Begin); - if (StartColNo) --StartColNo; // Zero base the col #. - } - - // Compute the column number of the end. - unsigned EndColNo = CaretLine.size(); - if (EndLineNo == LineNo) { - EndColNo = SM.getInstantiationColumnNumber(End); - if (EndColNo) { - --EndColNo; // Zero base the col #. - - // Add in the length of the token, so that we cover multi-char tokens if - // this is a token range. - if (R.isTokenRange()) - EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); - } else { - EndColNo = CaretLine.size(); - } - } +/// \brief Prints an include stack when appropriate for a particular diagnostic +/// level and location. +/// +/// This routine handles all the logic of suppressing particular include stacks +/// (such as those for notes) and duplicate include stacks when repeated +/// warnings occur within the same file. It also handles the logic of +/// customizing the formatting and display of the include stack. +/// +/// \param Level The diagnostic level of the message this stack pertains to. +/// \param Loc The include location of the current file (not the diagnostic +/// location). +void TextDiagnosticPrinter::PrintIncludeStack(DiagnosticsEngine::Level Level, + SourceLocation Loc, + const SourceManager &SM) { + // Skip redundant include stacks altogether. + if (LastWarningLoc == Loc) + return; + LastWarningLoc = Loc; - assert(StartColNo <= EndColNo && "Invalid range!"); - - // Check that a token range does not highlight only whitespace. - if (R.isTokenRange()) { - // Pick the first non-whitespace column. - while (StartColNo < SourceLine.size() && - (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) - ++StartColNo; - - // Pick the last non-whitespace column. - if (EndColNo > SourceLine.size()) - EndColNo = SourceLine.size(); - while (EndColNo-1 && - (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) - --EndColNo; - - // If the start/end passed each other, then we are trying to highlight a - // range that just exists in whitespace, which must be some sort of other - // bug. - assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); - } + if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) + return; - // Fill the range with ~'s. - for (unsigned i = StartColNo; i < EndColNo; ++i) - CaretLine[i] = '~'; + PrintIncludeStackRecursively(OS, SM, Loc, DiagOpts->ShowLocation); } /// \brief When the source code line we want to print is too long for @@ -300,7 +247,7 @@ static SourceLocation skipToMacroArgExpansion(const SourceManager &SM, SourceLocation StartLoc) { for (SourceLocation L = StartLoc; L.isMacroID(); L = SM.getImmediateSpellingLoc(L)) { - if (SM.isMacroArgInstantiation(L)) + if (SM.isMacroArgExpansion(L)) return L; } @@ -317,12 +264,12 @@ static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM, // When we have the location of (part of) an expanded parameter, its spelling // location points to the argument as typed into the macro call, and // therefore is used to locate the macro caller. - if (SM.isMacroArgInstantiation(Loc)) + if (SM.isMacroArgExpansion(Loc)) return SM.getImmediateSpellingLoc(Loc); // Otherwise, the caller of the macro is located where this macro is // expanded (while the spelling is part of the macro definition). - return SM.getImmediateInstantiationRange(Loc).first; + return SM.getImmediateExpansionRange(Loc).first; } /// Gets the location of the immediate macro callee, one level down the stack @@ -334,34 +281,82 @@ static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM, // When we have the location of (part of) an expanded parameter, its // expansion location points to the unexpanded paramater reference within // the macro definition (or callee). - if (SM.isMacroArgInstantiation(Loc)) - return SM.getImmediateInstantiationRange(Loc).first; + if (SM.isMacroArgExpansion(Loc)) + return SM.getImmediateExpansionRange(Loc).first; // Otherwise, the callee of the macro is located where this location was // spelled inside the macro definition. return SM.getImmediateSpellingLoc(Loc); } -void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, - CharSourceRange *Ranges, - unsigned NumRanges, - const SourceManager &SM, - const FixItHint *Hints, - unsigned NumHints, - unsigned Columns, - unsigned OnMacroInst, - unsigned MacroSkipStart, - unsigned MacroSkipEnd) { - assert(LangOpts && "Unexpected diagnostic outside source file processing"); - assert(!Loc.isInvalid() && "must have a valid source location here"); +namespace { - // If this is a macro ID, first emit information about where this was - // expanded (recursively) then emit information about where the token was - // spelled from. - if (!Loc.isFileID()) { - // Whether to suppress printing this macro expansion. - bool Suppressed - = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd; +/// \brief Class to encapsulate the logic for formatting and printing a textual +/// diagnostic message. +/// +/// This class provides an interface for building and emitting a textual +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// The purpose of this class is to isolate the implementation of printing +/// beautiful text diagnostics from any particular interfaces. The Clang +/// DiagnosticClient is implemented through this class as is diagnostic +/// printing coming out of libclang. +/// +/// A brief worklist: +/// FIXME: Sink the printing of the diagnostic message itself into this class. +/// FIXME: Sink the printing of the include stack into this class. +/// FIXME: Remove the TextDiagnosticPrinter as an input. +/// FIXME: Sink the recursive printing of template instantiations into this +/// class. +class TextDiagnostic { + TextDiagnosticPrinter &Printer; + raw_ostream &OS; + const SourceManager &SM; + const LangOptions &LangOpts; + const DiagnosticOptions &DiagOpts; + +public: + TextDiagnostic(TextDiagnosticPrinter &Printer, + raw_ostream &OS, + const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts) + : Printer(Printer), OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts) { + } + + /// \brief Emit the caret and underlining text. + /// + /// Walks up the macro expansion stack printing the code snippet, caret, + /// underlines and FixItHint display as appropriate at each level. Walk is + /// accomplished by calling itself recursively. + /// + /// FIXME: Remove macro expansion from this routine, it shouldn't be tied to + /// caret diagnostics. + /// FIXME: Break up massive function into logical units. + /// + /// \param Loc The location for this caret. + /// \param Ranges The underlined ranges for this code snippet. + /// \param Hints The FixIt hints active for this diagnostic. + /// \param MacroSkipEnd The depth to stop skipping macro expansions. + /// \param OnMacroInst The current depth of the macro expansion stack. + void EmitCaret(SourceLocation Loc, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + unsigned &MacroDepth, + unsigned OnMacroInst = 0) { + assert(!Loc.isInvalid() && "must have a valid source location here"); + + // If this is a file source location, directly emit the source snippet and + // caret line. Also record the macro depth reached. + if (Loc.isFileID()) { + assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); + MacroDepth = OnMacroInst; + EmitSnippetAndCaret(Loc, Ranges, Hints); + return; + } + // Otherwise recurse through each macro expansion layer. // When processing macros, skip over the expansions leading up to // a macro argument, and trace the argument's expansion stack instead. @@ -370,21 +365,31 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc); // FIXME: Map ranges? - EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, - Hints, NumHints, Columns, - OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); + EmitCaret(OneLevelUp, Ranges, Hints, MacroDepth, OnMacroInst + 1); // Map the location. Loc = getImmediateMacroCalleeLoc(SM, Loc); + unsigned MacroSkipStart = 0, MacroSkipEnd = 0; + if (MacroDepth > DiagOpts.MacroBacktraceLimit) { + MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + + DiagOpts.MacroBacktraceLimit % 2; + MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; + } + + // Whether to suppress printing this macro expansion. + bool Suppressed = (OnMacroInst >= MacroSkipStart && + OnMacroInst < MacroSkipEnd); + // Map the ranges. - for (unsigned i = 0; i != NumRanges; ++i) { - CharSourceRange &R = Ranges[i]; - SourceLocation S = R.getBegin(), E = R.getEnd(); - if (S.isMacroID()) - R.setBegin(getImmediateMacroCalleeLoc(SM, S)); - if (E.isMacroID()) - R.setEnd(getImmediateMacroCalleeLoc(SM, E)); + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) { + SourceLocation Start = I->getBegin(), End = I->getEnd(); + if (Start.isMacroID()) + I->setBegin(getImmediateMacroCalleeLoc(SM, Start)); + if (End.isMacroID()) + I->setEnd(getImmediateMacroCalleeLoc(SM, End)); } if (!Suppressed) { @@ -398,139 +403,248 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // If this diagnostic is not in the main file, print out the // "included from" lines. - if (LastWarningLoc != PLoc.getIncludeLoc()) { - LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM); - } + Printer.PrintIncludeStack(DiagnosticsEngine::Note, PLoc.getIncludeLoc(), + SM); - if (DiagOpts->ShowLocation) { + if (DiagOpts.ShowLocation) { // Emit the file/line/column that this expansion came from. OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; - if (DiagOpts->ShowColumn) + if (DiagOpts.ShowColumn) OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: expanded from:\n"; - EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, 0, 0, - Columns, OnMacroInst + 1, MacroSkipStart, - MacroSkipEnd); + EmitSnippetAndCaret(Loc, Ranges, ArrayRef<FixItHint>()); return; } - + if (OnMacroInst == MacroSkipStart) { // Tell the user that we've skipped contexts. OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see " "all)\n"; } - - return; } - - // Decompose the location into a FID/Offset pair. - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); - FileID FID = LocInfo.first; - unsigned FileOffset = LocInfo.second; - - // Get information about the buffer it points into. - bool Invalid = false; - const char *BufStart = SM.getBufferData(FID, &Invalid).data(); - if (Invalid) - return; - unsigned ColNo = SM.getColumnNumber(FID, FileOffset); - unsigned CaretEndColNo - = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); + /// \brief Emit a code snippet and caret line. + /// + /// This routine emits a single line's code snippet and caret line.. + /// + /// \param Loc The location for the caret. + /// \param Ranges The underlined ranges for this code snippet. + /// \param Hints The FixIt hints active for this diagnostic. + void EmitSnippetAndCaret(SourceLocation Loc, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints) { + assert(!Loc.isInvalid() && "must have a valid source location here"); + assert(Loc.isFileID() && "must have a file location here"); + + // Decompose the location into a FID/Offset pair. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + // Get information about the buffer it points into. + bool Invalid = false; + const char *BufStart = SM.getBufferData(FID, &Invalid).data(); + if (Invalid) + return; - // Rewind from the current position to the start of the line. - const char *TokPtr = BufStart+FileOffset; - const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. + unsigned LineNo = SM.getLineNumber(FID, FileOffset); + unsigned ColNo = SM.getColumnNumber(FID, FileOffset); + unsigned CaretEndColNo + = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts); + + // Rewind from the current position to the start of the line. + const char *TokPtr = BufStart+FileOffset; + const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. + + + // Compute the line end. Scan forward from the error position to the end of + // the line. + const char *LineEnd = TokPtr; + while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') + ++LineEnd; + + // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past + // the source line length as currently being computed. See + // test/Misc/message-length.c. + CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(LineStart, LineEnd); + + // Create a line for the caret that is filled with spaces that is the same + // length as the line of source code. + std::string CaretLine(LineEnd-LineStart, ' '); + + // Highlight all of the characters covered by Ranges with ~ characters. + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + HighlightRange(*I, LineNo, FID, SourceLine, CaretLine); + + // Next, insert the caret itself. + if (ColNo-1 < CaretLine.size()) + CaretLine[ColNo-1] = '^'; + else + CaretLine.push_back('^'); + + ExpandTabs(SourceLine, CaretLine); + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying + // to produce easily machine parsable output. Add a space before the + // source line and the caret to make it trivial to tell the main diagnostic + // line from what the user is intended to see. + if (DiagOpts.ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } + std::string FixItInsertionLine = BuildFixItInsertionLine(LineNo, + LineStart, LineEnd, + Hints); - // Compute the line end. Scan forward from the error position to the end of - // the line. - const char *LineEnd = TokPtr; - while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') - ++LineEnd; + // If the source line is too long for our terminal, select only the + // "interesting" source region within that line. + unsigned Columns = DiagOpts.MessageLength; + if (Columns && SourceLine.size() > Columns) + SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, + CaretEndColNo, Columns); - // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past - // the source line length as currently being computed. See - // test/Misc/message-length.c. - CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + // Finally, remove any blank spaces from the end of CaretLine. + while (CaretLine[CaretLine.size()-1] == ' ') + CaretLine.erase(CaretLine.end()-1); - // Copy the line of code into an std::string for ease of manipulation. - std::string SourceLine(LineStart, LineEnd); + // Emit what we have computed. + OS << SourceLine << '\n'; - // Create a line for the caret that is filled with spaces that is the same - // length as the line of source code. - std::string CaretLine(LineEnd-LineStart, ' '); + if (DiagOpts.ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts.ShowColors) + OS.resetColor(); - // Highlight all of the characters covered by Ranges with ~ characters. - if (NumRanges) { - unsigned LineNo = SM.getLineNumber(FID, FileOffset); + if (!FixItInsertionLine.empty()) { + if (DiagOpts.ShowColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); + if (DiagOpts.ShowSourceRanges) + OS << ' '; + OS << FixItInsertionLine << '\n'; + if (DiagOpts.ShowColors) + OS.resetColor(); + } - for (unsigned i = 0, e = NumRanges; i != e; ++i) - HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); + // Print out any parseable fixit information requested by the options. + EmitParseableFixits(Hints); } - // Next, insert the caret itself. - if (ColNo-1 < CaretLine.size()) - CaretLine[ColNo-1] = '^'; - else - CaretLine.push_back('^'); - - // Scan the source line, looking for tabs. If we find any, manually expand - // them to spaces and update the CaretLine to match. - for (unsigned i = 0; i != SourceLine.size(); ++i) { - if (SourceLine[i] != '\t') continue; - - // Replace this tab with at least one space. - SourceLine[i] = ' '; - - // Compute the number of spaces we need to insert. - unsigned TabStop = DiagOpts->TabStop; - assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && - "Invalid -ftabstop value"); - unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); - assert(NumSpaces < TabStop && "Invalid computation of space amt"); +private: + /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. + void HighlightRange(const CharSourceRange &R, + unsigned LineNo, FileID FID, + const std::string &SourceLine, + std::string &CaretLine) { + assert(CaretLine.size() == SourceLine.size() && + "Expect a correspondence between source and caret line!"); + if (!R.isValid()) return; + + SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); + SourceLocation End = SM.getExpansionLoc(R.getEnd()); + + // If the End location and the start location are the same and are a macro + // location, then the range was something that came from a macro expansion + // or _Pragma. If this is an object-like macro, the best we can do is to + // highlight the range. If this is a function-like macro, we'd also like to + // highlight the arguments. + if (Begin == End && R.getEnd().isMacroID()) + End = SM.getExpansionRange(R.getEnd()).second; + + unsigned StartLineNo = SM.getExpansionLineNumber(Begin); + if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) + return; // No intersection. + + unsigned EndLineNo = SM.getExpansionLineNumber(End); + if (EndLineNo < LineNo || SM.getFileID(End) != FID) + return; // No intersection. + + // Compute the column number of the start. + unsigned StartColNo = 0; + if (StartLineNo == LineNo) { + StartColNo = SM.getExpansionColumnNumber(Begin); + if (StartColNo) --StartColNo; // Zero base the col #. + } - // Insert spaces into the SourceLine. - SourceLine.insert(i+1, NumSpaces, ' '); + // Compute the column number of the end. + unsigned EndColNo = CaretLine.size(); + if (EndLineNo == LineNo) { + EndColNo = SM.getExpansionColumnNumber(End); + if (EndColNo) { + --EndColNo; // Zero base the col #. + + // Add in the length of the token, so that we cover multi-char tokens if + // this is a token range. + if (R.isTokenRange()) + EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); + } else { + EndColNo = CaretLine.size(); + } + } - // Insert spaces or ~'s into CaretLine. - CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); - } + assert(StartColNo <= EndColNo && "Invalid range!"); + + // Check that a token range does not highlight only whitespace. + if (R.isTokenRange()) { + // Pick the first non-whitespace column. + while (StartColNo < SourceLine.size() && + (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) + ++StartColNo; + + // Pick the last non-whitespace column. + if (EndColNo > SourceLine.size()) + EndColNo = SourceLine.size(); + while (EndColNo-1 && + (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) + --EndColNo; + + // If the start/end passed each other, then we are trying to highlight a + // range that just exists in whitespace, which must be some sort of other + // bug. + assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); + } - // If we are in -fdiagnostics-print-source-range-info mode, we are trying to - // produce easily machine parsable output. Add a space before the source line - // and the caret to make it trivial to tell the main diagnostic line from what - // the user is intended to see. - if (DiagOpts->ShowSourceRanges) { - SourceLine = ' ' + SourceLine; - CaretLine = ' ' + CaretLine; + // Fill the range with ~'s. + for (unsigned i = StartColNo; i < EndColNo; ++i) + CaretLine[i] = '~'; } - std::string FixItInsertionLine; - if (NumHints && DiagOpts->ShowFixits) { - for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; - Hint != LastHint; ++Hint) { - if (!Hint->CodeToInsert.empty()) { + std::string BuildFixItInsertionLine(unsigned LineNo, + const char *LineStart, + const char *LineEnd, + ArrayRef<FixItHint> Hints) { + std::string FixItInsertionLine; + if (Hints.empty() || !DiagOpts.ShowFixits) + return FixItInsertionLine; + + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + if (!I->CodeToInsert.empty()) { // We have an insertion hint. Determine whether the inserted // code is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo - = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin()); - if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == - SM.getLineNumber(FID, FileOffset)) { + = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); + if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) { // Insert the new code into the line just below the code // that the user wrote. unsigned HintColNo = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); unsigned LastColumnModified - = HintColNo - 1 + Hint->CodeToInsert.size(); + = HintColNo - 1 + I->CodeToInsert.size(); if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); - std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), + std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), FixItInsertionLine.begin() + HintColNo - 1); } else { FixItInsertionLine.clear(); @@ -538,119 +652,348 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, } } } + + if (FixItInsertionLine.empty()) + return FixItInsertionLine; + // Now that we have the entire fixit line, expand the tabs in it. // Since we don't want to insert spaces in the middle of a word, // find each word and the column it should line up with and insert // spaces until they match. - if (!FixItInsertionLine.empty()) { - unsigned FixItPos = 0; - unsigned LinePos = 0; - unsigned TabExpandedCol = 0; - unsigned LineLength = LineEnd - LineStart; - - while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { - // Find the next word in the FixIt line. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] == ' ') - ++FixItPos; - unsigned CharDistance = FixItPos - TabExpandedCol; - - // Walk forward in the source line, keeping track of - // the tab-expanded column. - for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) - if (LinePos >= LineLength || LineStart[LinePos] != '\t') - ++TabExpandedCol; - else - TabExpandedCol = - (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; - - // Adjust the fixit line to match this column. - FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); - FixItPos = TabExpandedCol; - - // Walk to the end of the word. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] != ' ') - ++FixItPos; - } + unsigned FixItPos = 0; + unsigned LinePos = 0; + unsigned TabExpandedCol = 0; + unsigned LineLength = LineEnd - LineStart; + + while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { + // Find the next word in the FixIt line. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] == ' ') + ++FixItPos; + unsigned CharDistance = FixItPos - TabExpandedCol; + + // Walk forward in the source line, keeping track of + // the tab-expanded column. + for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) + if (LinePos >= LineLength || LineStart[LinePos] != '\t') + ++TabExpandedCol; + else + TabExpandedCol = + (TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop; + + // Adjust the fixit line to match this column. + FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); + FixItPos = TabExpandedCol; + + // Walk to the end of the word. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] != ' ') + ++FixItPos; } + + return FixItInsertionLine; } - // If the source line is too long for our terminal, select only the - // "interesting" source region within that line. - if (Columns && SourceLine.size() > Columns) - SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, - CaretEndColNo, Columns); + void ExpandTabs(std::string &SourceLine, std::string &CaretLine) { + // Scan the source line, looking for tabs. If we find any, manually expand + // them to spaces and update the CaretLine to match. + for (unsigned i = 0; i != SourceLine.size(); ++i) { + if (SourceLine[i] != '\t') continue; - // Finally, remove any blank spaces from the end of CaretLine. - while (CaretLine[CaretLine.size()-1] == ' ') - CaretLine.erase(CaretLine.end()-1); + // Replace this tab with at least one space. + SourceLine[i] = ' '; - // Emit what we have computed. - OS << SourceLine << '\n'; + // Compute the number of spaces we need to insert. + unsigned TabStop = DiagOpts.TabStop; + assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && + "Invalid -ftabstop value"); + unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); + assert(NumSpaces < TabStop && "Invalid computation of space amt"); - if (DiagOpts->ShowColors) - OS.changeColor(caretColor, true); - OS << CaretLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + // Insert spaces into the SourceLine. + SourceLine.insert(i+1, NumSpaces, ' '); - if (!FixItInsertionLine.empty()) { - if (DiagOpts->ShowColors) - // Print fixit line in color - OS.changeColor(fixitColor, false); - if (DiagOpts->ShowSourceRanges) - OS << ' '; - OS << FixItInsertionLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + // Insert spaces or ~'s into CaretLine. + CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); + } } - if (DiagOpts->ShowParseableFixits) { + void EmitParseableFixits(ArrayRef<FixItHint> Hints) { + if (!DiagOpts.ShowParseableFixits) + return; // We follow FixItRewriter's example in not (yet) handling // fix-its in macros. - bool BadApples = false; - for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { - if (Hint->RemoveRange.isInvalid() || - Hint->RemoveRange.getBegin().isMacroID() || - Hint->RemoveRange.getEnd().isMacroID()) { - BadApples = true; + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + if (I->RemoveRange.isInvalid() || + I->RemoveRange.getBegin().isMacroID() || + I->RemoveRange.getEnd().isMacroID()) + return; + } + + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + SourceLocation BLoc = I->RemoveRange.getBegin(); + SourceLocation ELoc = I->RemoveRange.getEnd(); + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); + + // Adjust for token ranges. + if (I->RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts); + + // We specifically do not do word-wrapping or tab-expansion here, + // because this is supposed to be easy to parse. + PresumedLoc PLoc = SM.getPresumedLoc(BLoc); + if (PLoc.isInvalid()) break; + + OS << "fix-it:\""; + OS.write_escaped(PLoc.getFilename()); + OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) + << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) + << '-' << SM.getLineNumber(EInfo.first, EInfo.second) + << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) + << "}:\""; + OS.write_escaped(I->CodeToInsert); + OS << "\"\n"; + } + } +}; + +} // end namespace + +/// Get the presumed location of a diagnostic message. This computes the +/// presumed location for the top of any macro backtrace when present. +static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, + SourceLocation Loc) { + // This is a condensed form of the algorithm used by EmitCaretDiagnostic to + // walk to the top of the macro call stack. + while (Loc.isMacroID()) { + Loc = skipToMacroArgExpansion(SM, Loc); + Loc = getImmediateMacroCallerLoc(SM, Loc); + } + + return SM.getPresumedLoc(Loc); +} + +/// \brief Print out the file/line/column information and include trace. +/// +/// This method handlen the emission of the diagnostic location information. +/// This includes extracting as much location information as is present for the +/// diagnostic and printing it, as well as any include stack or source ranges +/// necessary. +void TextDiagnosticPrinter::EmitDiagnosticLoc(DiagnosticsEngine::Level Level, + const Diagnostic &Info, + const SourceManager &SM, + PresumedLoc PLoc) { + if (PLoc.isInvalid()) { + // At least print the file name if available: + FileID FID = SM.getFileID(Info.getLocation()); + if (!FID.isInvalid()) { + const FileEntry* FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) { + OS << FE->getName(); + if (FE->getDevice() == 0 && FE->getInode() == 0 + && FE->getFileMode() == 0) { + // in PCH is a guess, but a good one: + OS << " (in PCH)"; + } + OS << ": "; } } + return; + } + unsigned LineNo = PLoc.getLine(); + + if (!DiagOpts->ShowLocation) + return; + + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); - if (!BadApples) { - for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { + OS << PLoc.getFilename(); + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: OS << ':' << LineNo; break; + case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; + case DiagnosticOptions::Vi: OS << " +" << LineNo; break; + } - SourceLocation B = Hint->RemoveRange.getBegin(); - SourceLocation E = Hint->RemoveRange.getEnd(); + if (DiagOpts->ShowColumn) + // Compute the column number. + if (unsigned ColNo = PLoc.getColumn()) { + if (DiagOpts->Format == DiagnosticOptions::Msvc) { + OS << ','; + ColNo--; + } else + OS << ':'; + OS << ColNo; + } + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: + case DiagnosticOptions::Vi: OS << ':'; break; + case DiagnosticOptions::Msvc: OS << ") : "; break; + } - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { + FileID CaretFileID = + SM.getFileID(SM.getExpansionLoc(Info.getLocation())); + bool PrintedRange = false; + + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { + // Ignore invalid ranges. + if (!Info.getRange(i).isValid()) continue; + + SourceLocation B = Info.getRange(i).getBegin(); + SourceLocation E = Info.getRange(i).getEnd(); + B = SM.getExpansionLoc(B); + E = SM.getExpansionLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a + // macro expansion or _Pragma. If this is an object-like macro, the + // best we can do is to highlight the range. If this is a + // function-like macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getExpansionRange(Info.getRange(i).getEnd()).second; + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + + // If the start or end of the range is in another file, just discard + // it. + if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + continue; + + // Add in the length of the token, so that we cover multi-char + // tokens. + unsigned TokSize = 0; + if (Info.getRange(i).isTokenRange()) + TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); + + OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) + << '}'; + PrintedRange = true; + } + + if (PrintedRange) + OS << ':'; + } + OS << ' '; +} - // Adjust for token ranges. - if (Hint->RemoveRange.isTokenRange()) - EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts); +/// \brief Print the diagonstic level to a raw_ostream. +/// +/// Handles colorizing the level and formatting. +static void printDiagnosticLevel(raw_ostream &OS, + DiagnosticsEngine::Level Level, + bool ShowColors) { + if (ShowColors) { + // Print diagnostic category in bold and color + switch (Level) { + case DiagnosticsEngine::Ignored: + llvm_unreachable("Invalid diagnostic type"); + case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break; + case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break; + case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break; + case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break; + } + } - // We specifically do not do word-wrapping or tab-expansion here, - // because this is supposed to be easy to parse. - PresumedLoc PLoc = SM.getPresumedLoc(B); - if (PLoc.isInvalid()) - break; - - OS << "fix-it:\""; - OS.write_escaped(SM.getPresumedLoc(B).getFilename()); - OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) - << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) - << '-' << SM.getLineNumber(EInfo.first, EInfo.second) - << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) - << "}:\""; - OS.write_escaped(Hint->CodeToInsert); - OS << "\"\n"; + switch (Level) { + case DiagnosticsEngine::Ignored: llvm_unreachable("Invalid diagnostic type"); + case DiagnosticsEngine::Note: OS << "note: "; break; + case DiagnosticsEngine::Warning: OS << "warning: "; break; + case DiagnosticsEngine::Error: OS << "error: "; break; + case DiagnosticsEngine::Fatal: OS << "fatal error: "; break; + } + + if (ShowColors) + OS.resetColor(); +} + +/// \brief Print the diagnostic name to a raw_ostream. +/// +/// This prints the diagnostic name to a raw_ostream if it has one. It formats +/// the name according to the expected diagnostic message formatting: +/// " [diagnostic_name_here]" +static void printDiagnosticName(raw_ostream &OS, const Diagnostic &Info) { + if (!DiagnosticIDs::isBuiltinNote(Info.getID())) + OS << " [" << DiagnosticIDs::getName(Info.getID()) << "]"; +} + +/// \brief Print any diagnostic option information to a raw_ostream. +/// +/// This implements all of the logic for adding diagnostic options to a message +/// (via OS). Each relevant option is comma separated and all are enclosed in +/// the standard bracketing: " [...]". +static void printDiagnosticOptions(raw_ostream &OS, + DiagnosticsEngine::Level Level, + const Diagnostic &Info, + const DiagnosticOptions &DiagOpts) { + bool Started = false; + if (DiagOpts.ShowOptionNames) { + // Handle special cases for non-warnings early. + if (Info.getID() == diag::fatal_too_many_errors) { + OS << " [-ferror-limit=]"; + return; + } + + // The code below is somewhat fragile because we are essentially trying to + // report to the user what happened by inferring what the diagnostic engine + // did. Eventually it might make more sense to have the diagnostic engine + // include some "why" information in the diagnostic. + + // If this is a warning which has been mapped to an error by the user (as + // inferred by checking whether the default mapping is to an error) then + // flag it as such. Note that diagnostics could also have been mapped by a + // pragma, but we don't currently have a way to distinguish this. + if (Level == DiagnosticsEngine::Error && + DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) && + !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) { + OS << " [-Werror"; + Started = true; + } + + // If the diagnostic is an extension diagnostic and not enabled by default + // then it must have been turned on with -pedantic. + bool EnabledByDefault; + if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), + EnabledByDefault) && + !EnabledByDefault) { + OS << (Started ? "," : " [") << "-pedantic"; + Started = true; + } + + StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); + if (!Opt.empty()) { + OS << (Started ? "," : " [") << "-W" << Opt; + Started = true; + } + } + + // If the user wants to see category information, include it too. + if (DiagOpts.ShowCategories) { + unsigned DiagCategory = + DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); + if (DiagCategory) { + OS << (Started ? "," : " ["); + Started = true; + if (DiagOpts.ShowCategories == 1) + OS << DiagCategory; + else { + assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value"); + OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory); } } } + if (Started) + OS << ']'; } /// \brief Skip over whitespace in the string, starting at the given @@ -659,9 +1002,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, /// \returns The index of the first non-whitespace character that is /// greater than or equal to Idx or, if no such character exists, /// returns the end of the string. -static unsigned skipWhitespace(unsigned Idx, - const llvm::SmallVectorImpl<char> &Str, - unsigned Length) { +static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) { while (Idx < Length && isspace(Str[Idx])) ++Idx; return Idx; @@ -692,8 +1033,7 @@ static inline char findMatchingPunctuation(char c) { /// /// \returns the index pointing one character past the end of the /// word. -static unsigned findEndOfWord(unsigned Start, - const llvm::SmallVectorImpl<char> &Str, +static unsigned findEndOfWord(unsigned Start, StringRef Str, unsigned Length, unsigned Column, unsigned Columns) { assert(Start < Str.size() && "Invalid start position!"); @@ -748,38 +1088,22 @@ static unsigned findEndOfWord(unsigned Start, /// \brief Print the given string to a stream, word-wrapping it to /// some number of columns in the process. /// -/// \brief OS the stream to which the word-wrapping string will be +/// \param OS the stream to which the word-wrapping string will be /// emitted. -/// -/// \brief Str the string to word-wrap and output. -/// -/// \brief Columns the number of columns to word-wrap to. -/// -/// \brief Column the column number at which the first character of \p +/// \param Str the string to word-wrap and output. +/// \param Columns the number of columns to word-wrap to. +/// \param Column the column number at which the first character of \p /// Str will be printed. This will be non-zero when part of the first /// line has already been printed. -/// -/// \brief Indentation the number of spaces to indent any lines beyond +/// \param Indentation the number of spaces to indent any lines beyond /// the first line. -/// /// \returns true if word-wrapping was required, or false if the /// string fit on the first line. -static bool PrintWordWrapped(llvm::raw_ostream &OS, - const llvm::SmallVectorImpl<char> &Str, +static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, unsigned Column = 0, unsigned Indentation = WordWrapIndentation) { - unsigned Length = Str.size(); - - // If there is a newline in this message somewhere, find that - // newline and split the message into the part before the newline - // (which will be word-wrapped) and the part from the newline one - // (which will be emitted unchanged). - for (unsigned I = 0; I != Length; ++I) - if (Str[I] == '\n') { - Length = I; - break; - } + const unsigned Length = std::min(Str.find('\n'), Str.size()); // The string used to indent each line. llvm::SmallString<16> IndentStr; @@ -803,7 +1127,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS, OS << ' '; Column += 1; } - OS.write(&Str[WordStart], WordLength); + OS << Str.substr(WordStart, WordLength); Column += WordLength; continue; } @@ -812,38 +1136,57 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS, // line. OS << '\n'; OS.write(&IndentStr[0], Indentation); - OS.write(&Str[WordStart], WordLength); + OS << Str.substr(WordStart, WordLength); Column = Indentation + WordLength; Wrapped = true; } - if (Length == Str.size()) - return Wrapped; // We're done. + // Append any remaning text from the message with its existing formatting. + OS << Str.substr(Length); - // There is a newline in the message, followed by something that - // will not be word-wrapped. Print that. - OS.write(&Str[Length], Str.size() - Length); - return true; + return Wrapped; } -/// Get the presumed location of a diagnostic message. This computes the -/// presumed location for the top of any macro backtrace when present. -static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, - SourceLocation Loc) { - // This is a condensed form of the algorithm used by EmitCaretDiagnostic to - // walk to the top of the macro call stack. - while (Loc.isMacroID()) { - Loc = skipToMacroArgExpansion(SM, Loc); - Loc = getImmediateMacroCallerLoc(SM, Loc); +static void printDiagnosticMessage(raw_ostream &OS, + DiagnosticsEngine::Level Level, + StringRef Message, + unsigned CurrentColumn, unsigned Columns, + bool ShowColors) { + if (ShowColors) { + // Print warnings, errors and fatal errors in bold, no color + switch (Level) { + case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break; + case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break; + case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break; + default: break; //don't bold notes + } } - return SM.getPresumedLoc(Loc); + if (Columns) + printWordWrapped(OS, Message, Columns, CurrentColumn); + else + OS << Message; + + if (ShowColors) + OS.resetColor(); + OS << '\n'; } -void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); + + // Render the diagnostic message into a temporary buffer eagerly. We'll use + // this later as we print out the diagnostic to the terminal. + llvm::SmallString<100> OutStr; + Info.FormatDiagnostic(OutStr); + + llvm::raw_svector_ostream DiagMessageStream(OutStr); + if (DiagOpts->ShowNames) + printDiagnosticName(DiagMessageStream, Info); + printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); + // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error @@ -854,289 +1197,82 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (!Prefix.empty()) OS << Prefix << ": "; - // If the location is specified, print out a file/line/col and include trace - // if enabled. - if (Info.getLocation().isValid()) { - const SourceManager &SM = Info.getSourceManager(); - PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); - if (PLoc.isInvalid()) { - // At least print the file name if available: - FileID FID = SM.getFileID(Info.getLocation()); - if (!FID.isInvalid()) { - const FileEntry* FE = SM.getFileEntryForID(FID); - if (FE && FE->getName()) { - OS << FE->getName(); - if (FE->getDevice() == 0 && FE->getInode() == 0 - && FE->getFileMode() == 0) { - // in PCH is a guess, but a good one: - OS << " (in PCH)"; - } - OS << ": "; - } - } - } else { - unsigned LineNo = PLoc.getLine(); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - if (LastWarningLoc != PLoc.getIncludeLoc()) { - LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(Level, LastWarningLoc, SM); - StartOfLocationInfo = OS.tell(); - } - - // Compute the column number. - if (DiagOpts->ShowLocation) { - if (DiagOpts->ShowColors) - OS.changeColor(savedColor, true); - - OS << PLoc.getFilename(); - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: OS << ':' << LineNo; break; - case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; - case DiagnosticOptions::Vi: OS << " +" << LineNo; break; - } - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) { - if (DiagOpts->Format == DiagnosticOptions::Msvc) { - OS << ','; - ColNo--; - } else - OS << ':'; - OS << ColNo; - } - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: - case DiagnosticOptions::Vi: OS << ':'; break; - case DiagnosticOptions::Msvc: OS << ") : "; break; - } - - - if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { - FileID CaretFileID = - SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); - bool PrintedRange = false; - - for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { - // Ignore invalid ranges. - if (!Info.getRange(i).isValid()) continue; - - SourceLocation B = Info.getRange(i).getBegin(); - SourceLocation E = Info.getRange(i).getEnd(); - B = SM.getInstantiationLoc(B); - E = SM.getInstantiationLoc(E); - - // If the End location and the start location are the same and are a - // macro location, then the range was something that came from a - // macro expansion or _Pragma. If this is an object-like macro, the - // best we can do is to highlight the range. If this is a - // function-like macro, we'd also like to highlight the arguments. - if (B == E && Info.getRange(i).getEnd().isMacroID()) - E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; - - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); - - // If the start or end of the range is in another file, just discard - // it. - if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) - continue; - - // Add in the length of the token, so that we cover multi-char - // tokens. - unsigned TokSize = 0; - if (Info.getRange(i).isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); - - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) - << '}'; - PrintedRange = true; - } - - if (PrintedRange) - OS << ':'; - } - } - OS << ' '; - if (DiagOpts->ShowColors) - OS.resetColor(); - } - } - - if (DiagOpts->ShowColors) { - // Print diagnostic category in bold and color - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS.changeColor(noteColor, true); break; - case Diagnostic::Warning: OS.changeColor(warningColor, true); break; - case Diagnostic::Error: OS.changeColor(errorColor, true); break; - case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; - } - } - - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS << "note: "; break; - case Diagnostic::Warning: OS << "warning: "; break; - case Diagnostic::Error: OS << "error: "; break; - case Diagnostic::Fatal: OS << "fatal error: "; break; + // Use a dedicated, simpler path for diagnostics without a valid location. + // This is important as if the location is missing, we may be emitting + // diagnostics in a context that lacks language options, a source manager, or + // other infrastructure necessary when emitting more rich diagnostics. + if (!Info.getLocation().isValid()) { + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); + printDiagnosticMessage(OS, Level, DiagMessageStream.str(), + OS.tell() - StartOfLocationInfo, + DiagOpts->MessageLength, DiagOpts->ShowColors); + OS.flush(); + return; } - if (DiagOpts->ShowColors) - OS.resetColor(); - - llvm::SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); + // Assert that the rest of our infrastructure is setup properly. + assert(LangOpts && "Unexpected diagnostic outside source file processing"); + assert(DiagOpts && "Unexpected diagnostic without options set"); + assert(Info.hasSourceManager() && + "Unexpected diagnostic with no source manager"); + const SourceManager &SM = Info.getSourceManager(); + TextDiagnostic TextDiag(*this, OS, SM, *LangOpts, *DiagOpts); - if (DiagOpts->ShowNames && - !DiagnosticIDs::isBuiltinNote(Info.getID())) { - OutStr += " ["; - OutStr += DiagnosticIDs::getName(Info.getID()); - OutStr += "]"; - } - - std::string OptionName; - if (DiagOpts->ShowOptionNames) { - // Was this a warning mapped to an error using -Werror or pragma? - if (Level == Diagnostic::Error && - DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID())) { - diag::Mapping mapping = diag::MAP_IGNORE; - Info.getDiags()->getDiagnosticLevel(Info.getID(), Info.getLocation(), - &mapping); - if (mapping == diag::MAP_WARNING) - OptionName += "-Werror"; - } + PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); - llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); - if (!Opt.empty()) { - if (!OptionName.empty()) - OptionName += ','; - OptionName += "-W"; - OptionName += Opt; - } else if (Info.getID() == diag::fatal_too_many_errors) { - OptionName = "-ferror-limit="; - } else { - // If the diagnostic is an extension diagnostic and not enabled by default - // then it must have been turned on with -pedantic. - bool EnabledByDefault; - if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), - EnabledByDefault) && - !EnabledByDefault) - OptionName = "-pedantic"; - } - } - - // If the user wants to see category information, include it too. - unsigned DiagCategory = 0; - if (DiagOpts->ShowCategories) - DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); - - // If there is any categorization information, include it. - if (!OptionName.empty() || DiagCategory != 0) { - bool NeedsComma = false; - OutStr += " ["; - - if (!OptionName.empty()) { - OutStr += OptionName; - NeedsComma = true; - } - - if (DiagCategory) { - if (NeedsComma) OutStr += ','; - if (DiagOpts->ShowCategories == 1) - OutStr += llvm::utostr(DiagCategory); - else { - assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); - OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory); - } - } - - OutStr += "]"; - } + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); + StartOfLocationInfo = OS.tell(); - - if (DiagOpts->ShowColors) { - // Print warnings, errors and fatal errors in bold, no color - switch (Level) { - case Diagnostic::Warning: OS.changeColor(savedColor, true); break; - case Diagnostic::Error: OS.changeColor(savedColor, true); break; - case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; - default: break; //don't bold notes - } - } + // Next emit the location of this particular diagnostic. + EmitDiagnosticLoc(Level, Info, SM, PLoc); - if (DiagOpts->MessageLength) { - // We will be word-wrapping the error message, so compute the - // column number where we currently are (after printing the - // location information). - unsigned Column = OS.tell() - StartOfLocationInfo; - PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); - } else { - OS.write(OutStr.begin(), OutStr.size()); - } - OS << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); + printDiagnosticMessage(OS, Level, DiagMessageStream.str(), + OS.tell() - StartOfLocationInfo, + DiagOpts->MessageLength, DiagOpts->ShowColors); + // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved // from the last diagnostic, if the last diagnostic was a note that // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (DiagOpts->ShowCarets && Info.getLocation().isValid() && + if (DiagOpts->ShowCarets && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || - (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || + (LastCaretDiagnosticWasNote && Level != DiagnosticsEngine::Note) || Info.getNumFixItHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); - LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); + LastCaretDiagnosticWasNote = (Level == DiagnosticsEngine::Note); // Get the ranges into a local array we can hack on. - CharSourceRange Ranges[20]; - unsigned NumRanges = Info.getNumRanges(); - assert(NumRanges < 20 && "Out of space"); - for (unsigned i = 0; i != NumRanges; ++i) - Ranges[i] = Info.getRange(i); - - unsigned NumHints = Info.getNumFixItHints(); - for (unsigned i = 0; i != NumHints; ++i) { + SmallVector<CharSourceRange, 20> Ranges; + Ranges.reserve(Info.getNumRanges()); + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) + Ranges.push_back(Info.getRange(i)); + + for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) { const FixItHint &Hint = Info.getFixItHint(i); - if (Hint.RemoveRange.isValid()) { - assert(NumRanges < 20 && "Out of space"); - Ranges[NumRanges++] = Hint.RemoveRange; - } + if (Hint.RemoveRange.isValid()) + Ranges.push_back(Hint.RemoveRange); } - const SourceManager &SM = LastLoc.getManager(); - unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; - if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { - // Compute the length of the macro-expansion backtrace, so that we - // can establish which steps in the macro backtrace we'll skip. - SourceLocation Loc = LastLoc; - unsigned Depth = 0; - do { - ++Depth; - Loc = skipToMacroArgExpansion(SM, Loc); - Loc = getImmediateMacroCallerLoc(SM, Loc); - } while (!Loc.isFileID()); - - if (Depth > DiagOpts->MacroBacktraceLimit) { - MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + - DiagOpts->MacroBacktraceLimit % 2; - MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; - } - } - - EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), - Info.getFixItHints(), - Info.getNumFixItHints(), - DiagOpts->MessageLength, - 0, MacroInstSkipStart, MacroInstSkipEnd); + unsigned MacroDepth = 0; + TextDiag.EmitCaret(LastLoc, Ranges, + llvm::makeArrayRef(Info.getFixItHints(), + Info.getNumFixItHints()), + MacroDepth); } OS.flush(); } + +DiagnosticConsumer * +TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index fff417e..cf35c8e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -1,4 +1,4 @@ -//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// +//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===// // // The LLVM Compiler Infrastructure // @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Lex/Preprocessor.h" @@ -20,19 +20,24 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, - DiagnosticClient *_Primary) - : Diags(_Diags), PrimaryClient(_Primary), - Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) { +VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) + : Diags(_Diags), PrimaryClient(Diags.getClient()), + OwnsPrimaryClient(Diags.ownsClient()), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) +{ + Diags.takeClient(); } -VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { - CheckDiagnostics(); +VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { + CheckDiagnostics(); + Diags.takeClient(); + if (OwnsPrimaryClient) + delete PrimaryClient; } -// DiagnosticClient interface. +// DiagnosticConsumer interface. -void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, +void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) { // FIXME: Const hack, we screw up the preprocessor but in practice its ok // because it doesn't get reused. It would be better if we could make a copy @@ -42,7 +47,7 @@ void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, PrimaryClient->BeginSourceFile(LangOpts, PP); } -void VerifyDiagnosticsClient::EndSourceFile() { +void VerifyDiagnosticConsumer::EndSourceFile() { CheckDiagnostics(); PrimaryClient->EndSourceFile(); @@ -50,8 +55,12 @@ void VerifyDiagnosticsClient::EndSourceFile() { CurrentPreprocessor = 0; } -void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { +void VerifyDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { + const SourceManager &SM = Info.getSourceManager(); + FirstErrorFID = SM.getFileID(Info.getLocation()); + } // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); @@ -163,7 +172,7 @@ public: : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } // Return true if string literal is next. - bool Next(llvm::StringRef S) { + bool Next(StringRef S) { P = C; PEnd = C + S.size(); if (PEnd > End) @@ -189,7 +198,7 @@ public: // Return true if string literal is found. // When true, P marks begin-position of S in content. - bool Search(llvm::StringRef S) { + bool Search(StringRef S) { P = std::search(C, End, S.begin(), S.end()); PEnd = P + S.size(); return P != End; @@ -278,7 +287,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // next token: {{ if (!PH.Next("{{")) { - PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } @@ -287,7 +296,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // search for token: }} if (!PH.Search("}}")) { - PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } @@ -296,11 +305,11 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // build directive text; convert \n to newlines std::string Text; - llvm::StringRef NewlineStr = "\\n"; - llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); + StringRef NewlineStr = "\\n"; + StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; - while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { + while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); @@ -314,7 +323,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, if (D->isValid(Error)) DL->push_back(D); else { - PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), + PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } @@ -323,14 +332,12 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, /// FindExpectedDiags - Lex the main source file to find all of the // expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { - // Create a raw lexer to pull all the comments out of the main file. We don't - // want to look in #include'd headers for expected-error strings. - SourceManager &SM = PP.getSourceManager(); - FileID FID = SM.getMainFileID(); - if (SM.getMainFileID().isInvalid()) +static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { + // Create a raw lexer to pull all the comments out of FID. + if (FID.isInvalid()) return; + SourceManager& SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); @@ -357,7 +364,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { /// happened. Print the map out in a nice format and return "true". If the map /// is empty and we're not going to print things, then return "false". /// -static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, +static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, const_diag_iterator diag_begin, const_diag_iterator diag_end, const char *Kind, bool Expected) { @@ -378,7 +385,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, return std::distance(diag_begin, diag_end); } -static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, +static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, DirectiveList &DL, const char *Kind, bool Expected) { if (DL.empty()) @@ -403,7 +410,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, /// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// -static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, +static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, @@ -446,7 +453,7 @@ static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, /// were actually reported. It emits any discrepencies. Return "true" if there /// were problems. Return "false" otherwise. /// -static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, +static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, ExpectedData &ED) { // We want to capture the delta between what was expected and what was @@ -471,21 +478,34 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, return NumProblems; } -void VerifyDiagnosticsClient::CheckDiagnostics() { +void VerifyDiagnosticConsumer::CheckDiagnostics() { ExpectedData ED; // Ensure any diagnostics go to the primary client. - DiagnosticClient *CurClient = Diags.takeClient(); - Diags.setClient(PrimaryClient.get()); + bool OwnsCurClient = Diags.ownsClient(); + DiagnosticConsumer *CurClient = Diags.takeClient(); + Diags.setClient(PrimaryClient, false); // If we have a preprocessor, scan the source for expected diagnostic // markers. If not then any diagnostics are unexpected. if (CurrentPreprocessor) { - FindExpectedDiags(*CurrentPreprocessor, ED); + SourceManager &SM = CurrentPreprocessor->getSourceManager(); + // Extract expected-error strings from main file. + FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); + // Only check for expectations in other diagnostic locations + // if they are not the main file (via ID or FileEntry) - the main + // file has already been looked at, and its expectations must not + // be added twice. + if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() + && (!SM.getFileEntryForID(FirstErrorFID) + || (SM.getFileEntryForID(FirstErrorFID) != + SM.getFileEntryForID(SM.getMainFileID())))) { + FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); + FirstErrorFID = FileID(); + } // Check that the expected diagnostics occurred. - NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), - *Buffer, ED); + NumErrors += CheckResults(Diags, SM, *Buffer, ED); } else { NumErrors += (PrintProblem(Diags, 0, Buffer->err_begin(), Buffer->err_end(), @@ -499,12 +519,20 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { } Diags.takeClient(); - Diags.setClient(CurClient); + Diags.setClient(CurClient, OwnsCurClient); // Reset the buffer, we have processed all the diagnostics in it. Buffer.reset(new TextDiagnosticBuffer()); } +DiagnosticConsumer * +VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { + if (!Diags.getClient()) + Diags.setClient(PrimaryClient->clone(Diags)); + + return new VerifyDiagnosticConsumer(Diags); +} + Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, const std::string &Text, unsigned Count) { if (RegexKind) diff --git a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp index f12b484..8fbcd4b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp @@ -31,12 +31,12 @@ #include <algorithm> using namespace clang; -void clang::ProcessWarningOptions(Diagnostic &Diags, +void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); Diags.setShowOverloads( - static_cast<Diagnostic::OverloadsShown>(Opts.ShowOverloads)); + static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads)); // Handle -ferror-limit if (Opts.ErrorLimit) @@ -48,14 +48,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, // extension diagnostics onto WARNING or ERROR unless the user has futz'd // around with them explicitly. if (Opts.PedanticErrors) - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error); else if (Opts.Pedantic) - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn); else - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore); for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { - llvm::StringRef Opt = Opts.Warnings[i]; + StringRef Opt = Opts.Warnings[i]; // Check to see if this warning starts with "no-", if so, this is a negative // form of the option. @@ -75,11 +75,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, Diags.setSuppressSystemWarnings(!isPositive); continue; } + + // -Weverything is a special case as well. It implicitly enables all + // warnings, including ones not explicitly in a warning group. + if (Opt == "everything") { + Diags.setEnableAllWarnings(true); + continue; + } // -Werror/-Wno-error is a special case, not controlled by the option table. // It also has the "specifier" form of -Werror=foo and -Werror-foo. if (Opt.startswith("error")) { - llvm::StringRef Specifier; + StringRef Specifier; if (Opt.size() > 5) { // Specifier must be present. if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { Diags.Report(diag::warn_unknown_warning_specifier) @@ -94,14 +101,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, continue; } - // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning. - Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR; - Opt = Specifier; + // Set the warning as error flag for this specifier. + if (Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive)) { + Diags.Report(isPositive ? diag::warn_unknown_warning_option : + diag::warn_unknown_negative_warning_option) + << ("-W" + Opt.str()); + } + continue; } // -Wfatal-errors is yet another special case. if (Opt.startswith("fatal-errors")) { - llvm::StringRef Specifier; + StringRef Specifier; if (Opt.size() != 12) { if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { Diags.Report(diag::warn_unknown_warning_specifier) @@ -116,15 +127,19 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, continue; } - // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo - // maps it to Error. - Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; - Opt = Specifier; + // Set the error as fatal flag for this specifier. + if (Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive)) { + Diags.Report(isPositive ? diag::warn_unknown_warning_option : + diag::warn_unknown_negative_warning_option) + << ("-W" + Opt.str()); + } + continue; } - if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) + if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) { Diags.Report(isPositive ? diag::warn_unknown_warning_option : diag::warn_unknown_negative_warning_option) << ("-W" + Opt.str()); + } } } diff --git a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index f2db3ae..c9af3cc 100644 --- a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -39,7 +39,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case ASTDumpXML: return new ASTDumpXMLAction(); case ASTPrint: return new ASTPrintAction(); case ASTView: return new ASTViewAction(); - case CreateModule: return 0; case DumpRawTokens: return new DumpRawTokensAction(); case DumpTokens: return new DumpTokensAction(); case EmitAssembly: return new EmitAssemblyAction(); @@ -50,7 +49,8 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); case EmitObj: return new EmitObjAction(); case FixIt: return new FixItAction(); - case GeneratePCH: return new GeneratePCHAction(); + case GenerateModule: return new GeneratePCHAction(true); + case GeneratePCH: return new GeneratePCHAction(false); case GeneratePTH: return new GeneratePTHAction(); case InitOnly: return new InitOnlyAction(); case ParseSyntaxOnly: return new SyntaxOnlyAction(); @@ -100,7 +100,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { Act = new arcmt::ModifyAction(Act); break; case FrontendOptions::ARCMT_Migrate: - Act = new arcmt::MigrateAction(Act, CI.getFrontendOpts().ARCMTMigrateDir); + Act = new arcmt::MigrateAction(Act, + CI.getFrontendOpts().ARCMTMigrateDir, + CI.getFrontendOpts().ARCMTMigrateReportOut, + CI.getFrontendOpts().ARCMTMigrateEmitARCErrors); break; } @@ -122,12 +125,6 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { return 0; } - // Honor -analyzer-checker-help. - if (Clang->getAnalyzerOpts().ShowCheckerHelp) { - ento::printCheckerHelp(llvm::outs()); - return 0; - } - // Honor -version. // // FIXME: Use a better -version message? @@ -136,9 +133,20 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { return 0; } + // Load any requested plugins. + for (unsigned i = 0, + e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { + const std::string &Path = Clang->getFrontendOpts().Plugins[i]; + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) + Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << Error; + } + // Honor -mllvm. // // FIXME: Remove this, one day. + // This should happen AFTER plugins have been loaded! if (!Clang->getFrontendOpts().LLVMArgs.empty()) { unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); const char **Args = new const char*[NumArgs + 2]; @@ -149,14 +157,11 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args)); } - // Load any requested plugins. - for (unsigned i = 0, - e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { - const std::string &Path = Clang->getFrontendOpts().Plugins[i]; - std::string Error; - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) - Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) - << Path << Error; + // Honor -analyzer-checker-help. + // This should happen AFTER plugins have been loaded! + if (Clang->getAnalyzerOpts().ShowCheckerHelp) { + ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins); + return 0; } // If there were errors in processing arguments, don't do anything else. diff --git a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h index 2eb2f85..0a0d2e4 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h @@ -341,7 +341,7 @@ _mm256_dp_ps(__m256 a, __m256 b, const int c) (__builtin_shufflevector((__v8sf)(a), (__v8sf)(b), \ (mask) & 0x3, ((mask) & 0xc) >> 2, \ (((mask) & 0x30) >> 4) + 8, (((mask) & 0xc0) >> 6) + 8, \ - (mask) & 0x3 + 4, (((mask) & 0xc) >> 2) + 4, \ + ((mask) & 0x3) + 4, (((mask) & 0xc) >> 2) + 4, \ (((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12)) #define _mm256_shuffle_pd(a, b, mask) \ diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h index ee12d3c..903cfde 100644 --- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h @@ -321,6 +321,12 @@ _mm_comigt_sd(__m128d a, __m128d b) } static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_mm_comige_sd(__m128d a, __m128d b) +{ + return __builtin_ia32_comisdge(a, b); +} + +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_comineq_sd(__m128d a, __m128d b) { return __builtin_ia32_comisdneq(a, b); @@ -351,6 +357,12 @@ _mm_ucomigt_sd(__m128d a, __m128d b) } static __inline__ int __attribute__((__always_inline__, __nodebug__)) +_mm_ucomige_sd(__m128d a, __m128d b) +{ + return __builtin_ia32_ucomisdge(a, b); +} + +static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_ucomineq_sd(__m128d a, __m128d b) { return __builtin_ia32_ucomisdneq(a, b); @@ -452,7 +464,11 @@ _mm_load_pd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_load1_pd(double const *dp) { - return (__m128d){ dp[0], dp[0] }; + struct __mm_load1_pd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + double u = ((struct __mm_load1_pd_struct*)dp)->u; + return (__m128d){ u, u }; } #define _mm_load_pd1(dp) _mm_load1_pd(dp) @@ -460,7 +476,8 @@ _mm_load1_pd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadr_pd(double const *dp) { - return (__m128d){ dp[1], dp[0] }; + __m128d u = *(__m128d*)dp; + return __builtin_shufflevector(u, u, 1, 0); } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) @@ -475,19 +492,31 @@ _mm_loadu_pd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_load_sd(double const *dp) { - return (__m128d){ *dp, 0.0 }; + struct __mm_load_sd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + double u = ((struct __mm_load_sd_struct*)dp)->u; + return (__m128d){ u, 0 }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadh_pd(__m128d a, double const *dp) { - return (__m128d){ a[0], *dp }; + struct __mm_loadh_pd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + double u = ((struct __mm_loadh_pd_struct*)dp)->u; + return (__m128d){ a[0], u }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pd(__m128d a, double const *dp) { - return (__m128d){ *dp, a[1] }; + struct __mm_loadl_pd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + double u = ((struct __mm_loadl_pd_struct*)dp)->u; + return (__m128d){ u, a[1] }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) @@ -529,14 +558,20 @@ _mm_move_sd(__m128d a, __m128d b) static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_sd(double *dp, __m128d a) { - dp[0] = a[0]; + struct __mm_store_sd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_store_sd_struct*)dp)->u = a[0]; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store1_pd(double *dp, __m128d a) { - dp[0] = a[0]; - dp[1] = a[0]; + struct __mm_store1_pd_struct { + double u[2]; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_store1_pd_struct*)dp)->u[0] = a[0]; + ((struct __mm_store1_pd_struct*)dp)->u[1] = a[0]; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) @@ -554,20 +589,26 @@ _mm_storeu_pd(double *dp, __m128d a) static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storer_pd(double *dp, __m128d a) { - dp[0] = a[1]; - dp[1] = a[0]; + a = __builtin_shufflevector(a, a, 1, 0); + *(__m128d *)dp = a; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storeh_pd(double *dp, __m128d a) { - dp[0] = a[1]; + struct __mm_storeh_pd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_storeh_pd_struct*)dp)->u = a[1]; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_storel_pd(double *dp, __m128d a) { - dp[0] = a[0]; + struct __mm_storeh_pd_struct { + double u; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_storeh_pd_struct*)dp)->u = a[0]; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) @@ -1023,7 +1064,10 @@ _mm_loadu_si128(__m128i const *p) static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_loadl_epi64(__m128i const *p) { - return (__m128i) { *(long long*)p, 0}; + struct __mm_loadl_epi64_struct { + long long u; + } __attribute__((__packed__, __may_alias__)); + return (__m128i) { ((struct __mm_loadl_epi64_struct*)p)->u, 0}; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Headers/float.h b/contrib/llvm/tools/clang/lib/Headers/float.h index 6eede0b..b7cb73a 100644 --- a/contrib/llvm/tools/clang/lib/Headers/float.h +++ b/contrib/llvm/tools/clang/lib/Headers/float.h @@ -24,7 +24,7 @@ #ifndef __FLOAT_H #define __FLOAT_H -/* If we're on MinGW, fall baack to the system's float.h, which might have +/* If we're on MinGW, fall back to the system's float.h, which might have * additional definitions provided for Windows. * For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx */ diff --git a/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h b/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h index ec92362..5fa1761 100644 --- a/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h +++ b/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h @@ -53,7 +53,9 @@ _mm_malloc(size_t size, size_t align) align = sizeof(void *); void *mallocedMemory; -#ifdef _WIN32 +#if defined(__MINGW32__) + mallocedMemory = __mingw_aligned_malloc(size, align); +#elif defined(_WIN32) mallocedMemory = _aligned_malloc(size, align); #else if (posix_memalign(&mallocedMemory, align, size)) diff --git a/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h index 7ca386c..5f9b097 100644 --- a/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h @@ -84,11 +84,7 @@ _mm_hsub_pd(__m128d a, __m128d b) return __builtin_ia32_hsubpd(a, b); } -static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_loaddup_pd(double const *dp) -{ - return (__m128d){ *dp, *dp }; -} +#define _mm_loaddup_pd(dp) _mm_load1_pd(dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_movedup_pd(__m128d a) diff --git a/contrib/llvm/tools/clang/lib/Headers/stdalign.h b/contrib/llvm/tools/clang/lib/Headers/stdalign.h new file mode 100644 index 0000000..e7fbfa0 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/stdalign.h @@ -0,0 +1,30 @@ +/*===---- stdalign.h - Standard header for alignment ------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __STDALIGN_H +#define __STDALIGN_H + +#define alignas _Alignas +#define __alignas_is_defined 1 + +#endif /* __STDALIGN_H */ diff --git a/contrib/llvm/tools/clang/lib/Headers/tgmath.h b/contrib/llvm/tools/clang/lib/Headers/tgmath.h index e1a0023..1b0b9d2 100644 --- a/contrib/llvm/tools/clang/lib/Headers/tgmath.h +++ b/contrib/llvm/tools/clang/lib/Headers/tgmath.h @@ -1049,19 +1049,18 @@ static long double static float _TG_ATTRS - __tg_nexttoward(float __x, float __y) {return nexttowardf(__x, __y);} + __tg_nexttoward(float __x, long double __y) {return nexttowardf(__x, __y);} static double _TG_ATTRS - __tg_nexttoward(double __x, double __y) {return nexttoward(__x, __y);} + __tg_nexttoward(double __x, long double __y) {return nexttoward(__x, __y);} static long double _TG_ATTRS __tg_nexttoward(long double __x, long double __y) {return nexttowardl(__x, __y);} #undef nexttoward -#define nexttoward(__x, __y) __tg_nexttoward(__tg_promote2((__x), (__y))(__x), \ - __tg_promote2((__x), (__y))(__y)) +#define nexttoward(__x, __y) __tg_nexttoward(__tg_promote1((__x))(__x), (__y)) // remainder diff --git a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h index 50f275d..a0bc0bb 100644 --- a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h @@ -501,31 +501,45 @@ _mm_cvtss_f32(__m128 a) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadh_pi(__m128 a, const __m64 *p) { - __m128 b; - b[0] = *(float*)p; - b[1] = *((float*)p+1); - return __builtin_shufflevector(a, b, 0, 1, 4, 5); + typedef float __mm_loadh_pi_v2f32 __attribute__((__vector_size__(8))); + struct __mm_loadh_pi_struct { + __mm_loadh_pi_v2f32 u; + } __attribute__((__packed__, __may_alias__)); + __mm_loadh_pi_v2f32 b = ((struct __mm_loadh_pi_struct*)p)->u; + __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1); + return __builtin_shufflevector(a, bb, 0, 1, 4, 5); } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pi(__m128 a, const __m64 *p) { - __m128 b; - b[0] = *(float*)p; - b[1] = *((float*)p+1); - return __builtin_shufflevector(a, b, 4, 5, 2, 3); + typedef float __mm_loadl_pi_v2f32 __attribute__((__vector_size__(8))); + struct __mm_loadl_pi_struct { + __mm_loadl_pi_v2f32 u; + } __attribute__((__packed__, __may_alias__)); + __mm_loadl_pi_v2f32 b = ((struct __mm_loadl_pi_struct*)p)->u; + __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1); + return __builtin_shufflevector(a, bb, 4, 5, 2, 3); } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_load_ss(const float *p) { - return (__m128){ *p, 0, 0, 0 }; + struct __mm_load_ss_struct { + float u; + } __attribute__((__packed__, __may_alias__)); + float u = ((struct __mm_load_ss_struct*)p)->u; + return (__m128){ u, 0, 0, 0 }; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_load1_ps(const float *p) { - return (__m128){ *p, *p, *p, *p }; + struct __mm_load1_ps_struct { + float u; + } __attribute__((__packed__, __may_alias__)); + float u = ((struct __mm_load1_ps_struct*)p)->u; + return (__m128){ u, u, u, u }; } #define _mm_load_ps1(p) _mm_load1_ps(p) @@ -541,7 +555,7 @@ _mm_loadu_ps(const float *p) { struct __loadu_ps { __m128 v; - } __attribute__((packed, may_alias)); + } __attribute__((__packed__, __may_alias__)); return ((struct __loadu_ps*)p)->v; } @@ -604,7 +618,10 @@ _mm_storel_pi(__m64 *p, __m128 a) static __inline__ void __attribute__((__always_inline__)) _mm_store_ss(float *p, __m128 a) { - *p = a[0]; + struct __mm_store_ss_struct { + float u; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_store_ss_struct*)p)->u = a[0]; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp b/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp index bd3b5ee..66b393e 100644 --- a/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp +++ b/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp @@ -41,7 +41,7 @@ Decl *ASTLocation::getReferencedDecl() { return 0; switch (getKind()) { - default: assert(0 && "Invalid Kind"); + default: llvm_unreachable("Invalid Kind"); case N_Type: return 0; case N_Decl: @@ -60,8 +60,7 @@ SourceRange ASTLocation::getSourceRange() const { return SourceRange(); switch (getKind()) { - default: assert(0 && "Invalid Kind"); - return SourceRange(); + default: llvm_unreachable("Invalid Kind"); case N_Decl: return D->getSourceRange(); case N_Stmt: @@ -75,7 +74,7 @@ SourceRange ASTLocation::getSourceRange() const { return SourceRange(); } -void ASTLocation::print(llvm::raw_ostream &OS) const { +void ASTLocation::print(raw_ostream &OS) const { if (isInvalid()) { OS << "<< Invalid ASTLocation >>\n"; return; @@ -87,7 +86,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { case N_Decl: OS << "[Decl: " << AsDecl()->getDeclKindName() << " "; if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl())) - OS << ND; + OS << *ND; break; case N_Stmt: @@ -97,7 +96,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { case N_NamedRef: OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " "; - OS << AsNamedRef().ND; + OS << *AsNamedRef().ND; break; case N_Type: { diff --git a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp index 94790b8..741e781 100644 --- a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp +++ b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp @@ -110,7 +110,7 @@ Decl *CallGraph::getDecl(CallGraphNode *Node) { return Node->getDecl(*Ctx); } -void CallGraph::print(llvm::raw_ostream &os) { +void CallGraph::print(raw_ostream &os) { for (iterator I = begin(), E = end(); I != E; ++I) { if (I->second->hasCallee()) { os << "function: " << I->first.getPrintableName() diff --git a/contrib/llvm/tools/clang/lib/Index/Entity.cpp b/contrib/llvm/tools/clang/lib/Index/Entity.cpp index afac05c..fbab6d8 100644 --- a/contrib/llvm/tools/clang/lib/Index/Entity.cpp +++ b/contrib/llvm/tools/clang/lib/Index/Entity.cpp @@ -47,7 +47,7 @@ public: unsigned IdNS, bool isObjCInstanceMethod); // Get an Entity associated with the name in the global namespace. - Entity getGlobalEntity(llvm::StringRef Name); + Entity getGlobalEntity(StringRef Name); Entity VisitNamedDecl(NamedDecl *D); Entity VisitVarDecl(VarDecl *D); @@ -77,7 +77,7 @@ Entity EntityGetter::getEntity(Entity Parent, DeclarationName Name, return Entity(New); } -Entity EntityGetter::getGlobalEntity(llvm::StringRef Name) { +Entity EntityGetter::getGlobalEntity(StringRef Name) { IdentifierInfo *II = &ProgImpl.getIdents().get(Name); DeclarationName GlobName(II); unsigned IdNS = Decl::IDNS_Ordinary; @@ -209,7 +209,7 @@ Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) { } /// \brief Get an Entity associated with a global name. -Entity EntityImpl::get(llvm::StringRef Name, Program &Prog, +Entity EntityImpl::get(StringRef Name, Program &Prog, ProgramImpl &ProgImpl) { return EntityGetter(Prog, ProgImpl).getGlobalEntity(Name); } @@ -259,7 +259,7 @@ Entity Entity::get(Decl *D, Program &Prog) { return EntityImpl::get(D, Prog, ProgImpl); } -Entity Entity::get(llvm::StringRef Name, Program &Prog) { +Entity Entity::get(StringRef Name, Program &Prog) { ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl); return EntityImpl::get(Name, Prog, ProgImpl); } diff --git a/contrib/llvm/tools/clang/lib/Index/EntityImpl.h b/contrib/llvm/tools/clang/lib/Index/EntityImpl.h index da52ccf..6d6a0c6 100644 --- a/contrib/llvm/tools/clang/lib/Index/EntityImpl.h +++ b/contrib/llvm/tools/clang/lib/Index/EntityImpl.h @@ -47,7 +47,7 @@ public: /// \brief Get an Entity associated with the given Decl. /// \returns Null if an Entity cannot refer to this Decl. static Entity get(Decl *D, Program &Prog, ProgramImpl &ProgImpl); - static Entity get(llvm::StringRef Name, Program &Prog, ProgramImpl &ProgImpl); + static Entity get(StringRef Name, Program &Prog, ProgramImpl &ProgImpl); std::string getPrintableName(); diff --git a/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp b/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp index 3467918..2fe6f95 100644 --- a/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp +++ b/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp @@ -25,7 +25,7 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const { Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val)); - llvm::SmallVector<IdentifierInfo *, 8> Ids; + SmallVector<IdentifierInfo *, 8> Ids; for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); i != e; ++i) { IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); @@ -52,7 +52,7 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl); - llvm::SmallVector<IdentifierInfo *, 8> Ids; + SmallVector<IdentifierInfo *, 8> Ids; for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); i != e; ++i) { IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp index e102a6d..0cb564c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp @@ -57,7 +57,7 @@ struct HMapHeader { /// HashHMapKey - This is the 'well known' hash function required by the file /// format, used to look up keys in the hash table. The hash table uses simple /// linear probing based on this function. -static inline unsigned HashHMapKey(llvm::StringRef Str) { +static inline unsigned HashHMapKey(StringRef Str) { unsigned Result = 0; const char *S = Str.begin(), *End = Str.end(); @@ -200,7 +200,7 @@ void HeaderMap::dump() const { /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. const FileEntry *HeaderMap::LookupFile( - llvm::StringRef Filename, FileManager &FM) const { + StringRef Filename, FileManager &FM) const { const HMapHeader &Hdr = getHeader(); unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp index 86ab956..931145a 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Capacity.h" #include <cstdio> using namespace clang; @@ -97,6 +98,60 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { return 0; } +const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName, + std::string *ModuleFileName, + std::string *UmbrellaHeader) { + // If we don't have a module cache path, we can't do anything. + if (ModuleCachePath.empty()) { + if (ModuleFileName) + ModuleFileName->clear(); + return 0; + } + + // Try to find the module path. + llvm::SmallString<256> FileName(ModuleCachePath); + llvm::sys::path::append(FileName, ModuleName + ".pcm"); + if (ModuleFileName) + *ModuleFileName = FileName.str(); + + if (const FileEntry *ModuleFile + = getFileMgr().getFile(FileName, /*OpenFile=*/false, + /*CacheFailure=*/false)) + return ModuleFile; + + // We didn't find the module. If we're not supposed to look for an + // umbrella header, this is the end of the road. + if (!UmbrellaHeader) + return 0; + + // Look in each of the framework directories for an umbrella header with + // the same name as the module. + // FIXME: We need a way for non-frameworks to provide umbrella headers. + llvm::SmallString<128> UmbrellaHeaderName; + UmbrellaHeaderName = ModuleName; + UmbrellaHeaderName += '/'; + UmbrellaHeaderName += ModuleName; + UmbrellaHeaderName += ".h"; + for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) { + // Skip non-framework include paths + if (!SearchDirs[Idx].isFramework()) + continue; + + // Look for the umbrella header in this directory. + if (const FileEntry *HeaderFile + = SearchDirs[Idx].LookupFile(UmbrellaHeaderName, *this, 0, 0, + StringRef(), 0)) { + *UmbrellaHeader = HeaderFile->getName(); + return 0; + } + } + + // We did not find an umbrella header. Clear out the UmbrellaHeader pointee + // so our caller knows that we failed. + UmbrellaHeader->clear(); + return 0; +} + //===----------------------------------------------------------------------===// // File lookup within a DirectoryLookup scope //===----------------------------------------------------------------------===// @@ -116,17 +171,19 @@ const char *DirectoryLookup::getName() const { /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. const FileEntry *DirectoryLookup::LookupFile( - llvm::StringRef Filename, + StringRef Filename, HeaderSearch &HS, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) const { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef BuildingModule, + StringRef *SuggestedModule) const { llvm::SmallString<1024> TmpDir; if (isNormalDir()) { // Concatenate the requested file onto the directory. TmpDir = getDir()->getName(); llvm::sys::path::append(TmpDir, Filename); if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(getDir()->getName()); + StringRef SearchPathRef(getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -138,14 +195,15 @@ const FileEntry *DirectoryLookup::LookupFile( } if (isFramework()) - return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath); + return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath, + BuildingModule, SuggestedModule); assert(isHeaderMap() && "Unknown directory lookup"); const FileEntry * const Result = getHeaderMap()->LookupFile( Filename, HS.getFileMgr()); if (Result) { if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(getName()); + StringRef SearchPathRef(getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -161,15 +219,18 @@ const FileEntry *DirectoryLookup::LookupFile( /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. const FileEntry *DirectoryLookup::DoFrameworkLookup( - llvm::StringRef Filename, + StringRef Filename, HeaderSearch &HS, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) const { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef BuildingModule, + StringRef *SuggestedModule) const +{ FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); - if (SlashPos == llvm::StringRef::npos) return 0; + if (SlashPos == StringRef::npos) return 0; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answer are yes/no and unknown. @@ -226,9 +287,16 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } + /// Determine whether this is the module we're building or not. + bool AutomaticImport = SuggestedModule && + (BuildingModule != StringRef(Filename.begin(), SlashPos)) && + !Filename.substr(SlashPos + 1).startswith(".."); + FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), - /*openFile=*/true)) { + /*openFile=*/!AutomaticImport)) { + if (AutomaticImport) + *SuggestedModule = StringRef(Filename.begin(), SlashPos); return FE; } @@ -240,7 +308,11 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); - return FileMgr.getFile(FrameworkName.str(), /*openFile=*/true); + const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), + /*openFile=*/!AutomaticImport); + if (FE && AutomaticImport) + *SuggestedModule = StringRef(Filename.begin(), SlashPos); + return FE; } @@ -255,13 +327,18 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( /// non-null, indicates where the #including file is, in case a relative search /// is needed. const FileEntry *HeaderSearch::LookupFile( - llvm::StringRef Filename, + StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, const FileEntry *CurFileEnt, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef *SuggestedModule) +{ + if (SuggestedModule) + *SuggestedModule = StringRef(); + // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = 0; @@ -279,7 +356,7 @@ const FileEntry *HeaderSearch::LookupFile( return FileMgr.getFile(Filename, /*openFile=*/true); } - // Step #0, unless disabled, check to see if the file is in the #includer's + // Unless disabled, check to see if the file is in the #includer's // directory. This has to be based on CurFileEnt, not CurDir, because // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h". @@ -301,7 +378,7 @@ const FileEntry *HeaderSearch::LookupFile( unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; getFileInfo(FE).DirInfo = DirInfo; if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(CurFileEnt->getDir()->getName()); + StringRef SearchPathRef(CurFileEnt->getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -346,19 +423,56 @@ const FileEntry *HeaderSearch::LookupFile( // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { const FileEntry *FE = - SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath); + SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, + BuildingModule, SuggestedModule); if (!FE) continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. - getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic(); - + HeaderFileInfo &HFI = getFileInfo(FE); + HFI.DirInfo = CurDir->getDirCharacteristic(); + + // If this file is found in a header map and uses the framework style of + // includes, then this header is part of a framework we're building. + if (CurDir->isIndexHeaderMap()) { + size_t SlashPos = Filename.find('/'); + if (SlashPos != StringRef::npos) { + HFI.IndexHeaderMapHeader = 1; + HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), + SlashPos)); + } + } + // Remember this location for the next lookup we do. CacheLookup.second = i; return FE; } + // If we are including a file with a quoted include "foo.h" from inside + // a header in a framework that is currently being built, and we couldn't + // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where + // "Foo" is the name of the framework in which the including header was found. + if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) { + HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt); + if (IncludingHFI.IndexHeaderMapHeader) { + llvm::SmallString<128> ScratchFilename; + ScratchFilename += IncludingHFI.Framework; + ScratchFilename += '/'; + ScratchFilename += Filename; + + const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true, + FromDir, CurDir, CurFileEnt, + SearchPath, RelativePath, + SuggestedModule); + std::pair<unsigned, unsigned> &CacheLookup + = LookupFileCache.GetOrCreateValue(Filename).getValue(); + CacheLookup.second + = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second; + return Result; + } + } + // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.second = SearchDirs.size(); return 0; @@ -370,15 +484,15 @@ const FileEntry *HeaderSearch::LookupFile( /// is a subframework within Carbon.framework. If so, return the FileEntry /// for the designated file, otherwise return null. const FileEntry *HeaderSearch:: -LookupSubframeworkHeader(llvm::StringRef Filename, +LookupSubframeworkHeader(StringRef Filename, const FileEntry *ContextFileEnt, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. size_t SlashPos = Filename.find('/'); - if (SlashPos == llvm::StringRef::npos) return 0; + if (SlashPos == StringRef::npos) return 0; // Look up the base framework name of the ContextFileEnt. const char *ContextName = ContextFileEnt->getName(); @@ -466,7 +580,31 @@ LookupSubframeworkHeader(llvm::StringRef Filename, // File Info Management. //===----------------------------------------------------------------------===// +/// \brief Merge the header file info provided by \p OtherHFI into the current +/// header file info (\p HFI) +static void mergeHeaderFileInfo(HeaderFileInfo &HFI, + const HeaderFileInfo &OtherHFI) { + HFI.isImport |= OtherHFI.isImport; + HFI.isPragmaOnce |= OtherHFI.isPragmaOnce; + HFI.NumIncludes += OtherHFI.NumIncludes; + + if (!HFI.ControllingMacro && !HFI.ControllingMacroID) { + HFI.ControllingMacro = OtherHFI.ControllingMacro; + HFI.ControllingMacroID = OtherHFI.ControllingMacroID; + } + + if (OtherHFI.External) { + HFI.DirInfo = OtherHFI.DirInfo; + HFI.External = OtherHFI.External; + HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader; + } + if (HFI.Framework.empty()) + HFI.Framework = OtherHFI.Framework; + + HFI.Resolved = true; +} + /// getFileInfo - Return the HeaderFileInfo structure for the specified /// FileEntry. HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { @@ -474,10 +612,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { FileInfo.resize(FE->getUID()+1); HeaderFileInfo &HFI = FileInfo[FE->getUID()]; - if (ExternalSource && !HFI.Resolved) { - HFI = ExternalSource->GetHeaderFileInfo(FE); - HFI.Resolved = true; - } + if (ExternalSource && !HFI.Resolved) + mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE)); return HFI; } @@ -488,10 +624,8 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) { // Resolve header file info from the external source, if needed. HeaderFileInfo &HFI = FileInfo[File->getUID()]; - if (ExternalSource && !HFI.Resolved) { - HFI = ExternalSource->GetHeaderFileInfo(File); - HFI.Resolved = true; - } + if (ExternalSource && !HFI.Resolved) + mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File)); return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID; } @@ -542,4 +676,14 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ return true; } +size_t HeaderSearch::getTotalMemory() const { + return SearchDirs.capacity() + + llvm::capacity_in_bytes(FileInfo) + + llvm::capacity_in_bytes(HeaderMaps) + + LookupFileCache.getAllocator().getTotalMemory() + + FrameworkMap.getAllocator().getTotalMemory(); +} +StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) { + return FrameworkNames.GetOrCreateValue(Framework).getKey(); +} diff --git a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp index a28b8f6..a98d889 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp @@ -32,7 +32,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" -#include <cctype> +#include <cstring> using namespace clang; static void InitCharacterInfo(); @@ -76,7 +76,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, // skip the UTF-8 BOM if it's present. if (BufferStart == BufferPtr) { // Determine the size of the BOM. - llvm::StringRef Buf(BufferStart, BufferEnd - BufferStart); + StringRef Buf(BufferStart, BufferEnd - BufferStart); size_t BOMLength = llvm::StringSwitch<size_t>(Buf) .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM .Default(0); @@ -86,7 +86,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, } Is_PragmaLexer = false; - IsInConflictMarker = false; + CurrentConflictMarkerState = CMK_None; // Start of the file is a start of line. IsAtStartOfLine = true; @@ -187,9 +187,9 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc, // Set the SourceLocation with the remapping information. This ensures that // GetMappedTokenLoc will remap the tokens as they are lexed. - L->FileLoc = SM.createInstantiationLoc(SM.getLocForStartOfFile(SpellingFID), - ExpansionLocStart, - ExpansionLocEnd, TokLen); + L->FileLoc = SM.createExpansionLoc(SM.getLocForStartOfFile(SpellingFID), + ExpansionLocStart, + ExpansionLocEnd, TokLen); // Ensure that the lexer thinks it is inside a directive, so that end \n will // return an EOD token. @@ -217,7 +217,7 @@ std::string Lexer::Stringify(const std::string &Str, bool Charify) { /// Stringify - Convert the specified string into a C string by escaping '\' /// and " characters. This does not add surrounding ""'s to the string. -void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) { +void Lexer::Stringify(SmallVectorImpl<char> &Str) { for (unsigned i = 0, e = Str.size(); i != e; ++i) { if (Str[i] == '\\' || Str[i] == '"') { Str.insert(Str.begin()+i, '\\'); @@ -235,8 +235,8 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) { /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. -llvm::StringRef Lexer::getSpelling(SourceLocation loc, - llvm::SmallVectorImpl<char> &buffer, +StringRef Lexer::getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, const SourceManager &SM, const LangOptions &options, bool *invalid) { @@ -245,10 +245,10 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc, // Try to the load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) { if (invalid) *invalid = true; - return llvm::StringRef(); + return StringRef(); } const char *tokenBegin = file.data() + locInfo.second; @@ -263,7 +263,7 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc, // Common case: no need for cleaning. if (!token.needsCleaning()) - return llvm::StringRef(tokenBegin, length); + return StringRef(tokenBegin, length); // Hard case, we need to relex the characters into the string. buffer.clear(); @@ -275,7 +275,7 @@ llvm::StringRef Lexer::getSpelling(SourceLocation loc, ti += charSize; } - return llvm::StringRef(buffer.data(), buffer.size()); + return StringRef(buffer.data(), buffer.size()); } /// getSpelling() - Return the 'spelling' of this token. The spelling of a @@ -394,10 +394,10 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, // If this comes from a macro expansion, we really do want the macro name, not // the token this macro expanded to. - Loc = SM.getInstantiationLoc(Loc); + Loc = SM.getExpansionLoc(Loc); std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); bool Invalid = false; - llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return 0; @@ -415,15 +415,16 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, return TheTok.getLength(); } -SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, - const SourceManager &SM, - const LangOptions &LangOpts) { +static SourceLocation getBeginningOfFileToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + assert(Loc.isFileID()); std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); if (LocInfo.first.isInvalid()) return Loc; bool Invalid = false; - llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) return Loc; @@ -448,7 +449,7 @@ SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, } // Create a lexer starting at the beginning of this token. - SourceLocation LexerStartLoc = Loc.getFileLocWithOffset(-LocInfo.second); + SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second); Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end()); TheLexer.SetCommentRetentionState(true); @@ -474,6 +475,25 @@ SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, return Loc; } +SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + if (Loc.isFileID()) + return getBeginningOfFileToken(Loc, SM, LangOpts); + + if (!SM.isMacroArgExpansion(Loc)) + return Loc; + + SourceLocation FileLoc = SM.getSpellingLoc(Loc); + SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts); + std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc); + std::pair<FileID, unsigned> BeginFileLocInfo= SM.getDecomposedLoc(BeginFileLoc); + assert(FileLocInfo.first == BeginFileLocInfo.first && + FileLocInfo.second >= BeginFileLocInfo.second); + return Loc.getLocWithOffset(SM.getDecomposedLoc(BeginFileLoc).second - + SM.getDecomposedLoc(FileLoc).second); +} + namespace { enum PreambleDirectiveKind { PDK_Skipped, @@ -484,21 +504,36 @@ namespace { } std::pair<unsigned, bool> -Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) { +Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, + const LangOptions &Features, unsigned MaxLines) { // Create a lexer starting at the beginning of the file. Note that we use a // "fake" file source location at offset 1 so that the lexer will track our // position within the file. const unsigned StartOffset = 1; SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset); - LangOptions LangOpts; - Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(), + Lexer TheLexer(StartLoc, Features, Buffer->getBufferStart(), Buffer->getBufferStart(), Buffer->getBufferEnd()); bool InPreprocessorDirective = false; Token TheTok; Token IfStartTok; unsigned IfCount = 0; - unsigned Line = 0; + + unsigned MaxLineOffset = 0; + if (MaxLines) { + const char *CurPtr = Buffer->getBufferStart(); + unsigned CurLine = 0; + while (CurPtr != Buffer->getBufferEnd()) { + char ch = *CurPtr++; + if (ch == '\n') { + ++CurLine; + if (CurLine == MaxLines) + break; + } + } + if (CurPtr != Buffer->getBufferEnd()) + MaxLineOffset = CurPtr - Buffer->getBufferStart(); + } do { TheLexer.LexFromRawLexer(TheTok); @@ -522,11 +557,11 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) { // Keep track of the # of lines in the preamble. if (TheTok.isAtStartOfLine()) { - ++Line; + unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset; // If we were asked to limit the number of lines in the preamble, // and we're about to exceed that limit, we're done. - if (MaxLines && Line >= MaxLines) + if (MaxLineOffset && TokOffset >= MaxLineOffset) break; } @@ -539,12 +574,12 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) { Token HashTok = TheTok; InPreprocessorDirective = true; - // Figure out which direective this is. Since we're lexing raw tokens, + // Figure out which directive this is. Since we're lexing raw tokens, // we don't have an identifier table available. Instead, just look at // the raw identifier to recognize and categorize preprocessor directives. TheLexer.LexFromRawLexer(TheTok); if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) { - llvm::StringRef Keyword(TheTok.getRawIdentifierData(), + StringRef Keyword(TheTok.getRawIdentifierData(), TheTok.getLength()); PreambleDirectiveKind PDK = llvm::StringSwitch<PreambleDirectiveKind>(Keyword) @@ -638,7 +673,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, // chars, this method is extremely fast. while (Lexer::isObviouslySimpleCharacter(*TokPtr)) { if (CharNo == 0) - return TokStart.getFileLocWithOffset(PhysOffset); + return TokStart.getLocWithOffset(PhysOffset); ++TokPtr, --CharNo, ++PhysOffset; } @@ -658,7 +693,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart, if (!Lexer::isObviouslySimpleCharacter(*TokPtr)) PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; - return TokStart.getFileLocWithOffset(PhysOffset); + return TokStart.getLocWithOffset(PhysOffset); } /// \brief Computes the source location just past the end of the @@ -687,7 +722,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, return SourceLocation(); // Points inside the macro expansion. // Continue and find the location just after the macro expansion. - Loc = SM.getInstantiationRange(Loc).second; + Loc = SM.getExpansionRange(Loc).second; } unsigned Len = Lexer::MeasureTokenLength(Loc, SM, Features); @@ -696,14 +731,14 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, else return Loc; - return Loc.getFileLocWithOffset(Len); + return Loc.getLocWithOffset(Len); } /// \brief Returns true if the given MacroID location points at the first /// token of the macro expansion. bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc, - const SourceManager &SM, - const LangOptions &LangOpts) { + const SourceManager &SM, + const LangOptions &LangOpts) { assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc); @@ -713,8 +748,7 @@ bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc, return false; // Does not point at the start of token. SourceLocation expansionLoc = - SM.getSLocEntry(infoLoc.first) - .getInstantiation().getInstantiationLocStart(); + SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart(); if (expansionLoc.isFileID()) return true; // No other macro expansions, this is the first. @@ -734,17 +768,15 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc, return false; FileID FID = SM.getFileID(loc); - SourceLocation afterLoc = loc.getFileLocWithOffset(tokLen+1); - if (!SM.isBeforeInSourceLocationOffset(afterLoc, SM.getNextOffset())) - return true; // We got past the last FileID, this points to the last token. + SourceLocation afterLoc = loc.getLocWithOffset(tokLen+1); + if (SM.isInFileID(afterLoc, FID)) + return false; // Still in the same FileID, does not point to the last token. // FIXME: If the token comes from the macro token paste operator ('##') // or the stringify operator ('#') this function will always return false; - if (FID == SM.getFileID(afterLoc)) - return false; // Still in the same FileID, does not point to the last token. - + SourceLocation expansionLoc = - SM.getSLocEntry(FID).getInstantiation().getInstantiationLocEnd(); + SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd(); if (expansionLoc.isFileID()) return true; // No other macro expansions. @@ -761,7 +793,8 @@ enum { CHAR_LETTER = 0x04, // a-z,A-Z CHAR_NUMBER = 0x08, // 0-9 CHAR_UNDER = 0x10, // _ - CHAR_PERIOD = 0x20 // . + CHAR_PERIOD = 0x20, // . + CHAR_RAWDEL = 0x40 // {}[]#<>%:;?*+-/^&|~!=,"' }; // Statically initialize CharInfo table based on ASCII character set @@ -786,20 +819,20 @@ static const unsigned char CharInfo[256] = 0 , 0 , 0 , 0 , //32 SP 33 ! 34 " 35 # //36 $ 37 % 38 & 39 ' - CHAR_HORZ_WS, 0 , 0 , 0 , - 0 , 0 , 0 , 0 , + CHAR_HORZ_WS, CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , //40 ( 41 ) 42 * 43 + //44 , 45 - 46 . 47 / - 0 , 0 , 0 , 0 , - 0 , 0 , CHAR_PERIOD , 0 , + 0 , 0 , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL , //48 0 49 1 50 2 51 3 //52 4 53 5 54 6 55 7 CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , //56 8 57 9 58 : 59 ; //60 < 61 = 62 > 63 ? - CHAR_NUMBER , CHAR_NUMBER , 0 , 0 , - 0 , 0 , 0 , 0 , + CHAR_NUMBER , CHAR_NUMBER , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , //64 @ 65 A 66 B 67 C //68 D 69 E 70 F 71 G 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , @@ -814,8 +847,8 @@ static const unsigned char CharInfo[256] = CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , //88 X 89 Y 90 Z 91 [ //92 \ 93 ] 94 ^ 95 _ - CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , 0 , - 0 , 0 , 0 , CHAR_UNDER , + CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL , + 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER , //96 ` 97 a 98 b 99 c //100 d 101 e 102 f 103 g 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , @@ -829,9 +862,9 @@ static const unsigned char CharInfo[256] = CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , //120 x 121 y 122 z 123 { -//124 | 125 } 126 ~ 127 DEL - CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , 0 , - 0 , 0 , 0 , 0 +//124 | 125 } 126 ~ 127 DEL + CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0 }; static void InitCharacterInfo() { @@ -869,6 +902,12 @@ static inline bool isHorizontalWhitespace(unsigned char c) { return (CharInfo[c] & CHAR_HORZ_WS) ? true : false; } +/// isVerticalWhitespace - Return true if this character is vertical +/// whitespace: '\n', '\r'. Note that this returns false for '\0'. +static inline bool isVerticalWhitespace(unsigned char c) { + return (CharInfo[c] & CHAR_VERT_WS) ? true : false; +} + /// isWhitespace - Return true if this character is horizontal or vertical /// whitespace: ' ', '\t', '\f', '\v', '\n', '\r'. Note that this returns false /// for '\0'. @@ -883,6 +922,14 @@ static inline bool isNumberBody(unsigned char c) { true : false; } +/// isRawStringDelimBody - Return true if this is the body character of a +/// raw string delimiter. +static inline bool isRawStringDelimBody(unsigned char c) { + return (CharInfo[c] & + (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL)) ? + true : false; +} + //===----------------------------------------------------------------------===// // Diagnostics forwarding code. @@ -907,14 +954,14 @@ static SourceLocation GetMappedTokenLoc(Preprocessor &PP, // Create a new SLoc which is expanded from Expansion(FileLoc) but whose // characters come from spelling(FileLoc)+Offset. SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc); - SpellingLoc = SpellingLoc.getFileLocWithOffset(CharNo); + SpellingLoc = SpellingLoc.getLocWithOffset(CharNo); // Figure out the expansion loc range, which is the range covered by the // original _Pragma(...) sequence. std::pair<SourceLocation,SourceLocation> II = - SM.getImmediateInstantiationRange(FileLoc); + SM.getImmediateExpansionRange(FileLoc); - return SM.createInstantiationLoc(SpellingLoc, II.first, II.second, TokLen); + return SM.createExpansionLoc(SpellingLoc, II.first, II.second, TokLen); } /// getSourceLocation - Return a source location identifier for the specified @@ -928,7 +975,7 @@ SourceLocation Lexer::getSourceLocation(const char *Loc, // the file id from FileLoc with the offset specified. unsigned CharNo = Loc-BufferStart; if (FileLoc.isFileID()) - return FileLoc.getFileLocWithOffset(CharNo); + return FileLoc.getLocWithOffset(CharNo); // Otherwise, this is the _Pragma lexer case, which pretends that all of the // tokens are lexed from where the _Pragma was defined. @@ -978,7 +1025,7 @@ static char DecodeTrigraphChar(const char *CP, Lexer *L) { } if (!L->isLexingRawMode()) - L->Diag(CP-2, diag::trigraph_converted) << llvm::StringRef(&Res, 1); + L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1); return Res; } @@ -1028,6 +1075,59 @@ const char *Lexer::SkipEscapedNewLines(const char *P) { } } +/// \brief Checks that the given token is the first token that occurs after the +/// given location (this excludes comments and whitespace). Returns the location +/// immediately after the specified token. If the token is not found or the +/// location is inside a macro, the returned source location will be invalid. +SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc, + tok::TokenKind TKind, + const SourceManager &SM, + const LangOptions &LangOpts, + bool SkipTrailingWhitespaceAndNewLine) { + if (Loc.isMacroID()) { + if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts)) + return SourceLocation(); + Loc = SM.getExpansionRange(Loc).second; + } + Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); + + // Break down the source location. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + + // Try to load the file buffer. + bool InvalidTemp = false; + llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp); + if (InvalidTemp) + return SourceLocation(); + + const char *TokenBegin = File.data() + LocInfo.second; + + // Lex from the start of the given location. + Lexer lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(), + TokenBegin, File.end()); + // Find the token. + Token Tok; + lexer.LexFromRawLexer(Tok); + if (Tok.isNot(TKind)) + return SourceLocation(); + SourceLocation TokenLoc = Tok.getLocation(); + + // Calculate how much whitespace needs to be skipped if any. + unsigned NumWhitespaceChars = 0; + if (SkipTrailingWhitespaceAndNewLine) { + const char *TokenEnd = SM.getCharacterData(TokenLoc) + + Tok.getLength(); + unsigned char C = *TokenEnd; + while (isHorizontalWhitespace(C)) { + C = *(++TokenEnd); + NumWhitespaceChars++; + } + if (isVerticalWhitespace(C)) + NumWhitespaceChars++; + } + + return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars); +} /// getCharAndSizeSlow - Peek a single 'character' from the specified buffer, /// get its size, and return it. This is tricky in several cases: @@ -1191,6 +1291,7 @@ FinishIdentifier: // preprocessor, which may macro expand it or something. if (II->isHandleIdentifierCase()) PP->HandleIdentifier(Result); + return; } @@ -1252,13 +1353,12 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) { // If we are in Microsoft mode, don't continue if the constant is hex. // For example, MSVC will accept the following as 3 tokens: 0x1234567e+1 - if (!Features.Microsoft || !isHexaLiteral(BufferPtr, Features)) + if (!Features.MicrosoftExt || !isHexaLiteral(BufferPtr, Features)) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); } // If we have a hex FP constant, continue. - if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') && - !Features.CPlusPlus0x) + if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); // Update the location of token as well as BufferPtr. @@ -1268,10 +1368,17 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { } /// LexStringLiteral - Lex the remainder of a string literal, after having lexed -/// either " or L". -void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) { +/// either " or L" or u8" or u" or U". +void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, + tok::TokenKind Kind) { const char *NulCharacter = 0; // Does this string contain the \0 character? + if (!isLexingRawMode() && + (Kind == tok::utf8_string_literal || + Kind == tok::utf16_string_literal || + Kind == tok::utf32_string_literal)) + Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal); + char C = getAndAdvanceChar(CurPtr, Result); while (C != '"') { // Skip escaped characters. Escaped newlines will already be processed by @@ -1281,16 +1388,21 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) { if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) - PP->CodeCompleteNaturalLanguage(); - else if (!isLexingRawMode() && !Features.AsmPreprocessor) + if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::warn_unterminated_string); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; } - if (C == 0) + if (C == 0) { + if (isCodeCompletionPoint(CurPtr-1)) { + PP->CodeCompleteNaturalLanguage(); + FormTokenWithChars(Result, CurPtr-1, tok::unknown); + return cutOffLexing(); + } + NulCharacter = CurPtr-1; + } C = getAndAdvanceChar(CurPtr, Result); } @@ -1300,8 +1412,82 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) { // Update the location of the token as well as the BufferPtr instance var. const char *TokStart = BufferPtr; - FormTokenWithChars(Result, CurPtr, - Wide ? tok::wide_string_literal : tok::string_literal); + FormTokenWithChars(Result, CurPtr, Kind); + Result.setLiteralData(TokStart); +} + +/// LexRawStringLiteral - Lex the remainder of a raw string literal, after +/// having lexed R", LR", u8R", uR", or UR". +void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr, + tok::TokenKind Kind) { + // This function doesn't use getAndAdvanceChar because C++0x [lex.pptoken]p3: + // Between the initial and final double quote characters of the raw string, + // any transformations performed in phases 1 and 2 (trigraphs, + // universal-character-names, and line splicing) are reverted. + + if (!isLexingRawMode()) + Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal); + + unsigned PrefixLen = 0; + + while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen])) + ++PrefixLen; + + // If the last character was not a '(', then we didn't lex a valid delimiter. + if (CurPtr[PrefixLen] != '(') { + if (!isLexingRawMode()) { + const char *PrefixEnd = &CurPtr[PrefixLen]; + if (PrefixLen == 16) { + Diag(PrefixEnd, diag::err_raw_delim_too_long); + } else { + Diag(PrefixEnd, diag::err_invalid_char_raw_delim) + << StringRef(PrefixEnd, 1); + } + } + + // Search for the next '"' in hopes of salvaging the lexer. Unfortunately, + // it's possible the '"' was intended to be part of the raw string, but + // there's not much we can do about that. + while (1) { + char C = *CurPtr++; + + if (C == '"') + break; + if (C == 0 && CurPtr-1 == BufferEnd) { + --CurPtr; + break; + } + } + + FormTokenWithChars(Result, CurPtr, tok::unknown); + return; + } + + // Save prefix and move CurPtr past it + const char *Prefix = CurPtr; + CurPtr += PrefixLen + 1; // skip over prefix and '(' + + while (1) { + char C = *CurPtr++; + + if (C == ')') { + // Check for prefix match and closing quote. + if (strncmp(CurPtr, Prefix, PrefixLen) == 0 && CurPtr[PrefixLen] == '"') { + CurPtr += PrefixLen + 1; // skip over prefix and '"' + break; + } + } else if (C == 0 && CurPtr-1 == BufferEnd) { // End of file. + if (!isLexingRawMode()) + Diag(BufferPtr, diag::err_unterminated_raw_string) + << StringRef(Prefix, PrefixLen); + FormTokenWithChars(Result, CurPtr-1, tok::unknown); + return; + } + } + + // Update the location of token as well as BufferPtr. + const char *TokStart = BufferPtr; + FormTokenWithChars(Result, CurPtr, Kind); Result.setLiteralData(TokStart); } @@ -1317,7 +1503,8 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) { // Skip the escaped character. C = getAndAdvanceChar(CurPtr, Result); } else if (C == '\n' || C == '\r' || // Newline. - (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. + (C == 0 && (CurPtr-1 == BufferEnd || // End of file. + isCodeCompletionPoint(CurPtr-1)))) { // If the filename is unterminated, then it must just be a lone < // character. Return this as such. FormTokenWithChars(Result, AfterLessPos, tok::less); @@ -1340,10 +1527,15 @@ void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) { /// LexCharConstant - Lex the remainder of a character constant, after having -/// lexed either ' or L'. -void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { +/// lexed either ' or L' or u' or U'. +void Lexer::LexCharConstant(Token &Result, const char *CurPtr, + tok::TokenKind Kind) { const char *NulCharacter = 0; // Does this character contain the \0 character? + if (!isLexingRawMode() && + (Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant)) + Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal); + char C = getAndAdvanceChar(CurPtr, Result); if (C == '\'') { if (!isLexingRawMode() && !Features.AsmPreprocessor) @@ -1360,13 +1552,17 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { C = getAndAdvanceChar(CurPtr, Result); } else if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) - PP->CodeCompleteNaturalLanguage(); - else if (!isLexingRawMode() && !Features.AsmPreprocessor) + if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::warn_unterminated_char); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; } else if (C == 0) { + if (isCodeCompletionPoint(CurPtr-1)) { + PP->CodeCompleteNaturalLanguage(); + FormTokenWithChars(Result, CurPtr-1, tok::unknown); + return cutOffLexing(); + } + NulCharacter = CurPtr-1; } C = getAndAdvanceChar(CurPtr, Result); @@ -1378,7 +1574,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { // Update the location of token as well as BufferPtr. const char *TokStart = BufferPtr; - FormTokenWithChars(Result, CurPtr, tok::char_constant); + FormTokenWithChars(Result, CurPtr, Kind); Result.setLiteralData(TokStart); } @@ -1451,20 +1647,28 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { char C; do { C = *CurPtr; - // FIXME: Speedup BCPL comment lexing. Just scan for a \n or \r character. - // If we find a \n character, scan backwards, checking to see if it's an - // escaped newline, like we do for block comments. - // Skip over characters in the fast loop. while (C != 0 && // Potentially EOF. - C != '\\' && // Potentially escaped newline. - C != '?' && // Potentially trigraph. C != '\n' && C != '\r') // Newline or DOS-style newline. C = *++CurPtr; - // If this is a newline, we're done. - if (C == '\n' || C == '\r') - break; // Found the newline? Break out! + const char *NextLine = CurPtr; + if (C != 0) { + // We found a newline, see if it's escaped. + const char *EscapePtr = CurPtr-1; + while (isHorizontalWhitespace(*EscapePtr)) // Skip whitespace. + --EscapePtr; + + if (*EscapePtr == '\\') // Escaped newline. + CurPtr = EscapePtr; + else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' && + EscapePtr[-2] == '?') // Trigraph-escaped newline. + CurPtr = EscapePtr-2; + else + break; // This is a newline, we're done. + + C = *CurPtr; + } // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to // properly decode the character. Read it in raw mode to avoid emitting @@ -1476,6 +1680,13 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { C = getAndAdvanceChar(CurPtr, Result); LexingRawMode = OldRawMode; + // If we only read only one character, then no special handling is needed. + // We're done and can skip forward to the newline. + if (C != 0 && CurPtr == OldPtr+1) { + CurPtr = NextLine; + break; + } + // If the char that we finally got was a \n, then we must have had something // like \<newline><newline>. We don't want to have consumed the second // newline, we want CurPtr, to end up pointing to it down below. @@ -1492,9 +1703,9 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { if (OldPtr[0] == '\n' || OldPtr[0] == '\r') { // Okay, we found a // comment that ends in a newline, if the next // line is also a // comment, but has spaces, don't emit a diagnostic. - if (isspace(C)) { + if (isWhitespace(C)) { const char *ForwardPtr = CurPtr; - while (isspace(*ForwardPtr)) // Skip whitespace. + while (isWhitespace(*ForwardPtr)) // Skip whitespace. ++ForwardPtr; if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/') break; @@ -1507,12 +1718,16 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } if (CurPtr == BufferEnd+1) { - if (PP && PP->isCodeCompletionFile(FileLoc)) - PP->CodeCompleteNaturalLanguage(); - --CurPtr; break; } + + if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) { + PP->CodeCompleteNaturalLanguage(); + cutOffLexing(); + return false; + } + } while (C != '\n' && C != '\r'); // Found but did not consume the newline. Notify comment handlers about the @@ -1573,7 +1788,7 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { Result.setKind(tok::comment); PP->CreateString(&Spelling[0], Spelling.size(), Result, - Result.getLocation()); + Result.getLocation(), Result.getLocation()); return true; } @@ -1667,8 +1882,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { unsigned char C = getCharAndSize(CurPtr, CharSize); CurPtr += CharSize; if (C == 0 && CurPtr == BufferEnd+1) { - if (!isLexingRawMode() && - !PP->isCodeCompletionFile(FileLoc)) + if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); --CurPtr; @@ -1691,7 +1905,10 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { while (1) { // Skip over all non-interesting characters until we find end of buffer or a // (probably ending) '/' character. - if (CurPtr + 24 < BufferEnd) { + if (CurPtr + 24 < BufferEnd && + // If there is a code-completion point avoid the fast scan because it + // doesn't check for '\0'. + !(PP && PP->getCodeCompletionFileLoc() == FileLoc)) { // While not aligned to a 16-byte boundary. while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0) C = *CurPtr++; @@ -1751,9 +1968,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { Diag(CurPtr-1, diag::warn_nested_block_comment); } } else if (C == 0 && CurPtr == BufferEnd+1) { - if (PP && PP->isCodeCompletionFile(FileLoc)) - PP->CodeCompleteNaturalLanguage(); - else if (!isLexingRawMode()) + if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); // Note: the user probably forgot a */. We could continue immediately // after the /*, but this would involve lexing a lot of what really is the @@ -1769,7 +1984,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { BufferPtr = CurPtr; return false; + } else if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) { + PP->CodeCompleteNaturalLanguage(); + cutOffLexing(); + return false; } + C = *CurPtr++; } @@ -1826,6 +2046,12 @@ std::string Lexer::ReadToEndOfLine() { case 0: // Null. // Found end of file? if (CurPtr-1 != BufferEnd) { + if (isCodeCompletionPoint(CurPtr-1)) { + PP->CodeCompleteNaturalLanguage(); + cutOffLexing(); + return Result; + } + // Nope, normal character, continue. Result += Char; break; @@ -1840,8 +2066,8 @@ std::string Lexer::ReadToEndOfLine() { // Next, lex the character, which should handle the EOD transition. Lex(Tmp); if (Tmp.is(tok::code_completion)) { - if (PP && PP->getCodeCompletionHandler()) - PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage(); + if (PP) + PP->CodeCompleteNaturalLanguage(); Lex(Tmp); } assert(Tmp.is(tok::eod) && "Unexpected token!"); @@ -1857,22 +2083,6 @@ std::string Lexer::ReadToEndOfLine() { /// This returns true if Result contains a token, false if PP.Lex should be /// called again. bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { - // Check if we are performing code completion. - if (PP && PP->isCodeCompletionFile(FileLoc)) { - // We're at the end of the file, but we've been asked to consider the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); - - // Only do the eof -> code_completion translation once. - PP->SetCodeCompletionPoint(0, 0, 0); - - // Silence any diagnostics that occur once we hit the code-completion point. - PP->getDiagnostics().setSuppressAllDiagnostics(true); - return true; - } - // If we hit the end of the file while parsing a preprocessor directive, // end the preprocessor directive first. The next token returned will // then be the end of file. @@ -1900,7 +2110,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // If we are in a #if directive, emit an error. while (!ConditionalStack.empty()) { - if (!PP->isCodeCompletionFile(FileLoc)) + if (PP->getCodeCompletionFileLoc() != FileLoc) PP->Diag(ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); ConditionalStack.pop_back(); @@ -1951,15 +2161,18 @@ unsigned Lexer::isNextPPTokenLParen() { } /// FindConflictEnd - Find the end of a version control conflict marker. -static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) { - llvm::StringRef RestOfBuffer(CurPtr+7, BufferEnd-CurPtr-7); - size_t Pos = RestOfBuffer.find(">>>>>>>"); - while (Pos != llvm::StringRef::npos) { +static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd, + ConflictMarkerKind CMK) { + const char *Terminator = CMK == CMK_Perforce ? "<<<<\n" : ">>>>>>>"; + size_t TermLen = CMK == CMK_Perforce ? 5 : 7; + StringRef RestOfBuffer(CurPtr+TermLen, BufferEnd-CurPtr-TermLen); + size_t Pos = RestOfBuffer.find(Terminator); + while (Pos != StringRef::npos) { // Must occur at start of line. if (RestOfBuffer[Pos-1] != '\r' && RestOfBuffer[Pos-1] != '\n') { - RestOfBuffer = RestOfBuffer.substr(Pos+7); - Pos = RestOfBuffer.find(">>>>>>>"); + RestOfBuffer = RestOfBuffer.substr(Pos+TermLen); + Pos = RestOfBuffer.find(Terminator); continue; } return RestOfBuffer.data()+Pos; @@ -1977,23 +2190,25 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { CurPtr[-1] != '\n' && CurPtr[-1] != '\r') return false; - // Check to see if we have <<<<<<<. - if (BufferEnd-CurPtr < 8 || - llvm::StringRef(CurPtr, 7) != "<<<<<<<") + // Check to see if we have <<<<<<< or >>>>. + if ((BufferEnd-CurPtr < 8 || StringRef(CurPtr, 7) != "<<<<<<<") && + (BufferEnd-CurPtr < 6 || StringRef(CurPtr, 5) != ">>>> ")) return false; // If we have a situation where we don't care about conflict markers, ignore // it. - if (IsInConflictMarker || isLexingRawMode()) + if (CurrentConflictMarkerState || isLexingRawMode()) return false; - // Check to see if there is a >>>>>>> somewhere in the buffer at the start of - // a line to terminate this conflict marker. - if (FindConflictEnd(CurPtr, BufferEnd)) { + ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce; + + // Check to see if there is an ending marker somewhere in the buffer at the + // start of a line to terminate this conflict marker. + if (FindConflictEnd(CurPtr, BufferEnd, Kind)) { // We found a match. We are really in a conflict marker. // Diagnose this, and ignore to the end of line. Diag(CurPtr, diag::err_conflict_marker); - IsInConflictMarker = true; + CurrentConflictMarkerState = Kind; // Skip ahead to the end of line. We know this exists because the // end-of-conflict marker starts with \r or \n. @@ -2010,10 +2225,10 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { } -/// HandleEndOfConflictMarker - If this is a '=======' or '|||||||' or '>>>>>>>' -/// marker, then it is the end of a conflict marker. Handle it by ignoring up -/// until the end of the line. This returns true if it is a conflict marker and -/// false if not. +/// HandleEndOfConflictMarker - If this is a '====' or '||||' or '>>>>', or if +/// it is '<<<<' and the conflict marker started with a '>>>>' marker, then it +/// is the end of a conflict marker. Handle it by ignoring up until the end of +/// the line. This returns true if it is a conflict marker and false if not. bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { // Only a conflict marker if it starts at the beginning of a line. if (CurPtr != BufferStart && @@ -2022,18 +2237,19 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { // If we have a situation where we don't care about conflict markers, ignore // it. - if (!IsInConflictMarker || isLexingRawMode()) + if (!CurrentConflictMarkerState || isLexingRawMode()) return false; - // Check to see if we have the marker (7 characters in a row). - for (unsigned i = 1; i != 7; ++i) + // Check to see if we have the marker (4 characters in a row). + for (unsigned i = 1; i != 4; ++i) if (CurPtr[i] != CurPtr[0]) return false; // If we do have it, search for the end of the conflict marker. This could // fail if it got skipped with a '#if 0' or something. Note that CurPtr might // be the end of conflict marker. - if (const char *End = FindConflictEnd(CurPtr, BufferEnd)) { + if (const char *End = FindConflictEnd(CurPtr, BufferEnd, + CurrentConflictMarkerState)) { CurPtr = End; // Skip ahead to the end of line. @@ -2043,13 +2259,22 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { BufferPtr = CurPtr; // No longer in the conflict marker. - IsInConflictMarker = false; + CurrentConflictMarkerState = CMK_None; return true; } return false; } +bool Lexer::isCodeCompletionPoint(const char *CurPtr) const { + if (PP && PP->isCodeCompletionEnabled()) { + SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart); + return Loc == PP->getCodeCompletionLoc(); + } + + return false; +} + /// LexTokenInternal - This implements a simple C family lexer. It is an /// extremely performance critical piece of code. This assumes that the buffer @@ -2102,6 +2327,14 @@ LexNextToken: return PPCache->Lex(Result); } + // Check if we are performing code completion. + if (isCodeCompletionPoint(CurPtr-1)) { + // Return the code-completion token. + Result.startToken(); + FormTokenWithChars(Result, CurPtr, tok::code_completion); + return; + } + if (!isLexingRawMode()) Diag(CurPtr-1, diag::null_in_file); Result.setFlag(Token::LeadingSpace); @@ -2112,7 +2345,7 @@ LexNextToken: case 26: // DOS & CP/M EOF: "^Z". // If we're in Microsoft extensions mode, treat this as end of file. - if (Features.Microsoft) { + if (Features.MicrosoftExt) { // Read the PP instance variable into an automatic variable, because // LexEndOfFile will often delete 'this'. Preprocessor *PPCache = PP; @@ -2186,6 +2419,102 @@ LexNextToken: MIOpt.ReadToken(); return LexNumericConstant(Result, CurPtr); + case 'u': // Identifier (uber) or C++0x UTF-8 or UTF-16 string literal + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + + if (Features.CPlusPlus0x) { + Char = getCharAndSize(CurPtr, SizeTmp); + + // UTF-16 string literal + if (Char == '"') + return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), + tok::utf16_string_literal); + + // UTF-16 character constant + if (Char == '\'') + return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), + tok::utf16_char_constant); + + // UTF-16 raw string literal + if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') + return LexRawStringLiteral(Result, + ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result), + tok::utf16_string_literal); + + if (Char == '8') { + char Char2 = getCharAndSize(CurPtr + SizeTmp, SizeTmp2); + + // UTF-8 string literal + if (Char2 == '"') + return LexStringLiteral(Result, + ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result), + tok::utf8_string_literal); + + if (Char2 == 'R') { + unsigned SizeTmp3; + char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); + // UTF-8 raw string literal + if (Char3 == '"') { + return LexRawStringLiteral(Result, + ConsumeChar(ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result), + SizeTmp3, Result), + tok::utf8_string_literal); + } + } + } + } + + // treat u like the start of an identifier. + return LexIdentifier(Result, CurPtr); + + case 'U': // Identifier (Uber) or C++0x UTF-32 string literal + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + + if (Features.CPlusPlus0x) { + Char = getCharAndSize(CurPtr, SizeTmp); + + // UTF-32 string literal + if (Char == '"') + return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), + tok::utf32_string_literal); + + // UTF-32 character constant + if (Char == '\'') + return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), + tok::utf32_char_constant); + + // UTF-32 raw string literal + if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') + return LexRawStringLiteral(Result, + ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result), + tok::utf32_string_literal); + } + + // treat U like the start of an identifier. + return LexIdentifier(Result, CurPtr); + + case 'R': // Identifier or C++0x raw string literal + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + + if (Features.CPlusPlus0x) { + Char = getCharAndSize(CurPtr, SizeTmp); + + if (Char == '"') + return LexRawStringLiteral(Result, + ConsumeChar(CurPtr, SizeTmp, Result), + tok::string_literal); + } + + // treat R like the start of an identifier. + return LexIdentifier(Result, CurPtr); + case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); @@ -2194,21 +2523,30 @@ LexNextToken: // Wide string literal. if (Char == '"') return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), - true); + tok::wide_string_literal); + + // Wide raw string literal. + if (Features.CPlusPlus0x && Char == 'R' && + getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"') + return LexRawStringLiteral(Result, + ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result), + tok::wide_string_literal); // Wide character constant. if (Char == '\'') - return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); + return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result), + tok::wide_char_constant); // FALL THROUGH, treating L like the start of an identifier. // C99 6.4.2: Identifiers. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'O': case 'P': case 'Q': /*'R'*/case 'S': case 'T': /*'U'*/ case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': - case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': /*'u'*/ case 'v': case 'w': case 'x': case 'y': case 'z': case '_': // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -2231,13 +2569,13 @@ LexNextToken: case '\'': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexCharConstant(Result, CurPtr); + return LexCharConstant(Result, CurPtr, tok::char_constant); // C99 6.4.5: String Literals. case '"': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexStringLiteral(Result, CurPtr, false); + return LexStringLiteral(Result, CurPtr, tok::string_literal); // C99 6.4.6: Punctuators. case '?': @@ -2396,7 +2734,7 @@ LexNextToken: Kind = tok::hashhash; // '%:%:' -> '##' CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); - } else if (Char == '@' && Features.Microsoft) { // %:@ -> #@ -> Charize + } else if (Char == '@' && Features.MicrosoftExt) {// %:@ -> #@ -> Charize CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); if (!isLexingRawMode()) Diag(BufferPtr, diag::charize_microsoft_ext); @@ -2447,6 +2785,10 @@ LexNextToken: // If this is actually a '<<<<<<<' version control conflict marker, // recognize it as such and recover nicely. goto LexNextToken; + } else if (After == '<' && HandleEndOfConflictMarker(CurPtr-1)) { + // If this is '<<<<' and we're in a Perforce-style conflict marker, + // ignore it. + goto LexNextToken; } else if (Features.CUDA && After == '<') { Kind = tok::lesslessless; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), @@ -2470,6 +2812,8 @@ LexNextToken: char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); if (After != ':' && After != '>') { Kind = tok::less; + if (!isLexingRawMode()) + Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon); break; } } @@ -2494,6 +2838,10 @@ LexNextToken: CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), SizeTmp2, Result); Kind = tok::greatergreaterequal; + } else if (After == '>' && IsStartOfConflictMarker(CurPtr-1)) { + // If this is actually a '>>>>' conflict marker, recognize it as such + // and recover nicely. + goto LexNextToken; } else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) { // If this is '>>>>>>>' and we're in a conflict marker, ignore it. goto LexNextToken; @@ -2552,7 +2900,7 @@ LexNextToken: case '=': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { - // If this is '=======' and we're in a conflict marker, ignore it. + // If this is '====' and we're in a conflict marker, ignore it. if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1)) goto LexNextToken; @@ -2570,7 +2918,7 @@ LexNextToken: if (Char == '#') { Kind = tok::hashhash; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '@' && Features.Microsoft) { // #@ -> Charize + } else if (Char == '@' && Features.MicrosoftExt) { // #@ -> Charize Kind = tok::hashat; if (!isLexingRawMode()) Diag(BufferPtr, diag::charize_microsoft_ext); diff --git a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp index 2c96c4d..70183fd 100644 --- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp @@ -16,8 +16,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; /// HexDigitValue - Return the value of the specified hex digit, or -1 if it's @@ -29,12 +29,31 @@ static int HexDigitValue(char C) { return -1; } +static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) { + switch (kind) { + default: llvm_unreachable("Unknown token type!"); + case tok::char_constant: + case tok::string_literal: + case tok::utf8_string_literal: + return Target.getCharWidth(); + case tok::wide_char_constant: + case tok::wide_string_literal: + return Target.getWCharWidth(); + case tok::utf16_char_constant: + case tok::utf16_string_literal: + return Target.getChar16Width(); + case tok::utf32_char_constant: + case tok::utf32_string_literal: + return Target.getChar32Width(); + } +} + /// ProcessCharEscape - Parse a standard C escape sequence, which can occur in /// either a character or a string literal. static unsigned ProcessCharEscape(const char *&ThisTokBuf, const char *ThisTokEnd, bool &HadError, - FullSourceLoc Loc, bool IsWide, - Diagnostic *Diags, const TargetInfo &Target) { + FullSourceLoc Loc, unsigned CharWidth, + DiagnosticsEngine *Diags) { // Skip the '\' char. ++ThisTokBuf; @@ -99,9 +118,6 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, } // See if any bits will be truncated when evaluated as a character. - unsigned CharWidth = - IsWide ? Target.getWCharWidth() : Target.getCharWidth(); - if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { Overflow = true; ResultChar &= ~0U >> (32-CharWidth); @@ -129,9 +145,6 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7'); // Check for overflow. Reject '\777', but not L'\777'. - unsigned CharWidth = - IsWide ? Target.getWCharWidth() : Target.getCharWidth(); - if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { if (Diags) Diags->Report(Loc, diag::warn_octal_escape_too_large); @@ -167,7 +180,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, /// return the UTF32. static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, uint32_t &UcnVal, unsigned short &UcnLen, - FullSourceLoc Loc, Diagnostic *Diags, + FullSourceLoc Loc, DiagnosticsEngine *Diags, const LangOptions &Features) { if (!Features.CPlusPlus && !Features.C99 && Diags) Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89); @@ -220,7 +233,8 @@ static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, /// we will likely rework our support for UCN's. static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, char *&ResultBuf, bool &HadError, - FullSourceLoc Loc, bool wide, Diagnostic *Diags, + FullSourceLoc Loc, unsigned CharByteWidth, + DiagnosticsEngine *Diags, const LangOptions &Features) { typedef uint32_t UTF32; UTF32 UcnVal = 0; @@ -231,19 +245,22 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, return; } - if (wide) { - (void)UcnLen; - assert((UcnLen== 4 || UcnLen== 8) && "only ucn length of 4 or 8 supported"); + assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth) && + "only character widths of 1, 2, or 4 bytes supported"); - if (!Features.ShortWChar) { - // Note: our internal rep of wide char tokens is always little-endian. - *ResultBuf++ = (UcnVal & 0x000000FF); - *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8; - *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16; - *ResultBuf++ = (UcnVal & 0xFF000000) >> 24; - return; - } + (void)UcnLen; + assert((UcnLen== 4 || UcnLen== 8) && "only ucn length of 4 or 8 supported"); + if (CharByteWidth == 4) { + // Note: our internal rep of wide char tokens is always little-endian. + *ResultBuf++ = (UcnVal & 0x000000FF); + *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8; + *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16; + *ResultBuf++ = (UcnVal & 0xFF000000) >> 24; + return; + } + + if (CharByteWidth == 2) { // Convert to UTF16. if (UcnVal < (UTF32)0xFFFF) { *ResultBuf++ = (UcnVal & 0x000000FF); @@ -262,6 +279,9 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, *ResultBuf++ = (surrogate2 & 0x0000FF00) >> 8; return; } + + assert(CharByteWidth == 1 && "UTF-8 encoding is only for 1 byte characters"); + // Now that we've parsed/checked the UCN, we convert from UTF32->UTF8. // The conversion below was inspired by: // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c @@ -371,7 +391,7 @@ NumericLiteralParser(const char *begin, const char *end, // Done. } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), - diag::err_invalid_decimal_digit) << llvm::StringRef(s, 1); + diag::err_invalid_decimal_digit) << StringRef(s, 1); hadError = true; return; } else if (*s == '.') { @@ -434,7 +454,7 @@ NumericLiteralParser(const char *begin, const char *end, continue; // Success. case 'i': case 'I': - if (PP.getLangOptions().Microsoft) { + if (PP.getLangOptions().MicrosoftExt) { if (isFPConstant || isLong || isLongLong) break; // Allow i8, i16, i32, i64, and i128. @@ -498,7 +518,7 @@ NumericLiteralParser(const char *begin, const char *end, PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), isFPConstant ? diag::err_invalid_suffix_float_constant : diag::err_invalid_suffix_integer_constant) - << llvm::StringRef(SuffixBegin, ThisTokEnd-SuffixBegin); + << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin); hadError = true; return; } @@ -528,7 +548,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } // A binary exponent can appear with or with a '.'. If dotted, the // binary exponent is required. - if ((*s == 'p' || *s == 'P') && !PP.getLangOptions().CPlusPlus0x) { + if (*s == 'p' || *s == 'P') { const char *Exponent = s; s++; saw_exponent = true; @@ -542,12 +562,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } s = first_non_digit; - // In C++0x, we cannot support hexadecmial floating literals because - // they conflict with user-defined literals, so we warn in previous - // versions of C++ by default. - if (PP.getLangOptions().CPlusPlus) - PP.Diag(TokLoc, diag::ext_hexconstant_cplusplus); - else if (!PP.getLangOptions().HexFloats) + if (!PP.getLangOptions().HexFloats) PP.Diag(TokLoc, diag::ext_hexconstant_invalid); } else if (saw_period) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), @@ -569,7 +584,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // Done. } else if (isxdigit(*s)) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), - diag::err_invalid_binary_digit) << llvm::StringRef(s, 1); + diag::err_invalid_binary_digit) << StringRef(s, 1); hadError = true; } // Other suffixes will be diagnosed by the caller. @@ -599,7 +614,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // the code is using an incorrect base. if (isxdigit(*s) && *s != 'e' && *s != 'E') { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), - diag::err_invalid_octal_digit) << llvm::StringRef(s, 1); + diag::err_invalid_octal_digit) << StringRef(s, 1); hadError = true; return; } @@ -688,7 +703,6 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { llvm::APFloat::opStatus NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { using llvm::APFloat; - using llvm::StringRef; unsigned n = std::min(SuffixBegin - ThisTokBegin, ThisTokEnd - ThisTokBegin); return Result.convertFromString(StringRef(ThisTokBegin, n), @@ -696,14 +710,51 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { } +/// character-literal: [C++0x lex.ccon] +/// ' c-char-sequence ' +/// u' c-char-sequence ' +/// U' c-char-sequence ' +/// L' c-char-sequence ' +/// c-char-sequence: +/// c-char +/// c-char-sequence c-char +/// c-char: +/// any member of the source character set except the single-quote ', +/// backslash \, or new-line character +/// escape-sequence +/// universal-character-name +/// escape-sequence: [C++0x lex.ccon] +/// simple-escape-sequence +/// octal-escape-sequence +/// hexadecimal-escape-sequence +/// simple-escape-sequence: +/// one of \' \" \? \\ \a \b \f \n \r \t \v +/// octal-escape-sequence: +/// \ octal-digit +/// \ octal-digit octal-digit +/// \ octal-digit octal-digit octal-digit +/// hexadecimal-escape-sequence: +/// \x hexadecimal-digit +/// hexadecimal-escape-sequence hexadecimal-digit +/// universal-character-name: +/// \u hex-quad +/// \U hex-quad hex-quad +/// hex-quad: +/// hex-digit hex-digit hex-digit hex-digit +/// CharLiteralParser::CharLiteralParser(const char *begin, const char *end, - SourceLocation Loc, Preprocessor &PP) { + SourceLocation Loc, Preprocessor &PP, + tok::TokenKind kind) { // At this point we know that the character matches the regex "L?'.*'". HadError = false; - // Determine if this is a wide character. - IsWide = begin[0] == 'L'; - if (IsWide) ++begin; + Kind = kind; + + // Determine if this is a wide or UTF character. + if (Kind == tok::wide_char_constant || Kind == tok::utf16_char_constant || + Kind == tok::utf32_char_constant) { + ++begin; + } // Skip over the entry quote. assert(begin[0] == '\'' && "Invalid token lexed"); @@ -730,8 +781,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, // Is this a Universal Character Name escape? if (begin[0] != '\\') // If this is a normal character, consume it. - ResultChar = *begin++; + ResultChar = (unsigned char)*begin++; else { // Otherwise, this is an escape character. + unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo()); // Check for UCN. if (begin[1] == 'u' || begin[1] == 'U') { uint32_t utf32 = 0; @@ -742,19 +794,22 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, HadError = 1; } ResultChar = utf32; + if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { + PP.Diag(Loc, diag::warn_ucn_escape_too_large); + ResultChar &= ~0U >> (32-CharWidth); + } } else { // Otherwise, this is a non-UCN escape character. Process it. ResultChar = ProcessCharEscape(begin, end, HadError, FullSourceLoc(Loc,PP.getSourceManager()), - IsWide, - &PP.getDiagnostics(), PP.getTargetInfo()); + CharWidth, &PP.getDiagnostics()); } } // If this is a multi-character constant (e.g. 'abc'), handle it. These are // implementation defined (C99 6.4.4.4p10). if (NumCharsSoFar) { - if (IsWide) { + if (!isAscii()) { // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'. LitVal = 0; } else { @@ -776,8 +831,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, if (NumCharsSoFar > 1) { // Warn about discarding the top bits for multi-char wide-character // constants (L'abcd'). - if (IsWide) - PP.Diag(Loc, diag::warn_extraneous_wide_char_constant); + if (!isAscii()) + PP.Diag(Loc, diag::warn_extraneous_char_constant); else if (NumCharsSoFar != 4) PP.Diag(Loc, diag::ext_multichar_character_literal); else @@ -789,47 +844,62 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, // Transfer the value from APInt to uint64_t Value = LitVal.getZExtValue(); - if (IsWide && PP.getLangOptions().ShortWChar && Value > 0xFFFF) - PP.Diag(Loc, diag::warn_ucn_escape_too_large); - // If this is a single narrow character, sign extend it (e.g. '\xFF' is "-1") // if 'char' is signed for this target (C99 6.4.4.4p10). Note that multiple // character constants are not sign extended in the this implementation: // '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC. - if (!IsWide && NumCharsSoFar == 1 && (Value & 128) && + if (isAscii() && NumCharsSoFar == 1 && (Value & 128) && PP.getLangOptions().CharIsSigned) Value = (signed char)Value; } -/// string-literal: [C99 6.4.5] -/// " [s-char-sequence] " -/// L" [s-char-sequence] " +/// string-literal: [C++0x lex.string] +/// encoding-prefix " [s-char-sequence] " +/// encoding-prefix R raw-string +/// encoding-prefix: +/// u8 +/// u +/// U +/// L /// s-char-sequence: /// s-char /// s-char-sequence s-char /// s-char: -/// any source character except the double quote ", -/// backslash \, or newline character -/// escape-character -/// universal-character-name -/// escape-character: [C99 6.4.4.4] -/// \ escape-code +/// any member of the source character set except the double-quote ", +/// backslash \, or new-line character +/// escape-sequence /// universal-character-name -/// escape-code: -/// character-escape-code -/// octal-escape-code -/// hex-escape-code -/// character-escape-code: one of -/// n t b r f v a -/// \ ' " ? -/// octal-escape-code: -/// octal-digit -/// octal-digit octal-digit -/// octal-digit octal-digit octal-digit -/// hex-escape-code: -/// x hex-digit -/// hex-escape-code hex-digit +/// raw-string: +/// " d-char-sequence ( r-char-sequence ) d-char-sequence " +/// r-char-sequence: +/// r-char +/// r-char-sequence r-char +/// r-char: +/// any member of the source character set, except a right parenthesis ) +/// followed by the initial d-char-sequence (which may be empty) +/// followed by a double quote ". +/// d-char-sequence: +/// d-char +/// d-char-sequence d-char +/// d-char: +/// any member of the basic source character set except: +/// space, the left parenthesis (, the right parenthesis ), +/// the backslash \, and the control characters representing horizontal +/// tab, vertical tab, form feed, and newline. +/// escape-sequence: [C++0x lex.ccon] +/// simple-escape-sequence +/// octal-escape-sequence +/// hexadecimal-escape-sequence +/// simple-escape-sequence: +/// one of \' \" \? \\ \a \b \f \n \r \t \v +/// octal-escape-sequence: +/// \ octal-digit +/// \ octal-digit octal-digit +/// \ octal-digit octal-digit octal-digit +/// hexadecimal-escape-sequence: +/// \x hexadecimal-digit +/// hexadecimal-escape-sequence hexadecimal-digit /// universal-character-name: /// \u hex-quad /// \U hex-quad hex-quad @@ -841,8 +911,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, Preprocessor &PP, bool Complain) : SM(PP.getSourceManager()), Features(PP.getLangOptions()), Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0), - MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0), - ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) { + MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown), + ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) { init(StringToks, NumStringToks); } @@ -862,7 +932,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ MaxTokenLength = StringToks[0].getLength(); assert(StringToks[0].getLength() >= 2 && "literal token is invalid!"); SizeBound = StringToks[0].getLength()-2; // -2 for "". - AnyWide = StringToks[0].is(tok::wide_string_literal); + Kind = StringToks[0].getKind(); hadError = false; @@ -883,8 +953,18 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ if (StringToks[i].getLength() > MaxTokenLength) MaxTokenLength = StringToks[i].getLength(); - // Remember if we see any wide strings. - AnyWide |= StringToks[i].is(tok::wide_string_literal); + // Remember if we see any wide or utf-8/16/32 strings. + // Also check for illegal concatenations. + if (StringToks[i].isNot(Kind) && StringToks[i].isNot(tok::string_literal)) { + if (isAscii()) { + Kind = StringToks[i].getKind(); + } else { + if (Diags) + Diags->Report(FullSourceLoc(StringToks[i].getLocation(), SM), + diag::err_unsupported_string_concat); + hadError = true; + } + } } // Include space for the null terminator. @@ -892,19 +972,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ // TODO: K&R warning: "traditional C rejects string constant concatenation" - // Get the width in bytes of wchar_t. If no wchar_t strings are used, do not - // query the target. As such, wchar_tByteWidth is only valid if AnyWide=true. - wchar_tByteWidth = ~0U; - if (AnyWide) { - wchar_tByteWidth = Target.getWCharWidth(); - assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!"); - wchar_tByteWidth /= 8; - } + // Get the width in bytes of char/wchar_t/char16_t/char32_t + CharByteWidth = getCharWidth(Kind, Target); + assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple"); + CharByteWidth /= 8; // The output buffer size needs to be large enough to hold wide characters. // This is a worst-case assumption which basically corresponds to L"" "long". - if (AnyWide) - SizeBound *= wchar_tByteWidth; + SizeBound *= CharByteWidth; // Size the temporary buffer to hold the result string data. ResultBuf.resize(SizeBound); @@ -929,78 +1004,82 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ Lexer::getSpelling(StringToks[i], ThisTokBuf, SM, Features, &StringInvalid); if (StringInvalid) { - hadError = 1; + hadError = true; continue; } const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote. - bool wide = false; // TODO: Input character set mapping support. - // Skip L marker for wide strings. - if (ThisTokBuf[0] == 'L') { - wide = true; + // Skip marker for wide or unicode strings. + if (ThisTokBuf[0] == 'L' || ThisTokBuf[0] == 'u' || ThisTokBuf[0] == 'U') { ++ThisTokBuf; + // Skip 8 of u8 marker for utf8 strings. + if (ThisTokBuf[0] == '8') + ++ThisTokBuf; } - assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?"); - ++ThisTokBuf; - - // Check if this is a pascal string - if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd && - ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') { + // Check for raw string + if (ThisTokBuf[0] == 'R') { + ThisTokBuf += 2; // skip R" - // If the \p sequence is found in the first token, we have a pascal string - // Otherwise, if we already have a pascal string, ignore the first \p - if (i == 0) { + const char *Prefix = ThisTokBuf; + while (ThisTokBuf[0] != '(') ++ThisTokBuf; - Pascal = true; - } else if (Pascal) - ThisTokBuf += 2; - } + ++ThisTokBuf; // skip '(' + + // remove same number of characters from the end + if (ThisTokEnd >= ThisTokBuf + (ThisTokBuf - Prefix)) + ThisTokEnd -= (ThisTokBuf - Prefix); + + // Copy the string over + CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)); + } else { + assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?"); + ++ThisTokBuf; // skip " + + // Check if this is a pascal string + if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd && + ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') { - while (ThisTokBuf != ThisTokEnd) { - // Is this a span of non-escape characters? - if (ThisTokBuf[0] != '\\') { - const char *InStart = ThisTokBuf; - do { + // If the \p sequence is found in the first token, we have a pascal string + // Otherwise, if we already have a pascal string, ignore the first \p + if (i == 0) { ++ThisTokBuf; - } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\'); - - // Copy the character span over. - unsigned Len = ThisTokBuf-InStart; - if (!AnyWide) { - memcpy(ResultPtr, InStart, Len); - ResultPtr += Len; - } else { - // Note: our internal rep of wide char tokens is always little-endian. - for (; Len; --Len, ++InStart) { - *ResultPtr++ = InStart[0]; - // Add zeros at the end. - for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) - *ResultPtr++ = 0; - } - } - continue; - } - // Is this a Universal Character Name escape? - if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') { - EncodeUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr, - hadError, FullSourceLoc(StringToks[i].getLocation(),SM), - wide, Diags, Features); - continue; + Pascal = true; + } else if (Pascal) + ThisTokBuf += 2; } - // Otherwise, this is a non-UCN escape character. Process it. - unsigned ResultChar = - ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, - FullSourceLoc(StringToks[i].getLocation(), SM), - AnyWide, Diags, Target); - // Note: our internal rep of wide char tokens is always little-endian. - *ResultPtr++ = ResultChar & 0xFF; + while (ThisTokBuf != ThisTokEnd) { + // Is this a span of non-escape characters? + if (ThisTokBuf[0] != '\\') { + const char *InStart = ThisTokBuf; + do { + ++ThisTokBuf; + } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\'); + + // Copy the character span over. + CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart)); + continue; + } + // Is this a Universal Character Name escape? + if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') { + EncodeUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr, + hadError, FullSourceLoc(StringToks[i].getLocation(),SM), + CharByteWidth, Diags, Features); + continue; + } + // Otherwise, this is a non-UCN escape character. Process it. + unsigned ResultChar = + ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, + FullSourceLoc(StringToks[i].getLocation(), SM), + CharByteWidth*8, Diags); + + // Note: our internal rep of wide char tokens is always little-endian. + *ResultPtr++ = ResultChar & 0xFF; - if (AnyWide) { - for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) + for (unsigned i = 1, e = CharByteWidth; i != e; ++i) *ResultPtr++ = ResultChar >> i*8; } } @@ -1008,8 +1087,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ if (Pascal) { ResultBuf[0] = ResultPtr-&ResultBuf[0]-1; - if (AnyWide) - ResultBuf[0] /= wchar_tByteWidth; + ResultBuf[0] /= CharByteWidth; // Verify that pascal strings aren't too large. if (GetStringLength() > 256) { @@ -1018,7 +1096,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ diag::err_pascal_string_too_long) << SourceRange(StringToks[0].getLocation(), StringToks[NumStringToks-1].getLocation()); - hadError = 1; + hadError = true; return; } } else if (Diags) { @@ -1036,6 +1114,25 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ } +/// copyStringFragment - This function copies from Start to End into ResultPtr. +/// Performs widening for multi-byte characters. +void StringLiteralParser::CopyStringFragment(StringRef Fragment) { + // Copy the character span over. + if (CharByteWidth == 1) { + memcpy(ResultPtr, Fragment.data(), Fragment.size()); + ResultPtr += Fragment.size(); + } else { + // Note: our internal rep of wide char tokens is always little-endian. + for (StringRef::iterator I=Fragment.begin(), E=Fragment.end(); I!=E; ++I) { + *ResultPtr++ = *I; + // Add zeros at the end. + for (unsigned i = 1, e = CharByteWidth; i != e; ++i) + *ResultPtr++ = 0; + } + } +} + + /// getOffsetOfStringByte - This function returns the offset of the /// specified byte of the string data represented by Token. This handles /// advancing over escape sequences in the string. @@ -1052,7 +1149,8 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, if (StringInvalid) return 0; - assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet"); + assert(SpellingPtr[0] != 'L' && SpellingPtr[0] != 'u' && + SpellingPtr[0] != 'U' && "Doesn't handle wide or utf strings yet"); const char *SpellingStart = SpellingPtr; @@ -1077,7 +1175,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, bool HadError = false; ProcessCharEscape(SpellingPtr, SpellingEnd, HadError, FullSourceLoc(Tok.getLocation(), SM), - false, Diags, Target); + CharByteWidth*8, Diags); assert(!HadError && "This method isn't valid on erroneous strings"); --ByteNo; } diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp index 968c15e..1846d1c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp @@ -15,13 +15,15 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LexDiagnostic.h" + +#include <algorithm> + using namespace clang; /// MacroArgs ctor function - This destroys the vector passed in. MacroArgs *MacroArgs::create(const MacroInfo *MI, - const Token *UnexpArgTokens, - unsigned NumToks, bool VarargsElided, - Preprocessor &PP) { + llvm::ArrayRef<Token> UnexpArgTokens, + bool VarargsElided, Preprocessor &PP) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); MacroArgs **ResultEnt = 0; @@ -31,12 +33,12 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, // free list. If so, reuse it. for (MacroArgs **Entry = &PP.MacroArgCache; *Entry; Entry = &(*Entry)->ArgCache) - if ((*Entry)->NumUnexpArgTokens >= NumToks && + if ((*Entry)->NumUnexpArgTokens >= UnexpArgTokens.size() && (*Entry)->NumUnexpArgTokens < ClosestMatch) { ResultEnt = Entry; // If we have an exact match, use it. - if ((*Entry)->NumUnexpArgTokens == NumToks) + if ((*Entry)->NumUnexpArgTokens == UnexpArgTokens.size()) break; // Otherwise, use the best fit. ClosestMatch = (*Entry)->NumUnexpArgTokens; @@ -45,21 +47,22 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, MacroArgs *Result; if (ResultEnt == 0) { // Allocate memory for a MacroArgs object with the lexer tokens at the end. - Result = (MacroArgs*)malloc(sizeof(MacroArgs) + NumToks*sizeof(Token)); + Result = (MacroArgs*)malloc(sizeof(MacroArgs) + + UnexpArgTokens.size() * sizeof(Token)); // Construct the MacroArgs object. - new (Result) MacroArgs(NumToks, VarargsElided); + new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided); } else { Result = *ResultEnt; // Unlink this node from the preprocessors singly linked list. *ResultEnt = Result->ArgCache; - Result->NumUnexpArgTokens = NumToks; + Result->NumUnexpArgTokens = UnexpArgTokens.size(); Result->VarargsElided = VarargsElided; } // Copy the actual unexpanded tokens to immediately after the result ptr. - if (NumToks) - memcpy(const_cast<Token*>(Result->getUnexpArgument(0)), - UnexpArgTokens, NumToks*sizeof(Token)); + if (!UnexpArgTokens.empty()) + std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(), + const_cast<Token*>(Result->getUnexpArgument(0))); return Result; } @@ -186,7 +189,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI, /// Token MacroArgs::StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify, - SourceLocation hashInstLoc) { + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd) { Token Tok; Tok.startToken(); Tok.setKind(Charify ? tok::char_constant : tok::string_literal); @@ -208,13 +212,21 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, // by 6.10.3.2p2. if (Tok.is(tok::string_literal) || // "foo" Tok.is(tok::wide_string_literal) || // L"foo" - Tok.is(tok::char_constant)) { // 'x' and L'x'. + Tok.is(tok::utf8_string_literal) || // u8"foo" + Tok.is(tok::utf16_string_literal) || // u"foo" + Tok.is(tok::utf32_string_literal) || // U"foo" + Tok.is(tok::char_constant) || // 'x' + Tok.is(tok::wide_char_constant) || // L'x'. + Tok.is(tok::utf16_char_constant) || // u'x'. + Tok.is(tok::utf32_char_constant)) { // U'x'. bool Invalid = false; std::string TokStr = PP.getSpelling(Tok, &Invalid); if (!Invalid) { std::string Str = Lexer::Stringify(TokStr); Result.append(Str.begin(), Str.end()); } + } else if (Tok.is(tok::code_completion)) { + PP.CodeCompleteNaturalLanguage(); } else { // Otherwise, just append the token. Do some gymnastics to get the token // in place and avoid copies where possible. @@ -274,7 +286,8 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, } } - PP.CreateString(&Result[0], Result.size(), Tok, hashInstLoc); + PP.CreateString(&Result[0], Result.size(), Tok, + ExpansionLocStart, ExpansionLocEnd); return Tok; } @@ -282,7 +295,8 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, /// that has been 'stringified' as required by the # operator. const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, - SourceLocation hashInstLoc) { + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd) { assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!"); if (StringifiedArgs.empty()) { StringifiedArgs.resize(getNumArguments()); @@ -291,6 +305,8 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, } if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP, - /*Charify=*/false, hashInstLoc); + /*Charify=*/false, + ExpansionLocStart, + ExpansionLocEnd); return StringifiedArgs[ArgNo]; } diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.h b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.h index a962dac..cf86d71 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.h +++ b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_MACROARGS_H #define LLVM_CLANG_MACROARGS_H +#include "llvm/ADT/ArrayRef.h" + #include <vector> namespace clang { @@ -58,9 +60,8 @@ public: /// MacroArgs ctor function - Create a new MacroArgs object with the specified /// macro and argument info. static MacroArgs *create(const MacroInfo *MI, - const Token *UnexpArgTokens, - unsigned NumArgTokens, bool VarargsElided, - Preprocessor &PP); + llvm::ArrayRef<Token> UnexpArgTokens, + bool VarargsElided, Preprocessor &PP); /// destroy - Destroy and deallocate the memory for this object. /// @@ -88,7 +89,8 @@ public: /// getStringifiedArgument - Compute, cache, and return the specified argument /// that has been 'stringified' as required by the # operator. const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, - SourceLocation hashInstLoc); + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd); /// getNumArguments - Return the number of arguments passed into this macro /// invocation. @@ -109,7 +111,8 @@ public: /// static Token StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify, - SourceLocation hashInstLoc); + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd); /// deallocate - This should only be called by the Preprocessor when managing diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp index 0a16a25..5a7af56 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp @@ -21,6 +21,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { IsGNUVarargs = false; IsBuiltinMacro = false; IsFromAST = false; + ChangedAfterLoad = false; IsDisabled = false; IsUsed = false; IsAllowRedefinitionsWithoutWarning = false; @@ -40,6 +41,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) { IsGNUVarargs = MI.IsGNUVarargs; IsBuiltinMacro = MI.IsBuiltinMacro; IsFromAST = MI.IsFromAST; + ChangedAfterLoad = MI.ChangedAfterLoad; IsDisabled = MI.IsDisabled; IsUsed = MI.IsUsed; IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning; @@ -68,9 +70,9 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { assert((macroEnd.isFileID() || lastToken.is(tok::comment)) && "Macro defined in macro?"); std::pair<FileID, unsigned> - startInfo = SM.getDecomposedInstantiationLoc(macroStart); + startInfo = SM.getDecomposedExpansionLoc(macroStart); std::pair<FileID, unsigned> - endInfo = SM.getDecomposedInstantiationLoc(macroEnd); + endInfo = SM.getDecomposedExpansionLoc(macroEnd); assert(startInfo.first == endInfo.first && "Macro definition spanning multiple FileIDs ?"); assert(startInfo.second <= endInfo.second); diff --git a/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp b/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp index 3310659..986341b 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp @@ -74,6 +74,8 @@ void Preprocessor::EnterCachingLexMode() { return; PushIncludeMacroStack(); + if (CurLexerKind != CLK_LexAfterModuleImport) + CurLexerKind = CLK_CachingLexer; } diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index 4af5fab..de50c75 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -17,6 +17,7 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" +#include "clang/Lex/ModuleLoader.h" #include "clang/Lex/Pragma.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -102,8 +103,8 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { if (MacroNameTok.is(tok::code_completion)) { if (CodeComplete) CodeComplete->CodeCompleteMacroName(isDefineUndef == 1); + setCodeCompletionReached(); LexUnexpandedToken(MacroNameTok); - return; } // Missing macro name? @@ -192,7 +193,8 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { /// the first valid token. void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, bool FoundNonSkipPortion, - bool FoundElse) { + bool FoundElse, + SourceLocation ElseLoc) { ++NumSkipped; assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?"); @@ -214,6 +216,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, if (Tok.is(tok::code_completion)) { if (CodeComplete) CodeComplete->CodeCompleteInConditionalExclusion(); + setCodeCompletionReached(); continue; } @@ -222,7 +225,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // Emit errors for each unterminated conditional on the stack, including // the current one. while (!CurPPLexer->ConditionalStack.empty()) { - if (!isCodeCompletionFile(Tok.getLocation())) + if (CurLexer->getFileLoc() != CodeCompletionFileLoc) Diag(CurPPLexer->ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); CurPPLexer->ConditionalStack.pop_back(); @@ -275,9 +278,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // that we can't use Tok.getIdentifierInfo() because its lookup is disabled // when skipping. char DirectiveBuf[20]; - llvm::StringRef Directive; + StringRef Directive; if (!Tok.needsCleaning() && Tok.getLength() < 20) { - Directive = llvm::StringRef(RawCharData, Tok.getLength()); + Directive = StringRef(RawCharData, Tok.getLength()); } else { std::string DirectiveStr = getSpelling(Tok); unsigned IdLen = DirectiveStr.size(); @@ -288,11 +291,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, continue; } memcpy(DirectiveBuf, &DirectiveStr[0], IdLen); - Directive = llvm::StringRef(DirectiveBuf, IdLen); + Directive = StringRef(DirectiveBuf, IdLen); } if (Directive.startswith("if")) { - llvm::StringRef Sub = Directive.substr(2); + StringRef Sub = Directive.substr(2); if (Sub.empty() || // "if" Sub == "def" || // "ifdef" Sub == "ndef") { // "ifndef" @@ -307,7 +310,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, Callbacks->Endif(); } } else if (Directive[0] == 'e') { - llvm::StringRef Sub = Directive.substr(1); + StringRef Sub = Directive.substr(1); if (Sub == "ndif") { // "endif" CheckEndOfDirective("endif"); PPConditionalInfo CondInfo; @@ -387,6 +390,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // of the file, just stop skipping and return to lexing whatever came after // the #if block. CurPPLexer->LexingRawMode = false; + + if (Callbacks) { + SourceLocation BeginLoc = ElseLoc.isValid() ? ElseLoc : IfTokenLoc; + Callbacks->SourceRangeSkipped(SourceRange(BeginLoc, Tok.getLocation())); + } } void Preprocessor::PTHSkipExcludedConditionalBlock() { @@ -472,12 +480,13 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). const FileEntry *Preprocessor::LookupFile( - llvm::StringRef Filename, + StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef *SuggestedModule) { // If the header lookup mechanism may be relative to the current file, pass in // info about where the current file is. const FileEntry *CurFileEnt = 0; @@ -501,12 +510,13 @@ const FileEntry *Preprocessor::LookupFile( CurDir = CurDirLookup; const FileEntry *FE = HeaderInfo.LookupFile( Filename, isAngled, FromDir, CurDir, CurFileEnt, - SearchPath, RelativePath); + SearchPath, RelativePath, SuggestedModule); if (FE) return FE; // Otherwise, see if this is a subframework header. If so, this is relative // to one of the headers on the #include stack. Walk the list of the current // headers on the #include stack and pass them to HeaderInfo. + // FIXME: SuggestedModule! if (IsFileLexer()) { if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt, @@ -581,6 +591,7 @@ TryAgain: if (CodeComplete) CodeComplete->CodeCompleteDirective( CurPPLexer->getConditionalStackDepth() > 0); + setCodeCompletionReached(); return; case tok::numeric_constant: // # 7 GNU line marker directive. if (getLangOptions().AsmPreprocessor) @@ -652,6 +663,9 @@ TryAgain: case tok::pp_unassert: //isExtension = true; // FIXME: implement #unassert break; + + case tok::pp___export_macro__: + return HandleMacroExportDirective(Result); } break; } @@ -758,9 +772,13 @@ void Preprocessor::HandleLineDirective(Token &Tok) { // Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a // number greater than 2147483647". C90 requires that the line # be <= 32767. - unsigned LineLimit = Features.C99 ? 2147483648U : 32768U; + unsigned LineLimit = 32768U; + if (Features.C99 || Features.CPlusPlus0x) + LineLimit = 2147483648U; if (LineNo >= LineLimit) Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit; + else if (Features.CPlusPlus0x && LineNo >= 32768U) + Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big); int FilenameID = -1; Token StrTok; @@ -777,7 +795,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) { } else { // Parse and validate the string, converting it into a unique ID. StringLiteralParser Literal(&StrTok, 1, *this); - assert(!Literal.AnyWide && "Didn't allow wide strings in"); + assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) return DiscardUntilEndOfDirective(); if (Literal.Pascal) { @@ -825,7 +843,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, // If we are leaving the current presumed file, check to make sure the // presumed include stack isn't empty! FileID CurFileID = - SM.getDecomposedInstantiationLoc(FlagTok.getLocation()).first; + SM.getDecomposedExpansionLoc(FlagTok.getLocation()).first; PresumedLoc PLoc = SM.getPresumedLoc(FlagTok.getLocation()); if (PLoc.isInvalid()) return true; @@ -834,7 +852,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, // different physical file, then we aren't in a "1" line marker flag region. SourceLocation IncLoc = PLoc.getIncludeLoc(); if (IncLoc.isInvalid() || - SM.getDecomposedInstantiationLoc(IncLoc).first != CurFileID) { + SM.getDecomposedExpansionLoc(IncLoc).first != CurFileID) { PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_pop); PP.DiscardUntilEndOfDirective(); return true; @@ -910,7 +928,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { } else { // Parse and validate the string, converting it into a unique ID. StringLiteralParser Literal(&StrTok, 1, *this); - assert(!Literal.AnyWide && "Didn't allow wide strings in"); + assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) return DiscardUntilEndOfDirective(); if (Literal.Pascal) { @@ -1000,6 +1018,37 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { } } +/// \brief Handle a #__export_macro__ directive. +void Preprocessor::HandleMacroExportDirective(Token &Tok) { + Token MacroNameTok; + ReadMacroName(MacroNameTok, 2); + + // Error reading macro name? If so, diagnostic already issued. + if (MacroNameTok.is(tok::eod)) + return; + + // Check to see if this is the last token on the #__export_macro__ line. + CheckEndOfDirective("__export_macro__"); + + // Okay, we finally have a valid identifier to undef. + MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo()); + + // If the macro is not defined, this is an error. + if (MI == 0) { + Diag(MacroNameTok, diag::err_pp_export_non_macro) + << MacroNameTok.getIdentifierInfo(); + return; + } + + // Note that this macro has now been exported. + MI->setExportLocation(MacroNameTok.getLocation()); + + // If this macro definition came from a PCH file, mark it + // as having changed since serialization. + if (MI->isFromAST()) + MI->setChangedAfterLoad(); +} + //===----------------------------------------------------------------------===// // Preprocessor Include Directive Handling. //===----------------------------------------------------------------------===// @@ -1011,7 +1060,7 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { /// spelling of the filename, but is also expected to handle the case when /// this method decides to use a different buffer. bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, - llvm::StringRef &Buffer) { + StringRef &Buffer) { // Get the text form of the filename. assert(!Buffer.empty() && "Can't have tokens with empty spellings!"); @@ -1020,27 +1069,27 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, if (Buffer[0] == '<') { if (Buffer.back() != '>') { Diag(Loc, diag::err_pp_expects_filename); - Buffer = llvm::StringRef(); + Buffer = StringRef(); return true; } isAngled = true; } else if (Buffer[0] == '"') { if (Buffer.back() != '"') { Diag(Loc, diag::err_pp_expects_filename); - Buffer = llvm::StringRef(); + Buffer = StringRef(); return true; } isAngled = false; } else { Diag(Loc, diag::err_pp_expects_filename); - Buffer = llvm::StringRef(); + Buffer = StringRef(); return true; } // Diagnose #include "" as invalid. if (Buffer.size() <= 2) { Diag(Loc, diag::err_pp_empty_filename); - Buffer = llvm::StringRef(); + Buffer = StringRef(); return true; } @@ -1070,6 +1119,7 @@ bool Preprocessor::ConcatenateIncludeName( // FIXME: Provide code completion for #includes. if (CurTok.is(tok::code_completion)) { + setCodeCompletionReached(); Lex(CurTok); continue; } @@ -1122,7 +1172,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // Reserve a buffer to get the spelling. llvm::SmallString<128> FilenameBuffer; - llvm::StringRef Filename; + StringRef Filename; SourceLocation End; switch (FilenameTok.getKind()) { @@ -1171,23 +1221,44 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, return; } + // Complain about attempts to #include files in an audit pragma. + if (PragmaARCCFCodeAuditedLoc.isValid()) { + Diag(HashLoc, diag::err_pp_include_in_arc_cf_code_audited); + Diag(PragmaARCCFCodeAuditedLoc, diag::note_pragma_entered_here); + + // Immediately leave the pragma. + PragmaARCCFCodeAuditedLoc = SourceLocation(); + } + // Search include directories. const DirectoryLookup *CurDir; llvm::SmallString<1024> SearchPath; llvm::SmallString<1024> RelativePath; // We get the raw path only if we have 'Callbacks' to which we later pass // the path. + StringRef SuggestedModule; const FileEntry *File = LookupFile( Filename, isAngled, LookupFrom, CurDir, - Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL); - + Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL, + AutoModuleImport? &SuggestedModule : 0); + + // If we are supposed to import a module rather than including the header, + // do so now. + if (!SuggestedModule.empty()) { + TheModuleLoader.loadModule(IncludeTok.getLocation(), + Identifiers.get(SuggestedModule), + FilenameTok.getLocation()); + return; + } + // Notify the callback object that we've seen an inclusion directive. if (Callbacks) Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File, End, SearchPath, RelativePath); if (File == 0) { - Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename; + if (!SuppressIncludeNotFoundError) + Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } @@ -1284,7 +1355,7 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc, /// closing ), updating MI with what we learn. Return true if an error occurs /// parsing the arg list. bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { - llvm::SmallVector<IdentifierInfo*, 32> Arguments; + SmallVector<IdentifierInfo*, 32> Arguments; Token Tok; while (1) { @@ -1298,8 +1369,10 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { Diag(Tok, diag::err_pp_expected_ident_in_arg_list); return true; case tok::ellipsis: // #define X(... -> C99 varargs - // Warn if use of C99 feature in non-C99 mode. - if (!Features.C99) Diag(Tok, diag::ext_variadic_macro); + if (!Features.C99) + Diag(Tok, Features.CPlusPlus0x ? + diag::warn_cxx98_compat_variadic_macro : + diag::ext_variadic_macro); // Lex the token after the identifier. LexUnexpandedToken(Tok); @@ -1423,7 +1496,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // Read the first token after the arg list for down below. LexUnexpandedToken(Tok); - } else if (Features.C99) { + } else if (Features.C99 || Features.CPlusPlus0x) { // C99 requires whitespace between the macro definition and the body. Emit // a diagnostic for something like "#define X+". Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name); @@ -1564,7 +1637,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // warn-because-unused-macro set. If it gets used it will be removed from set. if (isInPrimaryFile() && // don't warn for include'd macros. Diags->getDiagnosticLevel(diag::pp_macro_not_used, - MI->getDefinitionLoc()) != Diagnostic::Ignored) { + MI->getDefinitionLoc()) != DiagnosticsEngine::Ignored) { MI->setIsWarnIfUnused(true); WarnUnusedMacroLocs.insert(MI->getDefinitionLoc()); } @@ -1765,7 +1838,7 @@ void Preprocessor::HandleElseDirective(Token &Result) { // Finally, skip the rest of the contents of this block. SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/true); + /*FoundElse*/true, Result.getLocation()); if (Callbacks) Callbacks->Else(); @@ -1798,7 +1871,8 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) { // Finally, skip the rest of the contents of this block. SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/CI.FoundElse); + /*FoundElse*/CI.FoundElse, + ElifToken.getLocation()); if (Callbacks) Callbacks->Elif(SourceRange(ConditionalBegin, ConditionalEnd)); diff --git a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp index 8fcfc70..20f624a 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp @@ -23,6 +23,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LexDiagnostic.h" #include "llvm/ADT/APSInt.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; namespace { @@ -83,20 +84,21 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, Result.setBegin(PeekTok.getLocation()); // Get the next token, don't expand it. - PP.LexUnexpandedToken(PeekTok); + PP.LexUnexpandedNonComment(PeekTok); // Two options, it can either be a pp-identifier or a (. SourceLocation LParenLoc; if (PeekTok.is(tok::l_paren)) { // Found a paren, remember we saw it and skip it. LParenLoc = PeekTok.getLocation(); - PP.LexUnexpandedToken(PeekTok); + PP.LexUnexpandedNonComment(PeekTok); } if (PeekTok.is(tok::code_completion)) { if (PP.getCodeCompletionHandler()) PP.getCodeCompletionHandler()->CodeCompleteMacroName(false); - PP.LexUnexpandedToken(PeekTok); + PP.setCodeCompletionReached(); + PP.LexUnexpandedNonComment(PeekTok); } // If we don't have a pp-identifier now, this is an error. @@ -115,12 +117,16 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, PP.markMacroAsUsed(Macro); } - // Consume identifier. - Result.setEnd(PeekTok.getLocation()); - PP.LexUnexpandedToken(PeekTok); + // Invoke the 'defined' callback. + if (PPCallbacks *Callbacks = PP.getPPCallbacks()) + Callbacks->Defined(PeekTok); // If we are in parens, ensure we have a trailing ). if (LParenLoc.isValid()) { + // Consume identifier. + Result.setEnd(PeekTok.getLocation()); + PP.LexUnexpandedNonComment(PeekTok); + if (PeekTok.isNot(tok::r_paren)) { PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined"; PP.Diag(LParenLoc, diag::note_matching) << "("; @@ -129,6 +135,10 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // Consume the ). Result.setEnd(PeekTok.getLocation()); PP.LexNonComment(PeekTok); + } else { + // Consume identifier. + Result.setEnd(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); } // Success, remember that we saw defined(X). @@ -152,7 +162,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, if (PeekTok.is(tok::code_completion)) { if (PP.getCodeCompletionHandler()) PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression(); - PP.LexUnexpandedToken(PeekTok); + PP.setCodeCompletionReached(); + PP.LexNonComment(PeekTok); } // If this token's spelling is a pp-identifier, check to see if it is @@ -188,7 +199,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, case tok::numeric_constant: { llvm::SmallString<64> IntegerBuffer; bool NumberInvalid = false; - llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer, + StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer, &NumberInvalid); if (NumberInvalid) return true; // a diagnostic was already reported @@ -205,9 +216,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); // long long is a C99 feature. - if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x - && Literal.isLongLong) - PP.Diag(PeekTok, diag::ext_longlong); + if (!PP.getLangOptions().C99 && Literal.isLongLong) + PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_longlong); // Parse the integer literal into Result. if (Literal.GetIntegerValue(Result.Val)) { @@ -236,15 +247,18 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, PP.LexNonComment(PeekTok); return false; } - case tok::char_constant: { // 'x' + case tok::char_constant: // 'x' + case tok::wide_char_constant: { // L'x' + case tok::utf16_char_constant: // u'x' + case tok::utf32_char_constant: // U'x' llvm::SmallString<32> CharBuffer; bool CharInvalid = false; - llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid); + StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid); if (CharInvalid) return true; CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), - PeekTok.getLocation(), PP); + PeekTok.getLocation(), PP, PeekTok.getKind()); if (Literal.hadError()) return true; // A diagnostic was already emitted. @@ -255,6 +269,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, NumBits = TI.getIntWidth(); else if (Literal.isWide()) NumBits = TI.getWCharWidth(); + else if (Literal.isUTF16()) + NumBits = TI.getChar16Width(); + else if (Literal.isUTF32()) + NumBits = TI.getChar32Width(); else NumBits = TI.getCharWidth(); @@ -262,8 +280,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, llvm::APSInt Val(NumBits); // Set the value. Val = Literal.getValue(); - // Set the signedness. - Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned); + // Set the signedness. UTF-16 and UTF-32 are always unsigned + if (!Literal.isUTF16() && !Literal.isUTF32()) + Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned); if (Result.Val.getBitWidth() > Val.getBitWidth()) { Result.Val = Val.extend(Result.Val.getBitWidth()); @@ -521,7 +540,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, bool Overflow = false; switch (Operator) { - default: assert(0 && "Unknown operator token!"); + default: llvm_unreachable("Unknown operator token!"); case tok::percent: if (RHS.Val != 0) Res = LHS.Val % RHS.Val; @@ -704,7 +723,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Peek ahead one token. Token Tok; - Lex(Tok); + LexNonComment(Tok); // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t. unsigned BitWidth = getTargetInfo().getIntMaxTWidth(); @@ -759,4 +778,3 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } - diff --git a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp index bf28199..25a98ae 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp @@ -89,7 +89,14 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, << std::string(SourceMgr.getBufferName(FileStart)) << ""; return; } - + + if (isCodeCompletionEnabled() && + SourceMgr.getFileEntryForID(FID) == CodeCompletionFile) { + CodeCompletionFileLoc = SourceMgr.getLocForStartOfFile(FID); + CodeCompletionLoc = + CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset); + } + EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); return; } @@ -106,7 +113,9 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, CurLexer.reset(TheLexer); CurPPLexer = TheLexer; CurDirLookup = CurDir; - + if (CurLexerKind != CLK_LexAfterModuleImport) + CurLexerKind = CLK_Lexer; + // Notify the client, if desired, that we are in a new source file. if (Callbacks && !CurLexer->Is_PragmaLexer) { SrcMgr::CharacteristicKind FileType = @@ -128,7 +137,9 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL, CurDirLookup = CurDir; CurPTHLexer.reset(PL); CurPPLexer = CurPTHLexer.get(); - + if (CurLexerKind != CLK_LexAfterModuleImport) + CurLexerKind = CLK_PTHLexer; + // Notify the client, if desired, that we are in a new source file. if (Callbacks) { FileID FID = CurPPLexer->getFileID(); @@ -152,6 +163,8 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd, CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]); CurTokenLexer->Init(Tok, ILEnd, Args); } + if (CurLexerKind != CLK_LexAfterModuleImport) + CurLexerKind = CLK_TokenLexer; } /// EnterTokenStream - Add a "macro" context to the top of the include stack, @@ -181,6 +194,8 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks, CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]); CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens); } + if (CurLexerKind != CLK_LexAfterModuleImport) + CurLexerKind = CLK_TokenLexer; } /// HandleEndOfFile - This callback is invoked when the lexer hits the end of @@ -201,9 +216,50 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { } } + // Complain about reaching an EOF within arc_cf_code_audited. + if (PragmaARCCFCodeAuditedLoc.isValid()) { + Diag(PragmaARCCFCodeAuditedLoc, diag::err_pp_eof_in_arc_cf_code_audited); + + // Recover by leaving immediately. + PragmaARCCFCodeAuditedLoc = SourceLocation(); + } + // If this is a #include'd file, pop it off the include stack and continue // lexing the #includer file. if (!IncludeMacroStack.empty()) { + + // If we lexed the code-completion file, act as if we reached EOF. + if (isCodeCompletionEnabled() && CurPPLexer && + SourceMgr.getLocForStartOfFile(CurPPLexer->getFileID()) == + CodeCompletionFileLoc) { + if (CurLexer) { + Result.startToken(); + CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof); + CurLexer.reset(); + } else { + assert(CurPTHLexer && "Got EOF but no current lexer set!"); + CurPTHLexer->getEOF(Result); + CurPTHLexer.reset(); + } + + CurPPLexer = 0; + return true; + } + + if (!isEndOfMacro && CurPPLexer && + SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid()) { + // Notify SourceManager to record the number of FileIDs that were created + // during lexing of the #include'd file. + unsigned NumFIDs = + SourceMgr.local_sloc_entry_size() - + CurPPLexer->getInitialNumSLocEntries() + 1/*#include'd file*/; + SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs); + } + + FileID ExitedFID; + if (Callbacks && !isEndOfMacro && CurPPLexer) + ExitedFID = CurPPLexer->getFileID(); + // We're done with the #included file. RemoveTopOfLexerStack(); @@ -212,7 +268,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { SrcMgr::CharacteristicKind FileType = SourceMgr.getFileCharacteristic(CurPPLexer->getSourceLocation()); Callbacks->FileChanged(CurPPLexer->getSourceLocation(), - PPCallbacks::ExitFile, FileType); + PPCallbacks::ExitFile, FileType, ExitedFID); } // Client should lex another token. diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp index ecd4d4c..e10c95c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -21,10 +21,12 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/LiteralSupport.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include <cstdio> #include <ctime> using namespace clang; @@ -91,9 +93,10 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); + Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); // Microsoft Extensions. - if (Features.Microsoft) + if (Features.MicrosoftExt) Ident__pragma = RegisterBuiltinMacro(*this, "__pragma"); else Ident__pragma = 0; @@ -185,7 +188,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { - if (Callbacks) Callbacks->MacroExpands(Identifier, MI); + if (Callbacks) Callbacks->MacroExpands(Identifier, MI, + Identifier.getLocation()); ExpandBuiltinMacro(Identifier); return false; } @@ -226,13 +230,14 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // Notice that this macro has been used. markMacroAsUsed(MI); - if (Callbacks) Callbacks->MacroExpands(Identifier, MI); - - // If we started lexing a macro, enter the macro expansion body. - // Remember where the token is expanded. SourceLocation ExpandLoc = Identifier.getLocation(); + if (Callbacks) Callbacks->MacroExpands(Identifier, MI, + SourceRange(ExpandLoc, ExpansionEnd)); + + // If we started lexing a macro, enter the macro expansion body. + // If this macro expands to no tokens, don't bother to push it onto the // expansion stack, only to take it right back off. if (MI->getNumTokens() == 0) { @@ -255,7 +260,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace); } Identifier.setFlag(Token::LeadingEmptyMacro); - LastEmptyMacroExpansionLoc = ExpandLoc; ++NumFastMacroExpanded; return false; @@ -284,8 +288,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // Update the tokens location to include both its expansion and physical // locations. SourceLocation Loc = - SourceMgr.createInstantiationLoc(Identifier.getLocation(), ExpandLoc, - ExpansionEnd,Identifier.getLength()); + SourceMgr.createExpansionLoc(Identifier.getLocation(), ExpandLoc, + ExpansionEnd,Identifier.getLength()); Identifier.setLocation(Loc); // If this is a disabled macro or #define X X, we must mark the result as @@ -333,7 +337,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // ArgTokens - Build up a list of tokens that make up each argument. Each // argument is separated by an EOF token. Use a SmallVector so we can avoid // heap allocations in the common case. - llvm::SmallVector<Token, 64> ArgTokens; + SmallVector<Token, 64> ArgTokens; unsigned NumActuals = 0; while (Tok.isNot(tok::r_paren)) { @@ -352,13 +356,6 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // an argument value in a macro could expand to ',' or '(' or ')'. LexUnexpandedToken(Tok); - if (Tok.is(tok::code_completion)) { - if (CodeComplete) - CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(), - MI, NumActuals); - LexUnexpandedToken(Tok); - } - if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n" Diag(MacroName, diag::err_unterm_macro_invoc); // Do not lose the EOF/EOD. Return it to the client. @@ -393,7 +390,15 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo())) if (!MI->isEnabled()) Tok.setFlag(Token::DisableExpand); + } else if (Tok.is(tok::code_completion)) { + if (CodeComplete) + CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(), + MI, NumActuals); + // Don't mark that we reached the code-completion point because the + // parser is going to handle the token and there will be another + // code-completion callback. } + ArgTokens.push_back(Tok); } @@ -416,8 +421,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // Empty arguments are standard in C99 and C++0x, and are supported as an extension in // other modes. - if (ArgTokens.size() == ArgTokenStart && !Features.C99 && !Features.CPlusPlus0x) - Diag(Tok, diag::ext_empty_fnmacro_arg); + if (ArgTokens.size() == ArgTokenStart && !Features.C99) + Diag(Tok, Features.CPlusPlus0x ? + diag::warn_cxx98_compat_empty_fnmacro_arg : + diag::ext_empty_fnmacro_arg); // Add a marker EOF token to the end of the token list for this argument. Token EOFTok; @@ -487,8 +494,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, return 0; } - return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(), - isVarargsElided, *this); + return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this); } /// \brief Keeps macro expanded tokens for TokenLexers. @@ -497,7 +503,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, /// going to lex in the cache and when it finishes the tokens are removed /// from the end of the cache. Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer, - llvm::ArrayRef<Token> tokens) { + ArrayRef<Token> tokens) { assert(tokLexer); if (tokens.empty()) return 0; @@ -597,34 +603,48 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("objc_arc", LangOpts.ObjCAutoRefCount) .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && LangOpts.ObjCRuntimeHasWeak) + .Case("objc_fixed_enum", LangOpts.ObjC2) + .Case("objc_instancetype", LangOpts.ObjC2) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) // C1X features + .Case("c_alignas", LangOpts.C1X) .Case("c_generic_selections", LangOpts.C1X) .Case("c_static_assert", LangOpts.C1X) // C++0x features .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x) .Case("cxx_alias_templates", LangOpts.CPlusPlus0x) + .Case("cxx_alignas", LangOpts.CPlusPlus0x) .Case("cxx_attributes", LangOpts.CPlusPlus0x) .Case("cxx_auto_type", LangOpts.CPlusPlus0x) + //.Case("cxx_constexpr", false); .Case("cxx_decltype", LangOpts.CPlusPlus0x) .Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x) .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x) .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) + .Case("cxx_explicit_conversions", LangOpts.CPlusPlus0x) + //.Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x) + .Case("cxx_implicit_moves", LangOpts.CPlusPlus0x) + //.Case("cxx_inheriting_constructors", false) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) + .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus0x) .Case("cxx_noexcept", LangOpts.CPlusPlus0x) .Case("cxx_nullptr", LangOpts.CPlusPlus0x) .Case("cxx_override_control", LangOpts.CPlusPlus0x) .Case("cxx_range_for", LangOpts.CPlusPlus0x) + //.Case("cxx_raw_string_literals", false) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x) .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x) .Case("cxx_strong_enums", LangOpts.CPlusPlus0x) .Case("cxx_static_assert", LangOpts.CPlusPlus0x) .Case("cxx_trailing_return", LangOpts.CPlusPlus0x) + //.Case("cxx_unicode_literals", false) + //.Case("cxx_unrestricted_unions", false) + //.Case("cxx_user_literals", false) .Case("cxx_variadic_templates", LangOpts.CPlusPlus0x) // Type traits .Case("has_nothrow_assign", LangOpts.CPlusPlus) @@ -639,16 +659,31 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_base_of", LangOpts.CPlusPlus) .Case("is_class", LangOpts.CPlusPlus) .Case("is_convertible_to", LangOpts.CPlusPlus) - .Case("is_empty", LangOpts.CPlusPlus) + // __is_empty is available only if the horrible + // "struct __is_empty" parsing hack hasn't been needed in this + // translation unit. If it has, __is_empty reverts to a normal + // identifier and __has_feature(is_empty) evaluates false. + .Case("is_empty", + LangOpts.CPlusPlus && + PP.getIdentifierInfo("__is_empty")->getTokenID() + != tok::identifier) .Case("is_enum", LangOpts.CPlusPlus) .Case("is_literal", LangOpts.CPlusPlus) .Case("is_standard_layout", LangOpts.CPlusPlus) - .Case("is_pod", LangOpts.CPlusPlus) + // __is_pod is available only if the horrible + // "struct __is_pod" parsing hack hasn't been needed in this + // translation unit. If it has, __is_pod reverts to a normal + // identifier and __has_feature(is_pod) evaluates false. + .Case("is_pod", + LangOpts.CPlusPlus && + PP.getIdentifierInfo("__is_pod")->getTokenID() + != tok::identifier) .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_trivially_copyable", LangOpts.CPlusPlus) .Case("is_union", LangOpts.CPlusPlus) .Case("tls", PP.getTargetInfo().isTLSSupported()) + .Case("underlying_type", LangOpts.CPlusPlus) .Default(false); } @@ -661,7 +696,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { // If the use of an extension results in an error diagnostic, extensions are // effectively unavailable, so just return false here. - if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error) + if (PP.getDiagnostics().getExtensionHandlingBehavior() == + DiagnosticsEngine::Ext_Error) return false; const LangOptions &LangOpts = PP.getLangOptions(); @@ -670,12 +706,16 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { // must be less restrictive than HasFeature's. return llvm::StringSwitch<bool>(II->getName()) // C1X features supported by other languages as extensions. + .Case("c_alignas", true) .Case("c_generic_selections", true) .Case("c_static_assert", true) // C++0x features supported by other languages as extensions. .Case("cxx_deleted_functions", LangOpts.CPlusPlus) + .Case("cxx_explicit_conversions", LangOpts.CPlusPlus) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) + .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus) .Case("cxx_override_control", LangOpts.CPlusPlus) + .Case("cxx_range_for", LangOpts.CPlusPlus) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) .Case("cxx_rvalue_references", LangOpts.CPlusPlus) .Default(false); @@ -714,7 +754,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // Reserve a buffer to get the spelling. llvm::SmallString<128> FilenameBuffer; - llvm::StringRef Filename; + StringRef Filename; SourceLocation EndLoc; switch (Tok.getKind()) { @@ -753,7 +793,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // Search include directories. const DirectoryLookup *CurDir; const FileEntry *File = - PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL); + PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL); // Get the result value. Result = true means the file exists. bool Result = File != 0; @@ -837,7 +877,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // can matter for a function-like macro that expands to contain __LINE__. // Skip down through expansion points until we find a file loc for the // end of the expansion history. - Loc = SourceMgr.getInstantiationRange(Loc).second; + Loc = SourceMgr.getExpansionRange(Loc).second; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. @@ -874,18 +914,18 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); - Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(), - Tok.getLocation(), - Tok.getLength())); + Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(), + Tok.getLocation(), + Tok.getLength())); return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); - Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(), - Tok.getLocation(), - Tok.getLength())); + Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(), + Tok.getLocation(), + Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected @@ -923,7 +963,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. - OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"'; + OS << '"' << StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. @@ -983,10 +1023,78 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); + } else if (II == Ident__has_warning) { + // The argument should be a parenthesized string literal. + // The argument to these builtins should be a parenthesized identifier. + SourceLocation StartLoc = Tok.getLocation(); + bool IsValid = false; + bool Value = false; + // Read the '('. + Lex(Tok); + do { + if (Tok.is(tok::l_paren)) { + // Read the string. + Lex(Tok); + + // We need at least one string literal. + if (!Tok.is(tok::string_literal)) { + StartLoc = Tok.getLocation(); + IsValid = false; + // Eat tokens until ')'. + do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod))); + break; + } + + // String concatenation allows multiple strings, which can even come + // from macro expansion. + SmallVector<Token, 4> StrToks; + while (Tok.is(tok::string_literal)) { + StrToks.push_back(Tok); + LexUnexpandedToken(Tok); + } + + // Is the end a ')'? + if (!(IsValid = Tok.is(tok::r_paren))) + break; + + // Concatenate and parse the strings. + StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); + assert(Literal.isAscii() && "Didn't allow wide strings in"); + if (Literal.hadError) + break; + if (Literal.Pascal) { + Diag(Tok, diag::warn_pragma_diagnostic_invalid); + break; + } + + StringRef WarningName(Literal.GetString()); + + if (WarningName.size() < 3 || WarningName[0] != '-' || + WarningName[1] != 'W') { + Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option); + break; + } + + // Finally, check if the warning flags maps to a diagnostic group. + // We construct a SmallVector here to talk to getDiagnosticIDs(). + // Although we don't use the result, this isn't a hot path, and not + // worth special casing. + llvm::SmallVector<diag::kind, 10> Diags; + Value = !getDiagnostics().getDiagnosticIDs()-> + getDiagnosticsInGroup(WarningName.substr(2), Diags); + } + } while (false); + + if (!IsValid) + Diag(StartLoc, diag::err_warning_check_malformed); + + OS << (int)Value; + Tok.setKind(tok::numeric_constant); } else { - assert(0 && "Unknown identifier!"); + llvm_unreachable("Unknown identifier!"); } - CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation()); + CreateString(OS.str().data(), OS.str().size(), Tok, + Tok.getLocation(), Tok.getLocation()); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp index e5ef0fd..e0c4cf0 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp @@ -73,7 +73,7 @@ LexNextToken: Tok.setKind(TKind); Tok.setFlag(TFlags); assert(!LexingRawMode); - Tok.setLocation(FileStartLoc.getFileLocWithOffset(FileOffset)); + Tok.setLocation(FileStartLoc.getLocWithOffset(FileOffset)); Tok.setLength(Len); // Handle identifiers. @@ -147,7 +147,7 @@ bool PTHLexer::LexEndOfFile(Token &Result) { // If we are in a #if directive, emit an error. while (!ConditionalStack.empty()) { - if (!PP->isCodeCompletionFile(FileStartLoc)) + if (PP->getCodeCompletionFileLoc() != FileStartLoc) PP->Diag(ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); ConditionalStack.pop_back(); @@ -297,7 +297,7 @@ SourceLocation PTHLexer::getSourceLocation() { // NOTE: This is a virtual function; hence it is defined out-of-line. const unsigned char *OffsetPtr = CurPtr + (DISK_TOKEN_SIZE - 4); uint32_t Offset = ReadLE32(OffsetPtr); - return FileStartLoc.getFileLocWithOffset(Offset); + return FileStartLoc.getLocWithOffset(Offset); } //===----------------------------------------------------------------------===// @@ -380,7 +380,7 @@ public: } static unsigned ComputeHash(const internal_key_type& a) { - return llvm::HashString(llvm::StringRef(a.first, a.second)); + return llvm::HashString(StringRef(a.first, a.second)); } // This hopefully will just get inlined and removed by the optimizer. @@ -431,11 +431,12 @@ PTHManager::~PTHManager() { free(PerIDCache); } -static void InvalidPTH(Diagnostic &Diags, const char *Msg) { - Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg)); +static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) { + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, Msg)); } -PTHManager *PTHManager::Create(const std::string &file, Diagnostic &Diags) { +PTHManager *PTHManager::Create(const std::string &file, + DiagnosticsEngine &Diags) { // Memory map the PTH file. llvm::OwningPtr<llvm::MemoryBuffer> File; @@ -572,10 +573,10 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { return II; } -IdentifierInfo* PTHManager::get(llvm::StringRef Name) { +IdentifierInfo* PTHManager::get(StringRef Name) { PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup); // Double check our assumption that the last character isn't '\0'. - assert(Name.empty() || Name.data()[Name.size()-1] != '\0'); + assert(Name.empty() || Name.back() != '\0'); PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(), Name.size())); if (I == SL.end()) // No identifier found? diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index e6b28c1..f6532c2 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -54,11 +54,11 @@ PragmaNamespace::~PragmaNamespace() { /// specified name. If not, return the handler for the null identifier if it /// exists, otherwise return null. If IgnoreNull is true (the default) then /// the null handler isn't returned on failure to match. -PragmaHandler *PragmaNamespace::FindHandler(llvm::StringRef Name, +PragmaHandler *PragmaNamespace::FindHandler(StringRef Name, bool IgnoreNull) const { if (PragmaHandler *Handler = Handlers.lookup(Name)) return Handler; - return IgnoreNull ? 0 : Handlers.lookup(llvm::StringRef()); + return IgnoreNull ? 0 : Handlers.lookup(StringRef()); } void PragmaNamespace::AddPragma(PragmaHandler *Handler) { @@ -85,7 +85,7 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP, // Get the handler for this token. If there is no handler, ignore the pragma. PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo() ? Tok.getIdentifierInfo()->getName() - : llvm::StringRef(), + : StringRef(), /*IgnoreNull=*/false); if (Handler == 0) { PP.Diag(Tok, diag::warn_pragma_ignored); @@ -210,7 +210,7 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { } // Get the tokens enclosed within the __pragma(), as well as the final ')'. - llvm::SmallVector<Token, 32> PragmaToks; + SmallVector<Token, 32> PragmaToks; int NumParens = 0; Lex(Tok); while (Tok.isNot(tok::eof)) { @@ -353,7 +353,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Reserve a buffer to get the spelling. llvm::SmallString<128> FilenameBuffer; bool Invalid = false; - llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); + StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); if (Invalid) return; @@ -366,9 +366,11 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL); + const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL, + NULL); if (File == 0) { - Diag(FilenameTok, diag::warn_pp_file_not_found) << Filename; + if (!SuppressIncludeNotFoundError) + Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } @@ -436,7 +438,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { // String concatenation allows multiple strings, which can even come from // macro expansion. // "foo " "bar" "Baz" - llvm::SmallVector<Token, 4> StrToks; + SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { StrToks.push_back(Tok); Lex(Tok); @@ -444,7 +446,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { // Concatenate and parse the strings. StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); - assert(!Literal.AnyWide && "Didn't allow wide strings in"); + assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) return; if (Literal.Pascal) { @@ -512,7 +514,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { // String concatenation allows multiple strings, which can even come from // macro expansion. // "foo " "bar" "Baz" - llvm::SmallVector<Token, 4> StrToks; + SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { StrToks.push_back(Tok); Lex(Tok); @@ -520,7 +522,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { // Concatenate and parse the strings. StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); - assert(!Literal.AnyWide && "Didn't allow wide strings in"); + assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) return; if (Literal.Pascal) { @@ -528,7 +530,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { return; } - llvm::StringRef MessageString(Literal.GetString()); + StringRef MessageString(Literal.GetString()); if (ExpectClosingParen) { if (Tok.isNot(tok::r_paren)) { @@ -662,7 +664,7 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". -void Preprocessor::AddPragmaHandler(llvm::StringRef Namespace, +void Preprocessor::AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler) { PragmaNamespace *InsertNS = PragmaHandlers; @@ -693,7 +695,7 @@ void Preprocessor::AddPragmaHandler(llvm::StringRef Namespace, /// preprocessor. If \arg Namespace is non-null, then it should be the /// namespace that \arg Handler was added to. It is an error to remove /// a handler that has not been registered. -void Preprocessor::RemovePragmaHandler(llvm::StringRef Namespace, +void Preprocessor::RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler) { PragmaNamespace *NS = PragmaHandlers; @@ -802,7 +804,7 @@ struct PragmaDebugHandler : public PragmaHandler { IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("assert")) { - assert(0 && "This is an assertion!"); + llvm_unreachable("This is an assertion!"); } else if (II->isStr("crash")) { *(volatile int*) 0x11 = 0; } else if (II->isStr("llvm_fatal_error")) { @@ -889,7 +891,7 @@ public: // String concatenation allows multiple strings, which can even come from // macro expansion. // "foo " "bar" "Baz" - llvm::SmallVector<Token, 4> StrToks; + SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { StrToks.push_back(Tok); PP.LexUnexpandedToken(Tok); @@ -902,7 +904,7 @@ public: // Concatenate and parse the strings. StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP); - assert(!Literal.AnyWide && "Didn't allow wide strings in"); + assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) return; if (Literal.Pascal) { @@ -910,7 +912,7 @@ public: return; } - llvm::StringRef WarningName(Literal.GetString()); + StringRef WarningName(Literal.GetString()); if (WarningName.size() < 3 || WarningName[0] != '-' || WarningName[1] != 'W') { @@ -1003,6 +1005,60 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler { } }; +/// PragmaARCCFCodeAuditedHandler - +/// #pragma clang arc_cf_code_audited begin/end +struct PragmaARCCFCodeAuditedHandler : public PragmaHandler { + PragmaARCCFCodeAuditedHandler() : PragmaHandler("arc_cf_code_audited") {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &NameTok) { + SourceLocation Loc = NameTok.getLocation(); + bool IsBegin; + + Token Tok; + + // Lex the 'begin' or 'end'. + PP.LexUnexpandedToken(Tok); + const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo(); + if (BeginEnd && BeginEnd->isStr("begin")) { + IsBegin = true; + } else if (BeginEnd && BeginEnd->isStr("end")) { + IsBegin = false; + } else { + PP.Diag(Tok.getLocation(), diag::err_pp_arc_cf_code_audited_syntax); + return; + } + + // Verify that this is followed by EOD. + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + // The start location of the active audit. + SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedLoc(); + + // The start location we want after processing this. + SourceLocation NewLoc; + + if (IsBegin) { + // Complain about attempts to re-enter an audit. + if (BeginLoc.isValid()) { + PP.Diag(Loc, diag::err_pp_double_begin_of_arc_cf_code_audited); + PP.Diag(BeginLoc, diag::note_pragma_entered_here); + } + NewLoc = Loc; + } else { + // Complain about attempts to leave an audit that doesn't exist. + if (!BeginLoc.isValid()) { + PP.Diag(Loc, diag::err_pp_unmatched_end_of_arc_cf_code_audited); + return; + } + NewLoc = SourceLocation(); + } + + PP.setPragmaARCCFCodeAuditedLoc(NewLoc); + } +}; + } // end anonymous namespace @@ -1026,13 +1082,14 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("clang", new PragmaDebugHandler()); AddPragmaHandler("clang", new PragmaDependencyHandler()); AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang")); + AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler()); AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler()); AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler()); // MS extensions. - if (Features.Microsoft) { + if (Features.MicrosoftExt) { AddPragmaHandler(new PragmaCommentHandler()); } } diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 9f93ab0..2816609 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -14,8 +14,8 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Token.h" -#include "clang/Basic/IdentifierTable.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Capacity.h" using namespace clang; @@ -24,7 +24,7 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, - llvm::StringRef FileName, + StringRef FileName, bool InQuotes, const FileEntry *File, SourceRange Range) : PreprocessingDirective(InclusionDirectiveKind, Range), @@ -34,116 +34,254 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, = (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>()); memcpy(Memory, FileName.data(), FileName.size()); Memory[FileName.size()] = 0; - this->FileName = llvm::StringRef(Memory, FileName.size()); + this->FileName = StringRef(Memory, FileName.size()); } -void PreprocessingRecord::MaybeLoadPreallocatedEntities() const { - if (!ExternalSource || LoadedPreallocatedEntities) - return; - - LoadedPreallocatedEntities = true; - ExternalSource->ReadPreprocessedEntities(); +PreprocessingRecord::PreprocessingRecord(SourceManager &SM, + bool IncludeNestedMacroExpansions) + : SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), + ExternalSource(0) +{ } -PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions) - : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), - ExternalSource(0), NumPreallocatedEntities(0), - LoadedPreallocatedEntities(false) -{ +/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities +/// that source range \arg R encompasses. +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { + if (Range.isInvalid()) + return std::make_pair(iterator(this, 0), iterator(this, 0)); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + std::pair<unsigned, unsigned> + Local = findLocalPreprocessedEntitiesInRange(Range); + + // Check if range spans local entities. + if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin())) + return std::make_pair(iterator(this, Local.first), + iterator(this, Local.second)); + + std::pair<unsigned, unsigned> + Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range); + + // Check if range spans local entities. + if (Loaded.first == Loaded.second) + return std::make_pair(iterator(this, Local.first), + iterator(this, Local.second)); + + unsigned TotalLoaded = LoadedPreprocessedEntities.size(); + + // Check if range spans loaded entities. + if (Local.first == Local.second) + return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded), + iterator(this, int(Loaded.second)-TotalLoaded)); + + // Range spands loaded and local entities. + return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded), + iterator(this, Local.second)); } -PreprocessingRecord::iterator -PreprocessingRecord::begin(bool OnlyLocalEntities) { - if (OnlyLocalEntities) - return PreprocessedEntities.begin() + NumPreallocatedEntities; - - MaybeLoadPreallocatedEntities(); - return PreprocessedEntities.begin(); +std::pair<unsigned, unsigned> +PreprocessingRecord::findLocalPreprocessedEntitiesInRange( + SourceRange Range) const { + if (Range.isInvalid()) + return std::make_pair(0,0); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin()); + unsigned End = findEndLocalPreprocessedEntity(Range.getEnd()); + return std::make_pair(Begin, End); } -PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) { - if (!OnlyLocalEntities) - MaybeLoadPreallocatedEntities(); - - return PreprocessedEntities.end(); +namespace { + +template <SourceLocation (SourceRange::*getRangeLoc)() const> +struct PPEntityComp { + const SourceManager &SM; + + explicit PPEntityComp(const SourceManager &SM) : SM(SM) { } + + bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const { + SourceLocation LHS = getLoc(L); + SourceLocation RHS = getLoc(R); + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(PreprocessedEntity *L, SourceLocation RHS) const { + SourceLocation LHS = getLoc(L); + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, PreprocessedEntity *R) const { + SourceLocation RHS = getLoc(R); + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLoc(PreprocessedEntity *PPE) const { + SourceRange Range = PPE->getSourceRange(); + return (Range.*getRangeLoc)(); + } +}; + } -PreprocessingRecord::const_iterator -PreprocessingRecord::begin(bool OnlyLocalEntities) const { - if (OnlyLocalEntities) - return PreprocessedEntities.begin() + NumPreallocatedEntities; - - MaybeLoadPreallocatedEntities(); - return PreprocessedEntities.begin(); +unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity( + SourceLocation Loc) const { + if (SourceMgr.isLoadedSourceLocation(Loc)) + return 0; + + size_t Count = PreprocessedEntities.size(); + size_t Half; + std::vector<PreprocessedEntity *>::const_iterator + First = PreprocessedEntities.begin(); + std::vector<PreprocessedEntity *>::const_iterator I; + + // Do a binary search manually instead of using std::lower_bound because + // The end locations of entities may be unordered (when a macro expansion + // is inside another macro argument), but for this case it is not important + // whether we get the first macro expansion or its containing macro. + while (Count > 0) { + Half = Count/2; + I = First; + std::advance(I, Half); + if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(), + Loc)){ + First = I; + ++First; + Count = Count - Half - 1; + } else + Count = Half; + } + + return First - PreprocessedEntities.begin(); } -PreprocessingRecord::const_iterator -PreprocessingRecord::end(bool OnlyLocalEntities) const { - if (!OnlyLocalEntities) - MaybeLoadPreallocatedEntities(); - - return PreprocessedEntities.end(); +unsigned PreprocessingRecord::findEndLocalPreprocessedEntity( + SourceLocation Loc) const { + if (SourceMgr.isLoadedSourceLocation(Loc)) + return 0; + + std::vector<PreprocessedEntity *>::const_iterator + I = std::upper_bound(PreprocessedEntities.begin(), + PreprocessedEntities.end(), + Loc, + PPEntityComp<&SourceRange::getBegin>(SourceMgr)); + return I - PreprocessedEntities.begin(); } void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { - PreprocessedEntities.push_back(Entity); + assert(Entity); + SourceLocation BeginLoc = Entity->getSourceRange().getBegin(); + + // Check normal case, this entity begin location is after the previous one. + if (PreprocessedEntities.empty() || + !SourceMgr.isBeforeInTranslationUnit(BeginLoc, + PreprocessedEntities.back()->getSourceRange().getBegin())) { + PreprocessedEntities.push_back(Entity); + return; + } + + // The entity's location is not after the previous one; this can happen rarely + // e.g. with "#include MACRO". + // Iterate the entities vector in reverse until we find the right place to + // insert the new entity. + for (std::vector<PreprocessedEntity *>::iterator + RI = PreprocessedEntities.end(), Begin = PreprocessedEntities.begin(); + RI != Begin; --RI) { + std::vector<PreprocessedEntity *>::iterator I = RI; + --I; + if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc, + (*I)->getSourceRange().getBegin())) { + PreprocessedEntities.insert(RI, Entity); + return; + } + } } void PreprocessingRecord::SetExternalSource( - ExternalPreprocessingRecordSource &Source, - unsigned NumPreallocatedEntities) { + ExternalPreprocessingRecordSource &Source) { assert(!ExternalSource && "Preprocessing record already has an external source"); ExternalSource = &Source; - this->NumPreallocatedEntities = NumPreallocatedEntities; - PreprocessedEntities.insert(PreprocessedEntities.begin(), - NumPreallocatedEntities, 0); } -void PreprocessingRecord::SetPreallocatedEntity(unsigned Index, - PreprocessedEntity *Entity) { - assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity"); - PreprocessedEntities[Index] = Entity; +unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) { + unsigned Result = LoadedPreprocessedEntities.size(); + LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size() + + NumEntities); + return Result; +} + +void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, + PPEntityID PPID) { + MacroDefinitions[Macro] = PPID; +} + +/// \brief Retrieve the preprocessed entity at the given ID. +PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){ + if (PPID < 0) { + assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() && + "Out-of bounds loaded preprocessed entity"); + return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID); + } + assert(unsigned(PPID) < PreprocessedEntities.size() && + "Out-of bounds local preprocessed entity"); + return PreprocessedEntities[PPID]; } -void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, - MacroDefinition *MD) { - MacroDefinitions[Macro] = MD; +/// \brief Retrieve the loaded preprocessed entity at the given index. +PreprocessedEntity * +PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) { + assert(Index < LoadedPreprocessedEntities.size() && + "Out-of bounds loaded preprocessed entity"); + assert(ExternalSource && "No external source to load from"); + PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index]; + if (!Entity) { + Entity = ExternalSource->ReadPreprocessedEntity(Index); + if (!Entity) // Failed to load. + Entity = new (*this) + PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange()); + } + return Entity; } MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { - llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos + llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos = MacroDefinitions.find(MI); if (Pos == MacroDefinitions.end()) return 0; - return Pos->second; + PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second); + if (Entity->isInvalid()) + return 0; + return cast<MacroDefinition>(Entity); } -void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) { +void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI, + SourceRange Range) { if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID()) return; - if (MacroDefinition *Def = findMacroDefinition(MI)) - PreprocessedEntities.push_back( - new (*this) MacroExpansion(Id.getIdentifierInfo(), - Id.getLocation(), Def)); + if (MI->isBuiltinMacro()) + addPreprocessedEntity( + new (*this) MacroExpansion(Id.getIdentifierInfo(),Range)); + else if (MacroDefinition *Def = findMacroDefinition(MI)) + addPreprocessedEntity( + new (*this) MacroExpansion(Def, Range)); } void PreprocessingRecord::MacroDefined(const Token &Id, const MacroInfo *MI) { SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); MacroDefinition *Def - = new (*this) MacroDefinition(Id.getIdentifierInfo(), - MI->getDefinitionLoc(), - R); - MacroDefinitions[MI] = Def; - PreprocessedEntities.push_back(Def); + = new (*this) MacroDefinition(Id.getIdentifierInfo(), R); + addPreprocessedEntity(Def); + MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1, + /*isLoaded=*/false); } void PreprocessingRecord::MacroUndefined(const Token &Id, const MacroInfo *MI) { - llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos + llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos = MacroDefinitions.find(MI); if (Pos != MacroDefinitions.end()) MacroDefinitions.erase(Pos); @@ -152,12 +290,12 @@ void PreprocessingRecord::MacroUndefined(const Token &Id, void PreprocessingRecord::InclusionDirective( SourceLocation HashLoc, const clang::Token &IncludeTok, - llvm::StringRef FileName, + StringRef FileName, bool IsAngled, const FileEntry *File, clang::SourceLocation EndLoc, - llvm::StringRef SearchPath, - llvm::StringRef RelativePath) { + StringRef SearchPath, + StringRef RelativePath) { InclusionDirective::InclusionKind Kind = InclusionDirective::Include; switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { @@ -185,5 +323,12 @@ void PreprocessingRecord::InclusionDirective( clang::InclusionDirective *ID = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, File, SourceRange(HashLoc, EndLoc)); - PreprocessedEntities.push_back(ID); + addPreprocessedEntity(ID); +} + +size_t PreprocessingRecord::getTotalMemory() const { + return BumpAlloc.getTotalMemory() + + llvm::capacity_in_bytes(MacroDefinitions) + + llvm::capacity_in_bytes(PreprocessedEntities) + + llvm::capacity_in_bytes(LoadedPreprocessedEntities); } diff --git a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp index e7aa286..31662ad 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp @@ -35,6 +35,7 @@ #include "clang/Lex/ScratchBuffer.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" +#include "clang/Lex/ModuleLoader.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" @@ -42,27 +43,83 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Capacity.h" using namespace clang; //===----------------------------------------------------------------------===// ExternalPreprocessorSource::~ExternalPreprocessorSource() { } -Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, - const TargetInfo &target, SourceManager &SM, - HeaderSearch &Headers, +Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts, + const TargetInfo *target, SourceManager &SM, + HeaderSearch &Headers, ModuleLoader &TheModuleLoader, IdentifierInfoLookup* IILookup, - bool OwnsHeaders) + bool OwnsHeaders, + bool DelayInitialization) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), - SourceMgr(SM), - HeaderInfo(Headers), ExternalSource(0), - Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0), - CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0), - CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0), MIChainHead(0), - MICache(0) { - ScratchBuf = new ScratchBuffer(SourceMgr); - CounterValue = 0; // __COUNTER__ starts at 0. + SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), + ExternalSource(0), + Identifiers(opts, IILookup), CodeComplete(0), + CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0), + SkipMainFilePreamble(0, true), CurPPLexer(0), + CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), MacroArgCache(0), + Record(0), MIChainHead(0), MICache(0) +{ OwnsHeaderSearch = OwnsHeaders; + + if (!DelayInitialization) { + assert(Target && "Must provide target information for PP initialization"); + Initialize(*Target); + } +} + +Preprocessor::~Preprocessor() { + assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!"); + assert(((MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty()) || + isCodeCompletionReached()) && + "Preprocessor::HandleEndOfTokenLexer should have cleared those"); + + while (!IncludeMacroStack.empty()) { + delete IncludeMacroStack.back().TheLexer; + delete IncludeMacroStack.back().TheTokenLexer; + IncludeMacroStack.pop_back(); + } + // Free any macro definitions. + for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next) + I->MI.Destroy(); + + // Free any cached macro expanders. + for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) + delete TokenLexerCache[i]; + + // Free any cached MacroArgs. + for (MacroArgs *ArgList = MacroArgCache; ArgList; ) + ArgList = ArgList->deallocate(); + + // Release pragma information. + delete PragmaHandlers; + + // Delete the scratch buffer info. + delete ScratchBuf; + + // Delete the header search info, if we own it. + if (OwnsHeaderSearch) + delete &HeaderInfo; + + delete Callbacks; +} + +void Preprocessor::Initialize(const TargetInfo &Target) { + assert((!this->Target || this->Target == &Target) && + "Invalid override of target information"); + this->Target = &Target; + + // Initialize information about built-ins. + BuiltinInfo.InitializeTarget(Target); + + ScratchBuf = new ScratchBuffer(SourceMgr); + CounterValue = 0; // __COUNTER__ starts at 0. + // Clear stats. NumDirectives = NumDefined = NumUndefined = NumPragma = 0; NumIf = NumElse = NumEndif = 0; @@ -71,33 +128,35 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0; MaxIncludeStackDepth = 0; NumSkipped = 0; - + // Default to discarding comments. KeepComments = false; KeepMacroComments = false; - + SuppressIncludeNotFoundError = false; + AutoModuleImport = false; + // Macro expansion is enabled. DisableMacroExpansion = false; InMacroArgs = false; NumCachedTokenLexers = 0; - + CachedLexPos = 0; - + // We haven't read anything from the external source. ReadMacrosFromExternalSource = false; - + // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. // This gets unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use); - + // Initialize the pragma handlers. - PragmaHandlers = new PragmaNamespace(llvm::StringRef()); + PragmaHandlers = new PragmaNamespace(StringRef()); RegisterBuiltinPragmas(); - + // Initialize builtin macros like __LINE__ and friends. RegisterBuiltinMacros(); - + if(Features.Borland) { Ident__exception_info = getIdentifierInfo("_exception_info"); Ident___exception_info = getIdentifierInfo("__exception_info"); @@ -112,44 +171,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0; Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0; Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0; - } - -} - -Preprocessor::~Preprocessor() { - assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!"); - assert(MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty() && - "Preprocessor::HandleEndOfTokenLexer should have cleared those"); - - while (!IncludeMacroStack.empty()) { - delete IncludeMacroStack.back().TheLexer; - delete IncludeMacroStack.back().TheTokenLexer; - IncludeMacroStack.pop_back(); - } - - // Free any macro definitions. - for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next) - I->MI.Destroy(); - - // Free any cached macro expanders. - for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) - delete TokenLexerCache[i]; - - // Free any cached MacroArgs. - for (MacroArgs *ArgList = MacroArgCache; ArgList; ) - ArgList = ArgList->deallocate(); - - // Release pragma information. - delete PragmaHandlers; - - // Delete the scratch buffer info. - delete ScratchBuf; - - // Delete the header search info, if we own it. - if (OwnsHeaderSearch) - delete &HeaderInfo; - - delete Callbacks; + } } void Preprocessor::setPTHManager(PTHManager* pm) { @@ -172,7 +194,7 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { llvm::errs() << " [ExpandDisabled]"; if (Tok.needsCleaning()) { const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); - llvm::errs() << " [UnClean='" << llvm::StringRef(Start, Tok.getLength()) + llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength()) << "']"; } @@ -228,7 +250,13 @@ Preprocessor::macro_begin(bool IncludeExternalMacros) const { } size_t Preprocessor::getTotalMemory() const { - return BP.getTotalMemory() + MacroExpandedTokens.capacity()*sizeof(Token); + return BP.getTotalMemory() + + llvm::capacity_in_bytes(MacroExpandedTokens) + + Predefines.capacity() /* Predefines buffer. */ + + llvm::capacity_in_bytes(Macros) + + llvm::capacity_in_bytes(PragmaPushMacroInfo) + + llvm::capacity_in_bytes(PoisonReasons) + + llvm::capacity_in_bytes(CommentHandlers); } Preprocessor::macro_iterator @@ -243,15 +271,13 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const { } bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, - unsigned TruncateAtLine, - unsigned TruncateAtColumn) { - using llvm::MemoryBuffer; - - CodeCompletionFile = File; + unsigned CompleteLine, + unsigned CompleteColumn) { + assert(File); + assert(CompleteLine && CompleteColumn && "Starts from 1:1"); + assert(!CodeCompletionFile && "Already set"); - // Okay to clear out the code-completion point by passing NULL. - if (!CodeCompletionFile) - return false; + using llvm::MemoryBuffer; // Load the actual file's contents. bool Invalid = false; @@ -261,7 +287,7 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, // Find the byte position of the truncation point. const char *Position = Buffer->getBufferStart(); - for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { + for (unsigned Line = 1; Line < CompleteLine; ++Line) { for (; *Position; ++Position) { if (*Position != '\r' && *Position != '\n') continue; @@ -275,38 +301,37 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, } } - Position += TruncateAtColumn - 1; + Position += CompleteColumn - 1; - // Truncate the buffer. + // Insert '\0' at the code-completion point. if (Position < Buffer->getBufferEnd()) { - llvm::StringRef Data(Buffer->getBufferStart(), - Position-Buffer->getBufferStart()); - MemoryBuffer *TruncatedBuffer - = MemoryBuffer::getMemBufferCopy(Data, Buffer->getBufferIdentifier()); - SourceMgr.overrideFileContents(File, TruncatedBuffer); + CodeCompletionFile = File; + CodeCompletionOffset = Position - Buffer->getBufferStart(); + + MemoryBuffer *NewBuffer = + MemoryBuffer::getNewUninitMemBuffer(Buffer->getBufferSize() + 1, + Buffer->getBufferIdentifier()); + char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart()); + char *NewPos = std::copy(Buffer->getBufferStart(), Position, NewBuf); + *NewPos = '\0'; + std::copy(Position, Buffer->getBufferEnd(), NewPos+1); + SourceMgr.overrideFileContents(File, NewBuffer); } return false; } -bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { - return CodeCompletionFile && FileLoc.isFileID() && - SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc)) - == CodeCompletionFile; -} - void Preprocessor::CodeCompleteNaturalLanguage() { - SetCodeCompletionPoint(0, 0, 0); - getDiagnostics().setSuppressAllDiagnostics(true); if (CodeComplete) CodeComplete->CodeCompleteNaturalLanguage(); + setCodeCompletionReached(); } /// getSpelling - This method is used to get the spelling of a token into a /// SmallVector. Note that the returned StringRef may not point to the /// supplied buffer if a copy can be avoided. -llvm::StringRef Preprocessor::getSpelling(const Token &Tok, - llvm::SmallVectorImpl<char> &Buffer, +StringRef Preprocessor::getSpelling(const Token &Tok, + SmallVectorImpl<char> &Buffer, bool *Invalid) const { // NOTE: this has to be checked *before* testing for an IdentifierInfo. if (Tok.isNot(tok::raw_identifier)) { @@ -321,22 +346,23 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok, const char *Ptr = Buffer.data(); unsigned Len = getSpelling(Tok, Ptr, Invalid); - return llvm::StringRef(Ptr, Len); + return StringRef(Ptr, Len); } /// CreateString - Plop the specified string into a scratch buffer and return a /// location for it. If specified, the source location provides a source /// location for the token. void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok, - SourceLocation ExpansionLoc) { + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd) { Tok.setLength(Len); const char *DestPtr; SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr); - if (ExpansionLoc.isValid()) - Loc = SourceMgr.createInstantiationLoc(Loc, ExpansionLoc, - ExpansionLoc, Len); + if (ExpansionLocStart.isValid()) + Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart, + ExpansionLocEnd, Len); Tok.setLocation(Loc); // If this is a raw identifier or a literal token, set the pointer data. @@ -407,12 +433,12 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const { IdentifierInfo *II; if (!Identifier.needsCleaning()) { // No cleaning needed, just use the characters from the lexed buffer. - II = getIdentifierInfo(llvm::StringRef(Identifier.getRawIdentifierData(), + II = getIdentifierInfo(StringRef(Identifier.getRawIdentifierData(), Identifier.getLength())); } else { // Cleaning needed, alloca a buffer, clean into it, then use the buffer. llvm::SmallString<64> IdentifierBuffer; - llvm::StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer); + StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer); II = getIdentifierInfo(CleanedStr); } @@ -487,6 +513,17 @@ void Preprocessor::HandleIdentifier(Token &Identifier) { } } + // If this identifier is a keyword in C++11, produce a warning. Don't warn if + // we're not considering macro expansion, since this identifier might be the + // name of a macro. + // FIXME: This warning is disabled in cases where it shouldn't be, like + // "#define constexpr constexpr", "int constexpr;" + if (II.isCXX11CompatKeyword() & !DisableMacroExpansion) { + Diag(Identifier, diag::warn_cxx11_keyword) << II.getName(); + // Don't diagnose this keyword again in this translation unit. + II.setIsCXX11CompatKeyword(false); + } + // C++ 2.11p2: If this is an alternative representation of a C++ operator, // then we act as if it is the actual operator and not the textual // representation of it. @@ -499,6 +536,44 @@ void Preprocessor::HandleIdentifier(Token &Identifier) { // like "#define TY typeof", "TY(1) x". if (II.isExtensionToken() && !DisableMacroExpansion) Diag(Identifier, diag::ext_token_used); + + // If this is the '__import_module__' keyword, note that the next token + // indicates a module name. + if (II.getTokenID() == tok::kw___import_module__ && + !InMacroArgs && !DisableMacroExpansion) { + ModuleImportLoc = Identifier.getLocation(); + CurLexerKind = CLK_LexAfterModuleImport; + } +} + +/// \brief Lex a token following the __import_module__ keyword. +void Preprocessor::LexAfterModuleImport(Token &Result) { + // Figure out what kind of lexer we actually have. + if (CurLexer) + CurLexerKind = CLK_Lexer; + else if (CurPTHLexer) + CurLexerKind = CLK_PTHLexer; + else if (CurTokenLexer) + CurLexerKind = CLK_TokenLexer; + else + CurLexerKind = CLK_CachingLexer; + + // Lex the next token. + Lex(Result); + + // The token sequence + // + // __import_module__ identifier + // + // indicates a module import directive. We already saw the __import_module__ + // keyword, so now we're looking for the identifier. + if (Result.getKind() != tok::identifier) + return; + + // Load the module. + (void)TheModuleLoader.loadModule(ModuleImportLoc, + *Result.getIdentifierInfo(), + Result.getLocation()); } void Preprocessor::AddCommentHandler(CommentHandler *Handler) { @@ -529,6 +604,8 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { return true; } +ModuleLoader::~ModuleLoader() { } + CommentHandler::~CommentHandler() { } CodeCompletionHandler::~CodeCompletionHandler() { } @@ -538,6 +615,7 @@ void Preprocessor::createPreprocessingRecord( if (Record) return; - Record = new PreprocessingRecord(IncludeNestedMacroExpansions); + Record = new PreprocessingRecord(getSourceManager(), + IncludeNestedMacroExpansions); addPPCallbacks(Record); } diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp index 808a81b..0da9ef5 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp @@ -17,6 +17,14 @@ #include "clang/Basic/SourceManager.h" using namespace clang; +PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid) + : PP(pp), FID(fid), InitialNumSLocEntries(0), + ParsingPreprocessorDirective(false), + ParsingFilename(false), LexingRawMode(false) { + if (pp) + InitialNumSLocEntries = pp->getSourceManager().local_sloc_entry_size(); +} + /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and /// (potentially) macro expand the filename. void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) { diff --git a/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp b/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp index 0e98c17..3d363fa 100644 --- a/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp @@ -53,7 +53,7 @@ SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len, // diagnostic points to one. CurBuffer[BytesUsed-1] = '\0'; - return BufferStartLoc.getFileLocWithOffset(BytesUsed-Len-1); + return BufferStartLoc.getLocWithOffset(BytesUsed-Len-1); } void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) { diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp index 3e9e855..dc6d686 100644 --- a/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp @@ -17,42 +17,53 @@ using namespace clang; -/// StartsWithL - Return true if the spelling of this token starts with 'L'. -bool TokenConcatenation::StartsWithL(const Token &Tok) const { - if (!Tok.needsCleaning()) { - SourceManager &SM = PP.getSourceManager(); - return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())) == 'L'; - } +/// IsStringPrefix - Return true if Str is a string prefix. +/// 'L', 'u', 'U', or 'u8'. Including raw versions. +static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) { - if (Tok.getLength() < 256) { - char Buffer[256]; - const char *TokPtr = Buffer; - PP.getSpelling(Tok, TokPtr); - return TokPtr[0] == 'L'; + if (Str[0] == 'L' || + (CPlusPlus0x && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) { + + if (Str.size() == 1) + return true; // "L", "u", "U", and "R" + + // Check for raw flavors. Need to make sure the first character wasn't + // already R. Need CPlusPlus0x check for "LR". + if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus0x) + return true; // "LR", "uR", "UR" + + // Check for "u8" and "u8R" + if (Str[0] == 'u' && Str[1] == '8') { + if (Str.size() == 2) return true; // "u8" + if (Str.size() == 3 && Str[2] == 'R') return true; // "u8R" + } } - return PP.getSpelling(Tok)[0] == 'L'; + return false; } -/// IsIdentifierL - Return true if the spelling of this token is literally -/// 'L'. -bool TokenConcatenation::IsIdentifierL(const Token &Tok) const { +/// IsIdentifierStringPrefix - Return true if the spelling of the token +/// is literally 'L', 'u', 'U', or 'u8'. Including raw versions. +bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const { + const LangOptions &LangOpts = PP.getLangOptions(); + if (!Tok.needsCleaning()) { - if (Tok.getLength() != 1) + if (Tok.getLength() < 1 || Tok.getLength() > 3) return false; SourceManager &SM = PP.getSourceManager(); - return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())) == 'L'; + const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); + return IsStringPrefix(StringRef(Ptr, Tok.getLength()), + LangOpts.CPlusPlus0x); } if (Tok.getLength() < 256) { char Buffer[256]; const char *TokPtr = Buffer; - if (PP.getSpelling(Tok, TokPtr) != 1) - return false; - return TokPtr[0] == 'L'; + unsigned length = PP.getSpelling(Tok, TokPtr); + return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus0x); } - return PP.getSpelling(Tok) == "L"; + return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus0x); } TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) { @@ -132,7 +143,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, // source. If they were, it must be okay to stick them together: if there // were an issue, the tokens would have been lexed differently. if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() && - PrevTok.getLocation().getFileLocWithOffset(PrevTok.getLength()) == + PrevTok.getLocation().getLocWithOffset(PrevTok.getLength()) == Tok.getLocation()) return false; @@ -179,24 +190,19 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, if (Tok.is(tok::numeric_constant)) return GetFirstChar(PP, Tok) != '.'; - if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) /* || - Tok.is(tok::wide_char_literal)*/) + if (Tok.getIdentifierInfo() || Tok.is(tok::wide_string_literal) || + Tok.is(tok::utf8_string_literal) || Tok.is(tok::utf16_string_literal) || + Tok.is(tok::utf32_string_literal) || Tok.is(tok::wide_char_constant) || + Tok.is(tok::utf16_char_constant) || Tok.is(tok::utf32_char_constant)) return true; // If this isn't identifier + string, we're done. if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal)) return false; - // FIXME: need a wide_char_constant! - - // If the string was a wide string L"foo" or wide char L'f', it would - // concat with the previous identifier into fooL"bar". Avoid this. - if (StartsWithL(Tok)) - return true; - // Otherwise, this is a narrow character or string. If the *identifier* - // is a literal 'L', avoid pasting L "foo" -> L"foo". - return IsIdentifierL(PrevTok); + // is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo". + return IsIdentifierStringPrefix(PrevTok); case tok::numeric_constant: return isalnum(FirstChar) || Tok.is(tok::numeric_constant) || FirstChar == '+' || FirstChar == '-' || FirstChar == '.'; diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp index 8ff82f1..a580544 100644 --- a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp @@ -43,7 +43,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) { MacroExpansionStart = SourceLocation(); SourceManager &SM = PP.getSourceManager(); - MacroStartSLocOffset = SM.getNextOffset(); + MacroStartSLocOffset = SM.getNextLocalOffset(); if (NumTokens > 0) { assert(Tokens[0].getLocation().isValid()); @@ -55,12 +55,12 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) { // definition. Tokens that get lexed directly from the definition will // have their locations pointing inside this chunk. This is to avoid // creating separate source location entries for each token. - SourceLocation macroStart = SM.getInstantiationLoc(Tokens[0].getLocation()); - MacroDefStartInfo = SM.getDecomposedLoc(macroStart); - MacroExpansionStart = SM.createInstantiationLoc(macroStart, - ExpandLocStart, - ExpandLocEnd, - Macro->getDefinitionLength(SM)); + MacroDefStart = SM.getExpansionLoc(Tokens[0].getLocation()); + MacroDefLength = Macro->getDefinitionLength(SM); + MacroExpansionStart = SM.createExpansionLoc(MacroDefStart, + ExpandLocStart, + ExpandLocEnd, + MacroDefLength); } // If this is a function-like macro, expand the arguments and change @@ -121,9 +121,8 @@ void TokenLexer::destroy() { /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. void TokenLexer::ExpandFunctionArguments() { - SourceManager &SM = PP.getSourceManager(); - llvm::SmallVector<Token, 128> ResultToks; + SmallVector<Token, 128> ResultToks; // Loop through 'Tokens', expanding them into ResultToks. Keep // track of whether we change anything. If not, no need to keep them. If so, @@ -144,19 +143,22 @@ void TokenLexer::ExpandFunctionArguments() { int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo()); assert(ArgNo != -1 && "Token following # is not an argument?"); - SourceLocation hashInstLoc; - if(ExpandLocStart.isValid()) { - hashInstLoc = getMacroExpansionLocation(CurTok.getLocation()); - assert(hashInstLoc.isValid() && "Expected '#' to come from definition"); - } + SourceLocation ExpansionLocStart = + getExpansionLocForMacroDefLoc(CurTok.getLocation()); + SourceLocation ExpansionLocEnd = + getExpansionLocForMacroDefLoc(Tokens[i+1].getLocation()); Token Res; if (CurTok.is(tok::hash)) // Stringify - Res = ActualArgs->getStringifiedArgument(ArgNo, PP, hashInstLoc); + Res = ActualArgs->getStringifiedArgument(ArgNo, PP, + ExpansionLocStart, + ExpansionLocEnd); else { // 'charify': don't bother caching these. Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), - PP, true, hashInstLoc); + PP, true, + ExpansionLocStart, + ExpansionLocEnd); } // The stringified/charified string leading space flag gets set to match @@ -225,16 +227,9 @@ void TokenLexer::ExpandFunctionArguments() { } if(ExpandLocStart.isValid()) { - SourceLocation curInst = - getMacroExpansionLocation(CurTok.getLocation()); - assert(curInst.isValid() && - "Expected arg identifier to come from definition"); - for (unsigned i = FirstResult, e = ResultToks.size(); i != e; ++i) { - Token &Tok = ResultToks[i]; - Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(), - curInst, - Tok.getLength())); - } + updateLocForMacroArgTokens(CurTok.getLocation(), + ResultToks.begin()+FirstResult, + ResultToks.end()); } // If any tokens were substituted from the argument, the whitespace @@ -282,17 +277,8 @@ void TokenLexer::ExpandFunctionArguments() { } if (ExpandLocStart.isValid()) { - SourceLocation curInst = - getMacroExpansionLocation(CurTok.getLocation()); - assert(curInst.isValid() && - "Expected arg identifier to come from definition"); - for (unsigned i = ResultToks.size() - NumToks, e = ResultToks.size(); - i != e; ++i) { - Token &Tok = ResultToks[i]; - Tok.setLocation(SM.createMacroArgInstantiationLoc(Tok.getLocation(), - curInst, - Tok.getLength())); - } + updateLocForMacroArgTokens(CurTok.getLocation(), + ResultToks.end()-NumToks, ResultToks.end()); } // If this token (the macro argument) was supposed to get leading @@ -417,18 +403,15 @@ void TokenLexer::Lex(Token &Tok) { // that captures all of this. if (ExpandLocStart.isValid() && // Don't do this for token streams. // Check that the token's location was not already set properly. - SM.isBeforeInSourceLocationOffset(Tok.getLocation(), - MacroStartSLocOffset)) { + SM.isBeforeInSLocAddrSpace(Tok.getLocation(), MacroStartSLocOffset)) { SourceLocation instLoc; if (Tok.is(tok::comment)) { - instLoc = SM.createInstantiationLoc(Tok.getLocation(), - ExpandLocStart, - ExpandLocEnd, - Tok.getLength()); + instLoc = SM.createExpansionLoc(Tok.getLocation(), + ExpandLocStart, + ExpandLocEnd, + Tok.getLength()); } else { - instLoc = getMacroExpansionLocation(Tok.getLocation()); - assert(instLoc.isValid() && - "Location for token not coming from definition was not set!"); + instLoc = getExpansionLocForMacroDefLoc(Tok.getLocation()); } Tok.setLocation(instLoc); @@ -469,6 +452,7 @@ void TokenLexer::Lex(Token &Tok) { bool TokenLexer::PasteTokens(Token &Tok) { llvm::SmallString<128> Buffer; const char *ResultTokStrPtr = 0; + SourceLocation StartLoc = Tok.getLocation(); SourceLocation PasteOpLoc; do { // Consume the ## operator. @@ -562,7 +546,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { if (isInvalid) { // Test for the Microsoft extension of /##/ turning into // here on the // error path. - if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) && + if (PP.getLangOptions().MicrosoftExt && Tok.is(tok::slash) && RHS.is(tok::slash)) { HandleMicrosoftCommentPaste(Tok); return true; @@ -574,14 +558,13 @@ bool TokenLexer::PasteTokens(Token &Tok) { // information so that the user knows where it came from. SourceManager &SM = PP.getSourceManager(); SourceLocation Loc = - SM.createInstantiationLoc(PasteOpLoc, ExpandLocStart, - ExpandLocEnd, 2); + SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2); // If we're in microsoft extensions mode, downgrade this from a hard // error to a warning that defaults to an error. This allows // disabling it. PP.Diag(Loc, - PP.getLangOptions().Microsoft ? diag::err_pp_bad_paste_ms - : diag::err_pp_bad_paste) + PP.getLangOptions().MicrosoftExt ? diag::err_pp_bad_paste_ms + : diag::err_pp_bad_paste) << Buffer.str(); } @@ -604,23 +587,20 @@ bool TokenLexer::PasteTokens(Token &Tok) { Tok = Result; } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)); + SourceLocation EndLoc = Tokens[CurToken - 1].getLocation(); + // The token's current location indicate where the token was lexed from. We // need this information to compute the spelling of the token, but any // diagnostics for the expanded token should appear as if the token was - // expanded from the (##) operator. Pull this information together into + // expanded from the full ## expression. Pull this information together into // a new SourceLocation that captures all of this. - if (ExpandLocStart.isValid()) { - SourceManager &SM = PP.getSourceManager(); - SourceLocation pasteLocInst = - getMacroExpansionLocation(PasteOpLoc); - assert(pasteLocInst.isValid() && - "Expected '##' to come from definition"); - - Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(), - pasteLocInst, - pasteLocInst, - Tok.getLength())); - } + SourceManager &SM = PP.getSourceManager(); + if (StartLoc.isFileID()) + StartLoc = getExpansionLocForMacroDefLoc(StartLoc); + if (EndLoc.isFileID()) + EndLoc = getExpansionLocForMacroDefLoc(EndLoc); + Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc, + Tok.getLength())); // Now that we got the result token, it will be subject to expansion. Since // token pasting re-lexes the result token in raw mode, identifier information @@ -666,22 +646,111 @@ void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) { PP.HandleMicrosoftCommentPaste(Tok); } -/// \brief If \arg loc is a FileID and points inside the current macro +/// \brief If \arg loc is a file ID and points inside the current macro /// definition, returns the appropriate source location pointing at the -/// macro expansion source location entry. -SourceLocation TokenLexer::getMacroExpansionLocation(SourceLocation loc) const { +/// macro expansion source location entry, otherwise it returns an invalid +/// SourceLocation. +SourceLocation +TokenLexer::getExpansionLocForMacroDefLoc(SourceLocation loc) const { assert(ExpandLocStart.isValid() && MacroExpansionStart.isValid() && "Not appropriate for token streams"); - assert(loc.isValid()); + assert(loc.isValid() && loc.isFileID()); SourceManager &SM = PP.getSourceManager(); - unsigned relativeOffset; - if (loc.isFileID() && - SM.isInFileID(loc, - MacroDefStartInfo.first, MacroDefStartInfo.second, - Macro->getDefinitionLength(SM), &relativeOffset)) { - return MacroExpansionStart.getFileLocWithOffset(relativeOffset); + assert(SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength) && + "Expected loc to come from the macro definition"); + + unsigned relativeOffset = 0; + SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength, &relativeOffset); + return MacroExpansionStart.getLocWithOffset(relativeOffset); +} + +/// \brief Finds the tokens that are consecutive (from the same FileID) +/// creates a single SLocEntry, and assigns SourceLocations to each token that +/// point to that SLocEntry. e.g for +/// assert(foo == bar); +/// There will be a single SLocEntry for the "foo == bar" chunk and locations +/// for the 'foo', '==', 'bar' tokens will point inside that chunk. +/// +/// \arg begin_tokens will be updated to a position past all the found +/// consecutive tokens. +static void updateConsecutiveMacroArgTokens(SourceManager &SM, + SourceLocation InstLoc, + Token *&begin_tokens, + Token * end_tokens) { + assert(begin_tokens < end_tokens); + + SourceLocation FirstLoc = begin_tokens->getLocation(); + SourceLocation CurLoc = FirstLoc; + + // Compare the source location offset of tokens and group together tokens that + // are close, even if their locations point to different FileIDs. e.g. + // + // |bar | foo | cake | (3 tokens from 3 consecutive FileIDs) + // ^ ^ + // |bar foo cake| (one SLocEntry chunk for all tokens) + // + // we can perform this "merge" since the token's spelling location depends + // on the relative offset. + + Token *NextTok = begin_tokens + 1; + for (; NextTok < end_tokens; ++NextTok) { + int RelOffs; + if (!SM.isInSameSLocAddrSpace(CurLoc, NextTok->getLocation(), &RelOffs)) + break; // Token from different local/loaded location. + // Check that token is not before the previous token or more than 50 + // "characters" away. + if (RelOffs < 0 || RelOffs > 50) + break; + CurLoc = NextTok->getLocation(); } - return SourceLocation(); + // For the consecutive tokens, find the length of the SLocEntry to contain + // all of them. + Token &LastConsecutiveTok = *(NextTok-1); + int LastRelOffs = 0; + SM.isInSameSLocAddrSpace(FirstLoc, LastConsecutiveTok.getLocation(), + &LastRelOffs); + unsigned FullLength = LastRelOffs + LastConsecutiveTok.getLength(); + + // Create a macro expansion SLocEntry that will "contain" all of the tokens. + SourceLocation Expansion = + SM.createMacroArgExpansionLoc(FirstLoc, InstLoc,FullLength); + + // Change the location of the tokens from the spelling location to the new + // expanded location. + for (; begin_tokens < NextTok; ++begin_tokens) { + Token &Tok = *begin_tokens; + int RelOffs = 0; + SM.isInSameSLocAddrSpace(FirstLoc, Tok.getLocation(), &RelOffs); + Tok.setLocation(Expansion.getLocWithOffset(RelOffs)); + } +} + +/// \brief Creates SLocEntries and updates the locations of macro argument +/// tokens to their new expanded locations. +/// +/// \param ArgIdDefLoc the location of the macro argument id inside the macro +/// definition. +/// \param Tokens the macro argument tokens to update. +void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc, + Token *begin_tokens, + Token *end_tokens) { + SourceManager &SM = PP.getSourceManager(); + + SourceLocation InstLoc = + getExpansionLocForMacroDefLoc(ArgIdSpellLoc); + + while (begin_tokens < end_tokens) { + // If there's only one token just create a SLocEntry for it. + if (end_tokens - begin_tokens == 1) { + Token &Tok = *begin_tokens; + Tok.setLocation(SM.createMacroArgExpansionLoc(Tok.getLocation(), + InstLoc, + Tok.getLength())); + return; + } + + updateConsecutiveMacroArgTokens(SM, InstLoc, begin_tokens, end_tokens); + } } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp index 56584c9..fdd7d0f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp @@ -37,11 +37,11 @@ using namespace clang; /// void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer) { llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, - CompleteTranslationUnit, + TUKind, CompletionConsumer)); // Recover resources if we crash before exiting this method. @@ -93,7 +93,7 @@ void clang::ParseAST(Sema &S, bool PrintStats) { Consumer->HandleTopLevelDecl(ADecl.get()); // Process any TopLevelDecls generated by #pragma weak. - for (llvm::SmallVector<Decl*,2>::iterator + for (SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(), E = S.WeakTopLevelDecls().end(); I != E; ++I) Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index f5c6998..b387e9e 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -21,7 +21,9 @@ using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. -Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, +Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, + AttributeList *AccessAttrs, + ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers& VS, ExprResult& Init) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); @@ -34,16 +36,25 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); Decl *FnD; + D.setFunctionDefinition(true); if (D.getDeclSpec().isFriendSpecified()) - // FIXME: Friend templates - FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, + FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, move(TemplateParams)); - else { // FIXME: pass template information through + else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VS, Init.release(), - /*HasInit=*/false, - /*IsDefinition*/true); + VS, /*HasInit=*/false); + if (FnD) { + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, + false, true); + bool TypeSpecContainsAuto + = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + if (Init.get()) + Actions.AddInitializerToDecl(FnD, Init.get(), false, + TypeSpecContainsAuto); + else + Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); + } } HandleMemberFunctionDefaultArgs(D, FnD); @@ -123,30 +134,24 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); - // We may have a constructor initializer or function-try-block here. - if (kind == tok::colon || kind == tok::kw_try) { - // Consume everything up to (and including) the left brace. - if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) { - // We didn't find the left-brace we expected after the - // constructor initializer. - if (Tok.is(tok::semi)) { - // We found a semicolon; complain, consume the semicolon, and - // don't try to parse this method later. - Diag(Tok.getLocation(), diag::err_expected_lbrace); - ConsumeAnyToken(); - delete getCurrentClass().LateParsedDeclarations.back(); - getCurrentClass().LateParsedDeclarations.pop_back(); - return FnD; - } + // Consume everything up to (and including) the left brace of the + // function body. + if (ConsumeAndStoreFunctionPrologue(Toks)) { + // We didn't find the left-brace we expected after the + // constructor initializer. + if (Tok.is(tok::semi)) { + // We found a semicolon; complain, consume the semicolon, and + // don't try to parse this method later. + Diag(Tok.getLocation(), diag::err_expected_lbrace); + ConsumeAnyToken(); + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); + return FnD; } - } else { - // Begin by storing the '{' token. - Toks.push_back(Tok); - ConsumeBrace(); + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } - // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { @@ -398,6 +403,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { if (!Tok.is(tok::l_brace)) { FnScope.Exit(); Actions.ActOnFinishFunctionBody(LM.D, 0); + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); return; } } else @@ -450,7 +457,7 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { } void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { - if (MI.Field->isInvalidDecl()) + if (!MI.Field || MI.Field->isInvalidDecl()) return; // Append the current token at the end of the new token stream so that it @@ -551,8 +558,16 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, ConsumeBrace(); break; + case tok::code_completion: + Toks.push_back(Tok); + ConsumeCodeCompletionToken(); + break; + case tok::string_literal: case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: Toks.push_back(Tok); ConsumeStringToken(); break; @@ -569,3 +584,70 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, isFirstTokenConsumed = false; } } + +/// \brief Consume tokens and store them in the passed token container until +/// we've passed the try keyword and constructor initializers and have consumed +/// the opening brace of the function body. The opening brace will be consumed +/// if and only if there was no error. +/// +/// \return True on error. +bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { + if (Tok.is(tok::kw_try)) { + Toks.push_back(Tok); + ConsumeToken(); + } + if (Tok.is(tok::colon)) { + // Initializers can contain braces too. + Toks.push_back(Tok); + ConsumeToken(); + + while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { + if (Tok.is(tok::eof) || Tok.is(tok::semi)) + return true; + + // Grab the identifier. + if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) + return true; + + tok::TokenKind kind = Tok.getKind(); + Toks.push_back(Tok); + if (kind == tok::l_paren) + ConsumeParen(); + else { + assert(kind == tok::l_brace && "Must be left paren or brace here."); + ConsumeBrace(); + // In C++03, this has to be the start of the function body, which + // means the initializer is malformed. + if (!getLang().CPlusPlus0x) + return false; + } + + // Grab the initializer + if (!ConsumeAndStoreUntil(kind == tok::l_paren ? tok::r_paren : + tok::r_brace, + Toks, /*StopAtSemi=*/true)) + return true; + + // Grab the separating comma, if any. + if (Tok.is(tok::comma)) { + Toks.push_back(Tok); + ConsumeToken(); + } + } + } + + // Grab any remaining garbage to be diagnosed later. We stop when we reach a + // brace: an opening one is the function body, while a closing one probably + // means we've reached the end of the class. + if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, + /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) + return true; + if(Tok.isNot(tok::l_brace)) + return true; + + Toks.push_back(Tok); + ConsumeBrace(); + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 0e17295..2aa178f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -32,12 +33,10 @@ using namespace clang; /// Called type-id in C++. TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context, - ObjCDeclSpec *objcQuals, AccessSpecifier AS, Decl **OwnedType) { // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); - DS.setObjCQualifiers(objcQuals); ParseSpecifierQualifierList(DS, AS); if (OwnedType) *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; @@ -54,6 +53,16 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } + +/// isAttributeLateParsed - Return true if the attribute has arguments that +/// require late parsing. +static bool isAttributeLateParsed(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(II.getName()) +#include "clang/Parse/AttrLateParsed.inc" + .Default(false); +} + + /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -91,7 +100,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, /// a pressing need to implement the 2 token lookahead. void Parser::ParseGNUAttributes(ParsedAttributes &attrs, - SourceLocation *endLoc) { + SourceLocation *endLoc, + LateParsedAttrList *LateAttrs) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); while (Tok.is(tok::kw___attribute)) { @@ -108,7 +118,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) while (Tok.is(tok::identifier) || isDeclarationSpecifier() || Tok.is(tok::comma)) { - if (Tok.is(tok::comma)) { // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) ConsumeToken(); @@ -118,112 +127,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - // Availability attributes have their own grammar. - if (AttrName->isStr("availability")) - ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); - // check if we have a "parameterized" attribute - else if (Tok.is(tok::l_paren)) { - ConsumeParen(); // ignore the left paren loc for now - - if (Tok.is(tok::identifier)) { - IdentifierInfo *ParmName = Tok.getIdentifierInfo(); - SourceLocation ParmLoc = ConsumeToken(); - - if (Tok.is(tok::r_paren)) { - // __attribute__(( mode(byte) )) - ConsumeParen(); // ignore the right paren loc for now - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - ParmName, ParmLoc, 0, 0); - } else if (Tok.is(tok::comma)) { - ConsumeToken(); - // __attribute__(( format(printf, 1, 2) )) - ExprVector ArgExprs(Actions); - bool ArgExprsOk = true; - - // now parse the non-empty comma separated list of expressions - while (1) { - ExprResult ArgExpr(ParseAssignmentExpression()); - if (ArgExpr.isInvalid()) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); - break; - } else { - ArgExprs.push_back(ArgExpr.release()); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - if (ArgExprsOk && Tok.is(tok::r_paren)) { - ConsumeParen(); // ignore the right paren loc for now - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); - } - } - } else { // not an identifier - switch (Tok.getKind()) { - case tok::r_paren: - // parse a possibly empty comma separated list of expressions - // __attribute__(( nonnull() )) - ConsumeParen(); // ignore the right paren loc for now - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); - break; - case tok::kw_char: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_float: - case tok::kw_double: - case tok::kw_void: - case tok::kw_typeof: { - AttributeList *attr - = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); - if (attr->getKind() == AttributeList::AT_IBOutletCollection) - Diag(Tok, diag::err_iboutletcollection_builtintype); - // If it's a builtin type name, eat it and expect a rparen - // __attribute__(( vec_type_hint(char) )) - ConsumeToken(); - if (Tok.is(tok::r_paren)) - ConsumeParen(); - break; - } - default: - // __attribute__(( aligned(16) )) - ExprVector ArgExprs(Actions); - bool ArgExprsOk = true; - - // now parse the list of expressions - while (1) { - ExprResult ArgExpr(ParseAssignmentExpression()); - if (ArgExpr.isInvalid()) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); - break; - } else { - ArgExprs.push_back(ArgExpr.release()); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - // Match the ')'. - if (ArgExprsOk && Tok.is(tok::r_paren)) { - ConsumeParen(); // ignore the right paren loc for now - attrs.addNew(AttrName, AttrNameLoc, 0, - AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size()); - } - break; - } + if (Tok.is(tok::l_paren)) { + // handle "parameterized" attributes + if (LateAttrs && !ClassStack.empty() && + isAttributeLateParsed(*AttrName)) { + // Delayed parsing is only available for attributes that occur + // in certain locations within a class scope. + LateParsedAttribute *LA = + new LateParsedAttribute(this, *AttrName, AttrNameLoc); + LateAttrs->push_back(LA); + getCurrentClass().LateParsedDeclarations.push_back(LA); + + // consume everything up to and including the matching right parens + ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); + + Token Eof; + Eof.startToken(); + Eof.setLocation(Tok.getLocation()); + LA->Toks.push_back(Eof); + } else { + ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc); } } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, @@ -241,6 +164,133 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } + +/// Parse the arguments to a parameterized GNU attribute +void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + // Availability attributes have their own grammar. + if (AttrName->isStr("availability")) { + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } + // Thread safety attributes fit into the FIXME case above, so we + // just parse the arguments as a list of expressions + if (IsThreadSafetyAttribute(AttrName->getName())) { + ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } + + ConsumeParen(); // ignore the left paren loc for now + + if (Tok.is(tok::identifier)) { + IdentifierInfo *ParmName = Tok.getIdentifierInfo(); + SourceLocation ParmLoc = ConsumeToken(); + + if (Tok.is(tok::r_paren)) { + // __attribute__(( mode(byte) )) + SourceLocation RParen = ConsumeParen(); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, + ParmName, ParmLoc, 0, 0); + } else if (Tok.is(tok::comma)) { + ConsumeToken(); + // __attribute__(( format(printf, 1, 2) )) + ExprVector ArgExprs(Actions); + bool ArgExprsOk = true; + + // now parse the non-empty comma separated list of expressions + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + ArgExprsOk = false; + SkipUntil(tok::r_paren); + break; + } else { + ArgExprs.push_back(ArgExpr.release()); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + if (ArgExprsOk && Tok.is(tok::r_paren)) { + SourceLocation RParen = ConsumeParen(); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); + } + } + } else { // not an identifier + switch (Tok.getKind()) { + case tok::r_paren: { + // parse a possibly empty comma separated list of expressions + // __attribute__(( nonnull() )) + SourceLocation RParen = ConsumeParen(); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); + break; + } + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw_typeof: { + // If it's a builtin type name, eat it and expect a rparen + // __attribute__(( vec_type_hint(char) )) + SourceLocation EndLoc = ConsumeToken(); + if (Tok.is(tok::r_paren)) + EndLoc = ConsumeParen(); + AttributeList *attr + = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, EndLoc), 0, + AttrNameLoc, 0, SourceLocation(), 0, 0); + if (attr->getKind() == AttributeList::AT_IBOutletCollection) + Diag(Tok, diag::err_iboutletcollection_builtintype); + break; + } + default: + // __attribute__(( aligned(16) )) + ExprVector ArgExprs(Actions); + bool ArgExprsOk = true; + + // now parse the list of expressions + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + ArgExprsOk = false; + SkipUntil(tok::r_paren); + break; + } else { + ArgExprs.push_back(ArgExpr.release()); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + // Match the ')'. + if (ArgExprsOk && Tok.is(tok::r_paren)) { + SourceLocation RParen = ConsumeParen(); + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, + AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); + } + break; + } + } +} + + /// ParseMicrosoftDeclSpec - Parse an __declspec construct /// /// [MS] decl-specifier: @@ -297,10 +347,13 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { // FIXME: Allow Sema to distinguish between these and real attributes! while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || - Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) { + Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || + Tok.is(tok::kw___ptr32) || + Tok.is(tok::kw___unaligned)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) + if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || + Tok.is(tok::kw___ptr32)) // FIXME: Support these properly! continue; attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, @@ -511,12 +564,11 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, AvailabilityChange Changes[Unknown]; // Opening '('. - SourceLocation LParenLoc; - if (!Tok.is(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen); return; } - LParenLoc = ConsumeParen(); // Parse the platform name, if (Tok.isNot(tok::identifier)) { @@ -614,12 +666,11 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, } while (true); // Closing ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - if (RParenLoc.isInvalid()) + if (T.consumeClose()) return; if (endLoc) - *endLoc = RParenLoc; + *endLoc = T.getCloseLocation(); // The 'unavailable' availability cannot be combined with any other // availability changes. Make sure that hasn't happened. @@ -641,7 +692,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, } // Record this attribute - attrs.addNew(&Availability, AvailabilityLoc, + attrs.addNew(&Availability, + SourceRange(AvailabilityLoc, T.getCloseLocation()), 0, SourceLocation(), Platform, PlatformLoc, Changes[Introduced], @@ -650,6 +702,172 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, UnavailableLoc, false, false); } + +// Late Parsed Attributes: +// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods + +void Parser::LateParsedDeclaration::ParseLexedAttributes() {} + +void Parser::LateParsedClass::ParseLexedAttributes() { + Self->ParseLexedAttributes(*Class); +} + +void Parser::LateParsedAttribute::ParseLexedAttributes() { + Self->ParseLexedAttribute(*this); +} + +/// Wrapper class which calls ParseLexedAttribute, after setting up the +/// scope appropriately. +void Parser::ParseLexedAttributes(ParsingClass &Class) { + // Deal with templates + // FIXME: Test cases to make sure this does the right thing for templates. + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + // Set or update the scope flags to include Scope::ThisScope. + bool AlreadyHasClassScope = Class.TopLevelClass; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; + ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); + ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + + for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) { + Class.LateParsedDeclarations[i]->ParseLexedAttributes(); + } +} + +/// \brief Finish parsing an attribute for which parsing was delayed. +/// This will be called at the end of parsing a class declaration +/// for each LateParsedAttribute. We consume the saved tokens and +/// create an attribute with the arguments filled in. We add this +/// to the Attribute list for the decl. +void Parser::ParseLexedAttribute(LateParsedAttribute &LA) { + // Save the current token position. + SourceLocation OrigLoc = Tok.getLocation(); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LA.Toks.push_back(Tok); + PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); + // Consume the previously pushed token. + ConsumeAnyToken(); + + ParsedAttributes Attrs(AttrFactory); + SourceLocation endLoc; + + // If the Decl is templatized, add template parameters to scope. + bool HasTemplateScope = LA.D && LA.D->isTemplateDecl(); + ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.CurScope, LA.D); + + // If the Decl is on a function, add function parameters to the scope. + bool HasFunctionScope = LA.D && LA.D->isFunctionOrFunctionTemplate(); + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); + if (HasFunctionScope) + Actions.ActOnReenterFunctionContext(Actions.CurScope, LA.D); + + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + + if (HasFunctionScope) { + Actions.ActOnExitFunctionContext(); + FnScope.Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) { + TempScope.Exit(); + } + + // Late parsed attributes must be attached to Decls by hand. If the + // LA.D is not set, then this was not done properly. + assert(LA.D && "No decl attached to late parsed attribute"); + Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs); + + if (Tok.getLocation() != OrigLoc) { + // Due to a parsing error, we either went over the cached tokens or + // there are still cached tokens left, so we skip the leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + OrigLoc)) + while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } +} + +/// \brief Wrapper around a case statement checking if AttrName is +/// one of the thread safety attributes +bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ + return llvm::StringSwitch<bool>(AttrName) + .Case("guarded_by", true) + .Case("guarded_var", true) + .Case("pt_guarded_by", true) + .Case("pt_guarded_var", true) + .Case("lockable", true) + .Case("scoped_lockable", true) + .Case("no_thread_safety_analysis", true) + .Case("acquired_after", true) + .Case("acquired_before", true) + .Case("exclusive_lock_function", true) + .Case("shared_lock_function", true) + .Case("exclusive_trylock_function", true) + .Case("shared_trylock_function", true) + .Case("unlock_function", true) + .Case("lock_returned", true) + .Case("locks_excluded", true) + .Case("exclusive_locks_required", true) + .Case("shared_locks_required", true) + .Default(false); +} + +/// \brief Parse the contents of thread safety attributes. These +/// should always be parsed as an expression list. +/// +/// We need to special case the parsing due to the fact that if the first token +/// of the first argument is an identifier, the main parse loop will store +/// that token as a "parameter" and the rest of +/// the arguments will be added to a list of "arguments". However, +/// subsequent tokens in the first argument are lost. We instead parse each +/// argument as an expression and add all arguments to the list of "arguments". +/// In future, we will take advantage of this special case to also +/// deal with some argument scoping issues here (for example, referring to a +/// function parameter in the attribute on that function). +void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprVector ArgExprs(Actions); + bool ArgExprsOk = true; + + // now parse the list of expressions + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + ArgExprsOk = false; + T.consumeClose(); + break; + } else { + ArgExprs.push_back(ArgExpr.release()); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + // Match the ')'. + if (ArgExprsOk && !T.consumeClose()) { + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); + } + if (EndLoc) + *EndLoc = T.getCloseLocation(); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; @@ -676,6 +894,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs) { ParenBraceBracketBalancer BalancerRAIIObj(*this); + // Must temporarily exit the objective-c container scope for + // parsing c none objective-c decls. + ObjCDeclContextSwitch ObjCDC(*this); Decl *SingleDecl = 0; Decl *OwnedType = 0; @@ -832,7 +1053,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); } - llvm::SmallVector<Decl *, 8> DeclsInGroup; + SmallVector<Decl *, 8> DeclsInGroup; Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); D.complete(FirstDecl); if (FirstDecl) @@ -998,9 +1219,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); - ConsumeCodeCompletionToken(); - SkipUntil(tok::comma, true, true); - return ThisDecl; + cutOffParsing(); + return 0; } ExprResult Init(ParseInitializer()); @@ -1019,7 +1239,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ExprVector Exprs(Actions); CommaLocsTy CommaLocs; @@ -1037,7 +1259,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } else { // Match the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); @@ -1047,9 +1269,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExitScope(); } - Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc, + Actions.AddCXXDirectInitializerToDecl(ThisDecl, T.getOpenLocation(), move_arg(Exprs), - RParenLoc, + T.getCloseLocation(), TypeContainsAuto); } } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { @@ -1090,6 +1312,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) { /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. + /// TODO: diagnose attribute-specifiers and alignment-specifiers. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // Validate declspec for type-name. @@ -1273,12 +1496,70 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_normal; } +/// ParseAlignArgument - Parse the argument to an alignment-specifier. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C1X/C++0x] type-id +/// [C1X] constant-expression +/// [C++0x] assignment-expression +ExprResult Parser::ParseAlignArgument(SourceLocation Start) { + if (isTypeIdInParens()) { + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + SourceLocation TypeLoc = Tok.getLocation(); + ParsedType Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); + } else + return ParseConstantExpression(); +} + +/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the +/// attribute to Attrs. +/// +/// alignment-specifier: +/// [C1X] '_Alignas' '(' type-id ')' +/// [C1X] '_Alignas' '(' constant-expression ')' +/// [C++0x] 'alignas' '(' type-id ')' +/// [C++0x] 'alignas' '(' assignment-expression ')' +void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc) { + assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && + "Not an alignment-specifier!"); + + SourceLocation KWLoc = Tok.getLocation(); + ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return; + + ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation()); + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + T.consumeClose(); + if (endLoc) + *endLoc = T.getCloseLocation(); + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, + 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true); +} + /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] +/// [C1X] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] +/// [Clang] '__module_private__' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' @@ -1316,6 +1597,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, switch (Tok.getKind()) { default: DoneWithDeclSpec: + // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt] + MaybeParseCXX0XAttributes(DS.getAttributes()); + // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); @@ -1337,8 +1621,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.CodeCompleteDeclSpec(getCurScope(), DS, AllowNonIdentifiers, AllowNestedNameSpecifiers); - ConsumeCodeCompletionToken(); - return; + return cutOffParsing(); } if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) @@ -1352,8 +1635,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, CCC = Sema::PCC_ObjCImplementation; Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); - ConsumeCodeCompletionToken(); - return; + return cutOffParsing(); } case tok::coloncolon: // ::foo::bar @@ -1641,11 +1923,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___w64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___unaligned: ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; @@ -1661,49 +1945,47 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // storage-class-specifier case tok::kw_typedef: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, + PrevSpec, DiagID); break; case tok::kw_extern: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "extern"; - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, + PrevSpec, DiagID); break; case tok::kw___private_extern__: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, - PrevSpec, DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern, + Loc, PrevSpec, DiagID); break; case tok::kw_static: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "static"; - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, + PrevSpec, DiagID); break; case tok::kw_auto: if (getLang().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID); if (!isInvalid) - Diag(Tok, diag::auto_storage_class) + Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); - } - else + } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); - } - else - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, - DiagID, getLang()); + } else + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID); break; case tok::kw_register: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, + PrevSpec, DiagID); break; case tok::kw_mutable: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec, - DiagID, getLang()); + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc, + PrevSpec, DiagID); break; case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); @@ -1720,6 +2002,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; + // alignment-specifier + case tok::kw__Alignas: + if (!getLang().C1X) + Diag(Tok, diag::ext_c1x_alignas); + ParseAlignmentSpecifier(DS.getAttributes()); + continue; + // friend case tok::kw_friend: if (DSContext == DSC_class) @@ -1731,6 +2020,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } break; + // Modules + case tok::kw___module_private__: + isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID); + break; + // constexpr case tok::kw_constexpr: isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); @@ -1781,6 +2075,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, + DiagID); + break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); @@ -1890,6 +2188,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___underlying_type: ParseUnderlyingTypeSpecifier(DS); + continue; + + case tok::kw__Atomic: + ParseAtomicSpecifier(DS); + continue; // OpenCL qualifiers: case tok::kw_private: @@ -2004,7 +2307,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw_typename: // typename foo::bar // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false, + /*NeedType=*/true)) return true; if (Tok.is(tok::identifier)) return false; @@ -2017,7 +2321,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false, + /*NeedType=*/true)) return true; return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, TemplateInfo, SuppressDeclarations); @@ -2082,6 +2387,9 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw_int: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); + break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; @@ -2166,6 +2474,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, ParseUnderlyingTypeSpecifier(DS); return true; + case tok::kw__Atomic: + ParseAtomicSpecifier(DS); + return true; + // OpenCL qualifiers: case tok::kw_private: if (!getLang().OpenCL) @@ -2182,18 +2494,24 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // C++0x auto support. case tok::kw_auto: - if (!getLang().CPlusPlus0x) + // This is only called in situations where a storage-class specifier is + // illegal, so we can assume an auto type specifier was intended even in + // C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate + // extension diagnostic. + if (!getLang().CPlusPlus) return false; isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); break; case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___w64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___unaligned: ParseMicrosoftTypeAttributes(DS.getAttributes()); return true; @@ -2236,6 +2554,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, /// void Parser:: ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { + if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. @@ -2314,7 +2633,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union body"); - SourceLocation LBraceLoc = ConsumeBrace(); + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) + return; ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); @@ -2325,7 +2646,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); - llvm::SmallVector<Decl *, 32> FieldDecls; + SmallVector<Decl *, 32> FieldDecls; // While we still have something to read, read the declarations in the struct. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -2347,10 +2668,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, struct CFieldCallback : FieldCallback { Parser &P; Decl *TagDecl; - llvm::SmallVectorImpl<Decl *> &FieldDecls; + SmallVectorImpl<Decl *> &FieldDecls; CFieldCallback(Parser &P, Decl *TagDecl, - llvm::SmallVectorImpl<Decl *> &FieldDecls) : + SmallVectorImpl<Decl *> &FieldDecls) : P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} virtual Decl *invoke(FieldDeclarator &FD) { @@ -2378,7 +2699,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SkipUntil(tok::semi, true); continue; } - llvm::SmallVector<Decl *, 16> Fields; + SmallVector<Decl *, 16> Fields; Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); @@ -2400,18 +2721,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } } - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. MaybeParseGNUAttributes(attrs); Actions.ActOnFields(getCurScope(), - RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), - LBraceLoc, RBraceLoc, + RecordLoc, TagDecl, FieldDecls, + T.getOpenLocation(), T.getCloseLocation(), attrs.getList()); StructScope.Exit(); - Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc); + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, + T.getCloseLocation()); } /// ParseEnumSpecifier @@ -2448,7 +2770,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::code_completion)) { // Code completion for an enum name. Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } bool IsScopedEnum = false; @@ -2465,7 +2787,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - bool AllowFixedUnderlyingType = getLang().CPlusPlus0x || getLang().Microsoft; + bool AllowFixedUnderlyingType + = getLang().CPlusPlus0x || getLang().MicrosoftExt || getLang().ObjC2; CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLang().CPlusPlus) { @@ -2568,7 +2891,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SourceRange Range; BaseType = ParseTypeName(&Range); - if (!getLang().CPlusPlus0x) + if (!getLang().CPlusPlus0x && !getLang().ObjC2) Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) << Range; } @@ -2615,7 +2938,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), - AS, + AS, DS.getModulePrivateSpecLoc(), MultiTemplateParamsArg(Actions), Owned, IsDependent, IsScopedEnum, IsScopedUsingClassTag, BaseType); @@ -2681,13 +3004,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ParseScope EnumScope(this, Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); - SourceLocation LBraceLoc = ConsumeBrace(); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); // C does not allow an empty enumerator-list, C++ does [dcl.enum]. if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) Diag(Tok, diag::error_empty_enum); - llvm::SmallVector<Decl *, 32> EnumConstantDecls; + SmallVector<Decl *, 32> EnumConstantDecls; Decl *LastEnumConstDecl = 0; @@ -2738,18 +3062,20 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { } // Eat the }. - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + T.consumeClose(); // If attributes exist after the identifier list, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, - EnumConstantDecls.data(), EnumConstantDecls.size(), - getCurScope(), attrs.getList()); + Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), + EnumDecl, EnumConstantDecls.data(), + EnumConstantDecls.size(), getCurScope(), + attrs.getList()); EnumScope.Exit(); - Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, RBraceLoc); + Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, + T.getCloseLocation()); } /// isTypeSpecifierQualifier - Return true if the current token could be the @@ -2797,6 +3123,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: @@ -2866,6 +3193,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: @@ -2901,7 +3229,9 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___pascal: + case tok::kw___unaligned: case tok::kw___private: case tok::kw___local: @@ -2915,6 +3245,10 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_private: return getLang().OpenCL; + + // C1x _Atomic() + case tok::kw__Atomic: + return true; } } @@ -2976,6 +3310,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_register: case tok::kw___thread: + // Modules + case tok::kw___module_private__: + // type-specifiers case tok::kw_short: case tok::kw_long: @@ -2991,6 +3328,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: @@ -3031,6 +3369,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_decltype: return true; + // C1x _Atomic() + case tok::kw__Atomic: + return true; + // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: return getLang().ObjC1; @@ -3047,8 +3389,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___forceinline: case tok::kw___pascal: + case tok::kw___unaligned: case tok::kw___private: case tok::kw___local: @@ -3148,8 +3492,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, switch (Tok.getKind()) { case tok::code_completion: Actions.CodeCompleteTypeQualifiers(DS); - ConsumeCodeCompletionToken(); - break; + return cutOffParsing(); case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, @@ -3180,10 +3523,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::kw___w64: case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___unaligned: if (VendorAttributesAllowed) { ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; @@ -3548,7 +3893,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { break; } ParsedAttributes attrs(AttrFactory); - ParseFunctionDeclarator(ConsumeParen(), D, attrs); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ParseFunctionDeclarator(D, attrs, T); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); } else { @@ -3571,7 +3918,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { /// parameter-type-list[opt] ')' /// void Parser::ParseParenDeclarator(Declarator &D) { - SourceLocation StartLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + assert(!D.isPastIdentifier() && "Should be called before passing identifier"); // Eat any attributes before we look at whether this is a grouping or function @@ -3596,7 +3945,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { // Eat any Microsoft extensions. if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || - Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { + Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) || + Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { ParseMicrosoftTypeAttributes(attrs); } // Eat any Borland extensions. @@ -3633,9 +3983,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. - SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc); - D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), - attrs, EndLoc); + T.consumeClose(); + D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); D.setGroupingParens(hadGroupingParens); return; @@ -3647,7 +3998,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // ParseFunctionDeclarator to handle of argument list. D.SetIdentifier(0, Tok.getLocation()); - ParseFunctionDeclarator(StartLoc, D, attrs, RequiresArg); + ParseFunctionDeclarator(D, attrs, T, RequiresArg); } /// ParseFunctionDeclarator - We are after the identifier and have parsed the @@ -3668,8 +4019,9 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// dynamic-exception-specification /// noexcept-specification /// -void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, +void Parser::ParseFunctionDeclarator(Declarator &D, ParsedAttributes &attrs, + BalancedDelimiterTracker &Tracker, bool RequiresArg) { // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); @@ -3678,7 +4030,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Otherwise, it is treated as a K&R-style function. bool HasProto = false; // Build up an array of information about the parsed arguments. - llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; + SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; // Remember where we see an ellipsis, if any. SourceLocation EllipsisLoc; @@ -3687,20 +4039,20 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, SourceLocation RefQualifierLoc; ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; - llvm::SmallVector<ParsedType, 2> DynamicExceptions; - llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + SmallVector<ParsedType, 2> DynamicExceptions; + SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; ParsedType TrailingReturnType; SourceLocation EndLoc; - if (isFunctionDeclaratorIdentifierList()) { if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); ParseFunctionDeclaratorIdentifierList(D, ParamInfo); - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + Tracker.consumeClose(); + EndLoc = Tracker.getCloseLocation(); } else { // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. @@ -3715,7 +4067,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, HasProto = ParamInfo.size() || getLang().CPlusPlus; // If we have the closing ')', eat it. - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + Tracker.consumeClose(); + EndLoc = Tracker.getCloseLocation(); if (getLang().CPlusPlus) { MaybeParseCXX0XAttributes(attrs); @@ -3745,7 +4098,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse trailing-return-type[opt]. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { - TrailingReturnType = ParseTrailingReturnType().get(); + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + EndLoc = Range.getEnd(); } } @@ -3768,7 +4124,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - LParenLoc, EndLoc, D, + Tracker.getOpenLocation(), + EndLoc, D, TrailingReturnType), attrs, EndLoc); } @@ -3811,7 +4168,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() { /// void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, - llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) { + SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) { // If there was no identifier specified for the declarator, either we are in // an abstract-declarator, or we are in a parameter declarator which was found // to be abstract. In abstract-declarators, identifier lists are not valid: @@ -3890,7 +4247,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( void Parser::ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &attrs, - llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, + SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, SourceLocation &EllipsisLoc) { while (1) { @@ -3902,9 +4259,9 @@ void Parser::ParseParameterDeclarationClause( // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS(AttrFactory); - + // Skip any Microsoft attributes before a param. - if (getLang().Microsoft && Tok.is(tok::l_square)) + if (getLang().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(DS.getAttributes()); SourceLocation DSStart = Tok.getLocation(); @@ -4036,20 +4393,22 @@ void Parser::ParseParameterDeclarationClause( /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' void Parser::ParseBracketDeclarator(Declarator &D) { - SourceLocation StartLoc = ConsumeBracket(); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); // C array syntax has many features, but by-far the most common is [] and [4]. // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { - SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed the empty array type. ExprResult NumElements; D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, - StartLoc, EndLoc), - attrs, EndLoc); + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); return; } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { @@ -4057,15 +4416,16 @@ void Parser::ParseBracketDeclarator(Declarator &D) { ExprResult ExprRes(Actions.ActOnNumericConstant(Tok)); ConsumeToken(); - SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(), - StartLoc, EndLoc), - attrs, EndLoc); + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); return; } @@ -4122,7 +4482,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { return; } - SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); @@ -4131,8 +4491,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) { D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, NumElements.release(), - StartLoc, EndLoc), - attrs, EndLoc); + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); } /// [GNU] typeof-specifier: @@ -4190,6 +4551,41 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } +/// [C1X] atomic-specifier: +/// _Atomic ( type-name ) +/// +void Parser::ParseAtomicSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); + + SourceLocation StartLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) { + SkipUntil(tok::r_paren); + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + T.consumeClose(); + + if (T.getCloseLocation().isInvalid()) + return; + + DS.setTypeofParensRange(T.getRange()); + DS.SetRangeEnd(T.getCloseLocation()); + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + /// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called /// from TryAltiVecVectorToken. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 172049c..4339047 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -52,10 +52,12 @@ Decl *Parser::ParseNamespace(unsigned Context, SourceLocation InlineLoc) { assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. - + ObjCDeclContextSwitch ObjCDC(*this); + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceDecl(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } SourceLocation IdentLoc; @@ -89,12 +91,12 @@ Decl *Parser::ParseNamespace(unsigned Context, if (InlineLoc.isValid()) Diag(InlineLoc, diag::err_inline_namespace_alias) << FixItHint::CreateRemoval(InlineLoc); - return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } - if (Tok.isNot(tok::l_brace)) { + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) { if (!ExtraIdent.empty()) { Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); @@ -104,8 +106,6 @@ Decl *Parser::ParseNamespace(unsigned Context, return 0; } - SourceLocation LBrace = ConsumeBrace(); - if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || getCurScope()->getFnParent()) { @@ -113,7 +113,7 @@ Decl *Parser::ParseNamespace(unsigned Context, Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } - Diag(LBrace, diag::err_namespace_nonnamespace_scope); + Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); return 0; } @@ -156,23 +156,23 @@ Decl *Parser::ParseNamespace(unsigned Context, Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc, - IdentLoc, Ident, LBrace, attrs.getList()); + IdentLoc, Ident, T.getOpenLocation(), + attrs.getList()); PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); - SourceLocation RBraceLoc; // Parse the contents of the namespace. This includes parsing recovery on // any improperly nested namespaces. ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, - InlineLoc, LBrace, attrs, RBraceLoc); + InlineLoc, attrs, T); // Leave the namespace scope. NamespaceScope.Exit(); - Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); + DeclEnd = T.getCloseLocation(); + Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd); - DeclEnd = RBraceLoc; return NamespcDecl; } @@ -181,9 +181,8 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, std::vector<IdentifierInfo*>& Ident, std::vector<SourceLocation>& NamespaceLoc, unsigned int index, SourceLocation& InlineLoc, - SourceLocation& LBrace, ParsedAttributes& attrs, - SourceLocation& RBraceLoc) { + BalancedDelimiterTracker &Tracker) { if (index == Ident.size()) { while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); @@ -191,7 +190,10 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } - RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); + + // The caller is what called check -- we are simply calling + // the close for it. + Tracker.consumeClose(); return; } @@ -201,14 +203,15 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), NamespaceLoc[index], IdentLoc[index], - Ident[index], LBrace, attrs.getList()); + Ident[index], Tracker.getOpenLocation(), + attrs.getList()); ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, - LBrace, attrs, RBraceLoc); + attrs, Tracker); NamespaceScope.Exit(); - Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); + Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation()); } /// ParseNamespaceAlias - Parse the part after the '=' in a namespace @@ -224,7 +227,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } CXXScopeSpec SS; @@ -262,7 +266,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallString<8> LangBuffer; bool Invalid = false; - llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); + StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); if (Invalid) return 0; @@ -296,7 +300,8 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { ProhibitAttributes(attrs); - SourceLocation LBrace = ConsumeBrace(); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); @@ -304,9 +309,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { ParseExternalDeclaration(attrs); } - SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); + T.consumeClose(); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, - RBrace); + T.getCloseLocation()); } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or @@ -317,13 +322,15 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, ParsedAttributesWithRange &attrs, Decl **OwnedType) { assert(Tok.is(tok::kw_using) && "Not using token"); - + ObjCDeclContextSwitch ObjCDC(*this); + // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsing(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } // 'using namespace' means this is a using-directive. @@ -344,7 +351,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, ProhibitAttributes(attrs); return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, - AS_none, OwnedType); + AS_none, OwnedType); } /// ParseUsingDirective - Parse C++ using-directive, assumes @@ -368,7 +375,8 @@ Decl *Parser::ParseUsingDirective(unsigned Context, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsingDirective(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } CXXScopeSpec SS; @@ -514,7 +522,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : - Declarator::AliasDeclContext, 0, AS, OwnedType); + Declarator::AliasDeclContext, AS, OwnedType); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); @@ -540,6 +548,15 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + // "typename" keyword is allowed for identifiers only, + // because it may be a type definition. + if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) + << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); + // Proceed parsing, but reset the IsTypeName flag. + IsTypeName = false; + } + if (IsAliasDecl) { TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; MultiTemplateParamsArg TemplateParamsArg(Actions, @@ -571,13 +588,12 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ SourceLocation StaticAssertLoc = ConsumeToken(); - if (Tok.isNot(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen); return 0; } - SourceLocation LParenLoc = ConsumeParen(); - ExprResult AssertExpr(ParseConstantExpression()); if (AssertExpr.isInvalid()) { SkipUntil(tok::semi); @@ -597,7 +613,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (AssertMessage.isInvalid()) return 0; - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); DeclEnd = Tok.getLocation(); ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); @@ -605,7 +621,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.take(), AssertMessage.take(), - RParenLoc); + T.getCloseLocation()); } /// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. @@ -616,11 +632,9 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier"); SourceLocation StartLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "decltype")) { - SkipUntil(tok::r_paren); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + "decltype", tok::r_paren)) { return; } @@ -637,13 +651,8 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { } // Match the ')' - SourceLocation RParenLoc; - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, LParenLoc); - - if (RParenLoc.isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return; const char *PrevSpec = 0; @@ -659,11 +668,9 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { "Not an underlying type specifier"); SourceLocation StartLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "__underlying_type")) { - SkipUntil(tok::r_paren); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + "__underlying_type", tok::r_paren)) { return; } @@ -674,13 +681,8 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { } // Match the ')' - SourceLocation RParenLoc; - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, LParenLoc); - - if (RParenLoc.isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return; const char *PrevSpec = 0; @@ -851,7 +853,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::code_completion)) { // Code completion for a struct, class, or union name. Actions.CodeCompleteTag(getCurScope(), TagType); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } // C++03 [temp.explicit] 14.7.2/8: @@ -901,7 +903,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.is(tok::kw___is_signed) || Tok.is(tok::kw___is_unsigned) || Tok.is(tok::kw___is_void))) { - // GNU libstdc++ 4.2 and libc++ uaw certain intrinsic names as the + // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct // X", make X into a normal identifier rather than a keyword, to @@ -1136,7 +1138,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Build the class template specialization. TagOrTempResult = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK, - StartLoc, SS, + StartLoc, DS.getModulePrivateSpecLoc(), SS, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, @@ -1188,6 +1190,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, + DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, false, false, clang::TypeResult()); @@ -1264,7 +1267,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, case tok::kw_typedef: // struct foo {...} typedef x; case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; - case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_constexpr: // struct foo {...} constexpr x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, // almost no one actually writes code like this. If we see one of these, @@ -1321,7 +1325,7 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { ConsumeToken(); // Build up an array of parsed base specifiers. - llvm::SmallVector<CXXBaseSpecifier *, 8> BaseInfo; + SmallVector<CXXBaseSpecifier *, 8> BaseInfo; while (true) { // Parse a base-specifier. @@ -1565,7 +1569,6 @@ bool Parser::isCXX0XFinalKeyword() const { /// virt-specifier: /// override /// final -/// new /// /// pure-specifier: /// '= 0' @@ -1574,6 +1577,7 @@ bool Parser::isCXX0XFinalKeyword() const { /// '=' constant-expression /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + AttributeList *AccessAttrs, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { if (Tok.is(tok::at)) { @@ -1640,7 +1644,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, "Nested template improperly parsed?"); SourceLocation DeclEnd; ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, - AS); + AS, AccessAttrs); return; } @@ -1649,7 +1653,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags); + return ParseCXXClassMemberDeclaration(AS, AccessAttrs, + TemplateInfo, TemplateDiags); } // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it @@ -1699,7 +1704,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); VirtSpecifiers VS; - ExprResult Init; + + // Hold late-parsed attributes so we can attach a Decl to them later. + LateParsedAttrList LateParsedAttrs; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -1719,11 +1726,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseOptionalCXX0XVirtSpecifierSeq(VS); // If attributes exist after the declarator, but before an '{', parse them. - MaybeParseGNUAttributes(DeclaratorInfo); + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); // MSVC permits pure specifier on inline functions declared at class scope. // Hence check for =0 before checking for function definition. - if (getLang().Microsoft && Tok.is(tok::equal) && + ExprResult Init; + if (getLang().MicrosoftExt && Tok.is(tok::equal) && DeclaratorInfo.isFunctionDeclarator() && NextToken().is(tok::numeric_constant)) { ConsumeToken(); @@ -1776,7 +1784,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init); + Decl *FunDecl = + ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, + VS, Init); + + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { + LateParsedAttrs[i]->setDecl(FunDecl); + } + LateParsedAttrs.clear(); // Consume the ';' - it's optional unless we have a delete or default if (Tok.is(tok::semi)) { @@ -1791,7 +1806,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // member-declarator // member-declarator-list ',' member-declarator - llvm::SmallVector<Decl *, 8> DeclsInGroup; + SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; while (1) { @@ -1818,31 +1833,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // If attributes exist after the declarator, parse them. - MaybeParseGNUAttributes(DeclaratorInfo); + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); // FIXME: When g++ adds support for this, we'll need to check whether it // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); + bool HasInitializer = false; bool HasDeferredInitializer = false; if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); } else { + HasInitializer = true; HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef; - - if (!HasDeferredInitializer) { - SourceLocation EqualLoc; - Init = ParseCXXMemberInitializer( - DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); - if (Init.isInvalid()) - SkipUntil(tok::comma, true, true); - } } } @@ -1854,32 +1863,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DS.isFriendSpecified()) { // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, - /*IsDefinition*/ false, move(TemplateParams)); } else { ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - VS, Init.release(), - HasDeferredInitializer, - /*IsDefinition*/ false); + VS, HasDeferredInitializer); + if (AccessAttrs) + Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, + false, true); } - if (ThisDecl) - DeclsInGroup.push_back(ThisDecl); - - if (DeclaratorInfo.isFunctionDeclarator() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef) { - HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); + + // Set the Decl for any late parsed attributes + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { + LateParsedAttrs[i]->setDecl(ThisDecl); } + LateParsedAttrs.clear(); - DeclaratorInfo.complete(ThisDecl); - + // Handle the initializer. if (HasDeferredInitializer) { + // The initializer was deferred; parse it and cache the tokens. if (!getLang().CPlusPlus0x) Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension); - + if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++0x [dcl.array]p3: An array bound may also be omitted when the // declarator is followed by an initializer. @@ -1892,8 +1899,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); + } else if (HasInitializer) { + // Normal initializer. + SourceLocation EqualLoc; + ExprResult Init + = ParseCXXMemberInitializer(DeclaratorInfo.isDeclarationOfFunction(), + EqualLoc); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + else if (ThisDecl) + Actions.AddInitializerToDecl(ThisDecl, Init.get(), false, + DS.getTypeSpecType() == DeclSpec::TST_auto); + } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { + // No initializer. + Actions.ActOnUninitializedDecl(ThisDecl, + DS.getTypeSpecType() == DeclSpec::TST_auto); + } + + if (ThisDecl) { + Actions.FinalizeDeclaration(ThisDecl); + DeclsInGroup.push_back(ThisDecl); + } + + if (DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) { + HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); } + DeclaratorInfo.complete(ThisDecl); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) @@ -1905,8 +1940,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the next declarator. DeclaratorInfo.clear(); VS.clear(); - BitfieldSize = 0; - Init = 0; + BitfieldSize = true; // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); @@ -1973,7 +2007,6 @@ ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction, return ExprResult(); } } else if (Tok.is(tok::kw_default)) { - Diag(ConsumeToken(), diag::err_default_special_members); if (IsFunction) Diag(Tok, diag::err_default_delete_in_multiple_declaration) << 0 /* default */; @@ -2067,12 +2100,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } assert(Tok.is(tok::l_brace)); - - SourceLocation LBraceLoc = ConsumeBrace(); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, - LBraceLoc); + T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union @@ -2082,14 +2115,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, CurAS = AS_private; else CurAS = AS_public; + ParsedAttributes AccessAttrs(AttrFactory); - SourceLocation RBraceLoc; if (TagDecl) { // While we still have something to read, read the member-declarations. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one member-declaration. - if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; @@ -2109,22 +2142,41 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Current token is a C++ access specifier. CurAS = AS; SourceLocation ASLoc = Tok.getLocation(); + unsigned TokLength = Tok.getLength(); ConsumeToken(); - if (Tok.is(tok::colon)) - Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); - else - Diag(Tok, diag::err_expected_colon); - ConsumeToken(); + AccessAttrs.clear(); + MaybeParseGNUAttributes(AccessAttrs); + + SourceLocation EndLoc; + if (Tok.is(tok::colon)) { + EndLoc = Tok.getLocation(); + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, + AccessAttrs.getList())) { + // found another attribute than only annotations + AccessAttrs.clear(); + } + ConsumeToken(); + } else if (Tok.is(tok::semi)) { + EndLoc = Tok.getLocation(); + ConsumeToken(); + Diag(EndLoc, diag::err_expected_colon) + << FixItHint::CreateReplacement(EndLoc, ":"); + } else { + EndLoc = ASLoc.getLocWithOffset(TokLength); + Diag(EndLoc, diag::err_expected_colon) + << FixItHint::CreateInsertion(EndLoc, ":"); + } + Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc); continue; } // FIXME: Make sure we don't have a template here. // Parse all the comma separated declarators. - ParseCXXClassMemberDeclaration(CurAS); + ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); } - RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + T.consumeClose(); } else { SkipUntil(tok::r_brace, false, false); } @@ -2135,7 +2187,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl, - LBraceLoc, RBraceLoc, + T.getOpenLocation(), + T.getCloseLocation(), attrs.getList()); // C++0x [class.mem]p2: Within the class member-specification, the class is @@ -2148,8 +2201,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl && NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method - // declarations and the lexed inline method definitions. + // declarations and the lexed inline method definitions, along with any + // delayed attributes. SourceLocation SavedPrevTokLocation = PrevTokLocation; + ParseLexedAttributes(getCurrentClass()); ParseLexedMethodDeclarations(getCurrentClass()); ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); @@ -2157,7 +2212,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } if (TagDecl) - Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc); + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, + T.getCloseLocation()); // Leave the class scope. ParsingDef.Pop(); @@ -2192,7 +2248,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); SourceLocation ColonLoc = ConsumeToken(); - llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers; + SmallVector<CXXCtorInitializer*, 4> MemInitializers; bool AnyErrors = false; do { @@ -2200,7 +2256,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { Actions.CodeCompleteConstructorInitializer(ConstructorDecl, MemInitializers.data(), MemInitializers.size()); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } else { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) @@ -2270,11 +2326,20 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // Parse the '('. if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { - // FIXME: Do something with the braced-init-list. - ParseBraceInitializer(); - return true; + ExprResult InitList = ParseBraceInitializer(); + if (InitList.isInvalid()) + return true; + + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, + TemplateTypeTy, IdLoc, InitList.take(), + EllipsisLoc); } else if(Tok.is(tok::l_paren)) { - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); // Parse the optional expression-list. ExprVector ArgExprs(Actions); @@ -2284,7 +2349,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { return true; } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); SourceLocation EllipsisLoc; if (Tok.is(tok::ellipsis)) @@ -2292,8 +2357,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, IdLoc, - LParenLoc, ArgExprs.take(), - ArgExprs.size(), RParenLoc, + T.getOpenLocation(), ArgExprs.take(), + ArgExprs.size(), T.getCloseLocation(), EllipsisLoc); } @@ -2313,8 +2378,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// 'noexcept' '(' constant-expression ')' ExceptionSpecificationType Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, - llvm::SmallVectorImpl<ParsedType> &DynamicExceptions, - llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges, + SmallVectorImpl<ParsedType> &DynamicExceptions, + SmallVectorImpl<SourceRange> &DynamicExceptionRanges, ExprResult &NoexceptExpr) { ExceptionSpecificationType Result = EST_None; @@ -2339,7 +2404,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, SourceLocation KeywordLoc = ConsumeToken(); if (Tok.is(tok::l_paren)) { // There is an argument. - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); NoexceptType = EST_ComputedNoexcept; NoexceptExpr = ParseConstantExpression(); // The argument must be contextually convertible to bool. We use @@ -2347,8 +2413,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, if (!NoexceptExpr.isInvalid()) NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, NoexceptExpr.get()); - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - NoexceptRange = SourceRange(KeywordLoc, RParenLoc); + T.consumeClose(); + NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); } else { // There is no argument. NoexceptType = EST_BasicNoexcept; @@ -2386,27 +2452,26 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, /// ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( SourceRange &SpecificationRange, - llvm::SmallVectorImpl<ParsedType> &Exceptions, - llvm::SmallVectorImpl<SourceRange> &Ranges) { + SmallVectorImpl<ParsedType> &Exceptions, + SmallVectorImpl<SourceRange> &Ranges) { assert(Tok.is(tok::kw_throw) && "expected throw"); SpecificationRange.setBegin(ConsumeToken()); - - if (!Tok.is(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << "throw"; SpecificationRange.setEnd(SpecificationRange.getBegin()); return EST_DynamicNone; } - SourceLocation LParenLoc = ConsumeParen(); // Parse throw(...), a Microsoft extension that means "this function // can throw anything". if (Tok.is(tok::ellipsis)) { SourceLocation EllipsisLoc = ConsumeToken(); - if (!getLang().Microsoft) + if (!getLang().MicrosoftExt) Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - SpecificationRange.setEnd(RParenLoc); + T.consumeClose(); + SpecificationRange.setEnd(T.getCloseLocation()); return EST_MSAny; } @@ -2436,13 +2501,14 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( break; } - SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc)); + T.consumeClose(); + SpecificationRange.setEnd(T.getCloseLocation()); return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } /// ParseTrailingReturnType - Parse a trailing return type on a new-style /// function declaration. -TypeResult Parser::ParseTrailingReturnType() { +TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { assert(Tok.is(tok::arrow) && "expected arrow"); ConsumeToken(); @@ -2454,8 +2520,6 @@ TypeResult Parser::ParseTrailingReturnType() { // // struct X is parsed as class definition because of the trailing // brace. - - SourceRange Range; return ParseTypeName(&Range); } @@ -2519,11 +2583,12 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } -/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only -/// parses standard attributes. +/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently +/// only parses standard attributes. /// /// [C++0x] attribute-specifier: /// '[' '[' attribute-list ']' ']' +/// alignment-specifier /// /// [C++0x] attribute-list: /// attribute[opt] @@ -2554,12 +2619,18 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' -void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, - SourceLocation *endLoc) { +void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *endLoc) { + if (Tok.is(tok::kw_alignas)) { + Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); + ParseAlignmentSpecifier(attrs, endLoc); + return; + } + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a C++0x attribute list"); - SourceLocation StartLoc = Tok.getLocation(), Loc; + Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); ConsumeBracket(); ConsumeBracket(); @@ -2617,29 +2688,6 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, break; } - // One argument; must be a type-id or assignment-expression - case AttributeList::AT_aligned: { - if (Tok.isNot(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments) - << AttrName->getName(); - break; - } - SourceLocation ParamLoc = ConsumeParen(); - - ExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); - - MatchRHSPunctuation(tok::r_paren, ParamLoc); - - ExprVector ArgExprs(Actions); - ArgExprs.push_back(ArgExpr.release()); - attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, - 0, ParamLoc, ArgExprs.take(), 1, - false, true); - - AttrParsed = true; - break; - } - // Silence warnings default: break; } @@ -2655,31 +2703,27 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) SkipUntil(tok::r_square, false); - Loc = Tok.getLocation(); + if (endLoc) + *endLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) SkipUntil(tok::r_square, false); - - attrs.Range = SourceRange(StartLoc, Loc); } -/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] -/// attribute. -/// -/// FIXME: Simply returns an alignof() expression if the argument is a -/// type. Ideally, the type should be propagated directly into Sema. -/// -/// [C++0x] 'align' '(' type-id ')' -/// [C++0x] 'align' '(' assignment-expression ')' -ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { - if (isTypeIdInParens()) { - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); - SourceLocation TypeLoc = Tok.getLocation(); - ParsedType Ty = ParseTypeName().get(); - SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, - Ty.getAsOpaquePtr(), TypeRange); - } else - return ParseConstantExpression(); +/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier-seq. +/// +/// attribute-specifier-seq: +/// attribute-specifier-seq[opt] attribute-specifier +void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc) { + SourceLocation StartLoc = Tok.getLocation(), Loc; + if (!endLoc) + endLoc = &Loc; + + do { + ParseCXX0XAttributeSpecifier(attrs, endLoc); + } while (isCXX0XAttributeSpecifier()); + + attrs.Range = SourceRange(StartLoc, *endLoc); } /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] @@ -2753,7 +2797,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, } // Parse all the comma separated declarators. - ParseCXXClassMemberDeclaration(CurAS); + ParseCXXClassMemberDeclaration(CurAS, 0); } if (Tok.isNot(tok::r_brace)) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index fc64ae0..bc8bbf5 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -214,7 +214,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return ExprError(); } if (Tok.is(tok::kw_throw)) @@ -303,23 +304,23 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // Eat the colon. ColonLoc = ConsumeToken(); } else { - // Otherwise, we're missing a ':'. Assume that this was a typo that the - // user forgot. If we're not in a macro instantiation, we can suggest a - // fixit hint. If there were two spaces before the current token, + // Otherwise, we're missing a ':'. Assume that this was a typo that + // the user forgot. If we're not in a macro expansion, we can suggest + // a fixit hint. If there were two spaces before the current token, // suggest inserting the colon in between them, otherwise insert ": ". SourceLocation FILoc = Tok.getLocation(); const char *FIText = ": "; const SourceManager &SM = PP.getSourceManager(); if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) { - FILoc = SM.getInstantiationLoc(FILoc); + FILoc = SM.getExpansionLoc(FILoc); bool IsInvalid = false; const char *SourcePtr = - SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid); + SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { SourcePtr = - SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid); + SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { - FILoc = FILoc.getFileLocWithOffset(-1); + FILoc = FILoc.getLocWithOffset(-1); FIText = ":"; } } @@ -336,7 +337,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // goes through a special hook that takes the left-hand side into account. if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) { Actions.CodeCompleteAssignmentRHS(getCurScope(), LHS.get()); - ConsumeCodeCompletionToken(); + cutOffParsing(); return ExprError(); } @@ -769,6 +770,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; } case tok::char_constant: // constant: character-constant + case tok::wide_char_constant: + case tok::utf16_char_constant: + case tok::utf32_char_constant: Res = Actions.ActOnCharacterConstant(Tok); ConsumeToken(); break; @@ -780,6 +784,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: Res = ParseStringLiteralExpression(); break; case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1] @@ -913,6 +920,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: @@ -1021,18 +1029,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' SourceLocation KeyLoc = ConsumeToken(); - SourceLocation LParen = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, - diag::err_expected_lparen_after, "noexcept")) + BalancedDelimiterTracker T(*this, tok::l_paren); + + if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) return ExprError(); // C++ [expr.unary.noexcept]p1: // The noexcept operator determines whether the evaluation of its operand, // which is an unevaluated operand, can throw an exception. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); ExprResult Result = ParseExpression(); - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + T.consumeClose(); + if (!Result.isInvalid()) - Result = Actions.ActOnNoexceptExpr(KeyLoc, LParen, Result.take(), RParen); + Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), + Result.take(), T.getCloseLocation()); return move(Result); } @@ -1104,11 +1115,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; case tok::code_completion: { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - ConsumeCodeCompletionToken(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + cutOffParsing(); + return ExprError(); } case tok::l_square: + if (getLang().CPlusPlus0x) { + if (getLang().ObjC1) { + Res = TryParseLambdaExpression(); + if (Res.isInvalid()) + Res = ParseObjCMessageExpression(); + break; + } + Res = ParseLambdaExpression(); + break; + } if (getLang().ObjC1) { Res = ParseObjCMessageExpression(); break; @@ -1154,9 +1174,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { return move(LHS); Actions.CodeCompletePostfixExpression(getCurScope(), LHS); - ConsumeCodeCompletionToken(); - LHS = ExprError(); - break; + cutOffParsing(); + return ExprError(); case tok::identifier: // If we see identifier: after an expression, and we're not already in a @@ -1183,8 +1202,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (getLang().ObjC1 && Tok.isAtStartOfLine() && isSimpleObjCMessageExpression()) return move(LHS); - - Loc = ConsumeBracket(); + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + Loc = T.getOpenLocation(); ExprResult Idx; if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) Idx = ParseBraceInitializer(); @@ -1200,7 +1221,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { LHS = ExprError(); // Match the ']'. - MatchRHSPunctuation(tok::r_square, Loc); + T.consumeClose(); break; } @@ -1212,12 +1233,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Expr *ExecConfig = 0; + BalancedDelimiterTracker LLLT(*this, tok::lesslessless); + BalancedDelimiterTracker PT(*this, tok::l_paren); + if (OpKind == tok::lesslessless) { ExprVector ExecConfigExprs(Actions); CommaLocsTy ExecConfigCommaLocs; - SourceLocation LLLLoc, GGGLoc; - - LLLLoc = ConsumeToken(); + LLLT.consumeOpen(); if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { LHS = ExprError(); @@ -1225,11 +1247,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (LHS.isInvalid()) { SkipUntil(tok::greatergreatergreater); - } else if (Tok.isNot(tok::greatergreatergreater)) { - MatchRHSPunctuation(tok::greatergreatergreater, LLLLoc); + } else if (LLLT.consumeClose()) { + // There was an error closing the brackets LHS = ExprError(); - } else { - GGGLoc = ConsumeToken(); } if (!LHS.isInvalid()) { @@ -1241,14 +1261,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (!LHS.isInvalid()) { ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), - LLLLoc, move_arg(ExecConfigExprs), GGGLoc); + LLLT.getOpenLocation(), + move_arg(ExecConfigExprs), + LLLT.getCloseLocation()); if (ECResult.isInvalid()) LHS = ExprError(); else ExecConfig = ECResult.get(); } } else { - Loc = ConsumeParen(); + PT.consumeOpen(); + Loc = PT.getOpenLocation(); } ExprVector ArgExprs(Actions); @@ -1256,7 +1279,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return ExprError(); } if (OpKind == tok::l_paren || !LHS.isInvalid()) { @@ -1272,7 +1296,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (LHS.isInvalid()) { SkipUntil(tok::r_paren); } else if (Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, Loc); + PT.consumeClose(); LHS = ExprError(); } else { assert((ArgExprs.size() == 0 || @@ -1281,7 +1305,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, move_arg(ArgExprs), Tok.getLocation(), ExecConfig); - ConsumeParen(); + PT.consumeClose(); } break; @@ -1314,7 +1338,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Actions.CodeCompleteMemberReferenceExpr(getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return ExprError(); } if (MayBePseudoDestructor && !LHS.isInvalid()) { @@ -1334,7 +1359,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/ getLang().Microsoft, + /*AllowConstructorName=*/ getLang().MicrosoftExt, ObjectType, Name)) LHS = ExprError(); @@ -1473,11 +1498,14 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { IdentifierInfo *Name = 0; SourceLocation NameLoc; if (Tok.is(tok::l_paren)) { - LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + LParenLoc = T.getOpenLocation(); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); + RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) RParenLoc = PP.getLocForEndOfToken(NameLoc); } else { @@ -1564,11 +1592,13 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { return ExprError(Diag(Tok, diag::err_expected_lparen_after_id) << BuiltinII); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker PT(*this, tok::l_paren); + PT.consumeOpen(); + // TODO: Build AST. switch (T) { - default: assert(0 && "Not a builtin primary expression!"); + default: llvm_unreachable("Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); @@ -1607,7 +1637,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { } // Keep track of the various subcomponents we see. - llvm::SmallVector<Sema::OffsetOfComponent, 4> Comps; + SmallVector<Sema::OffsetOfComponent, 4> Comps; Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; @@ -1634,7 +1664,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = true; - Comps.back().LocStart = ConsumeBracket(); + BalancedDelimiterTracker ST(*this, tok::l_square); + ST.consumeOpen(); + Comps.back().LocStart = ST.getOpenLocation(); Res = ParseExpression(); if (Res.isInvalid()) { SkipUntil(tok::r_paren); @@ -1642,18 +1674,19 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { } Comps.back().U.E = Res.release(); - Comps.back().LocEnd = - MatchRHSPunctuation(tok::r_square, Comps.back().LocStart); + ST.consumeClose(); + Comps.back().LocEnd = ST.getCloseLocation(); } else { if (Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, LParenLoc); + PT.consumeClose(); Res = ExprError(); } else if (Ty.isInvalid()) { Res = ExprError(); } else { + PT.consumeClose(); Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc, - Ty.get(), &Comps[0], - Comps.size(), ConsumeParen()); + Ty.get(), &Comps[0], Comps.size(), + PT.getCloseLocation()); } break; } @@ -1753,7 +1786,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); - SourceLocation OpenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) + return ExprError(); + SourceLocation OpenLoc = T.getOpenLocation(); + ExprResult Result(true); bool isAmbiguousTypeId; CastTy = ParsedType(); @@ -1762,7 +1799,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Actions.CodeCompleteOrdinaryName(getCurScope(), ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression : Sema::PCC_Expression); - ConsumeCodeCompletionToken(); + cutOffParsing(); return ExprError(); } @@ -1806,7 +1843,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, } TypeResult Ty = ParseTypeName(); - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc); + T.consumeClose(); + RParenLoc = T.getCloseLocation(); ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); if (Ty.isInvalid() || SubExpr.isInvalid()) @@ -1825,9 +1863,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // in which case we should treat it as type-id. // if stopIfCastExpr is false, we need to determine the context past the // parens, so we defer to ParseCXXAmbiguousParenExpression for that. - if (isAmbiguousTypeId && !stopIfCastExpr) - return ParseCXXAmbiguousParenExpression(ExprType, CastTy, - OpenLoc, RParenLoc); + if (isAmbiguousTypeId && !stopIfCastExpr) { + ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T); + RParenLoc = T.getCloseLocation(); + return res; + } // Parse the type declarator. DeclSpec DS(AttrFactory); @@ -1851,11 +1891,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Ty.get(), 0); } else { // Match the ')'. - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); - + T.consumeClose(); + RParenLoc = T.getCloseLocation(); if (Tok.is(tok::l_brace)) { ExprType = CompoundLiteral; TypeResult Ty; @@ -1939,11 +1976,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); } - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); - + T.consumeClose(); + RParenLoc = T.getCloseLocation(); return move(Result); } @@ -1978,7 +2012,7 @@ ExprResult Parser::ParseStringLiteralExpression() { // String concat. Note that keywords like __func__ and __FUNCTION__ are not // considered to be strings for concatenation purposes. - llvm::SmallVector<Token, 4> StringToks; + SmallVector<Token, 4> StringToks; do { StringToks.push_back(Tok); @@ -2007,8 +2041,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { if (!getLang().C1X) Diag(KeyLoc, diag::ext_c1x_generic_selection); - SourceLocation LParenLoc = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); ExprResult ControllingExpr; @@ -2074,11 +2108,12 @@ ExprResult Parser::ParseGenericSelectionExpression() { ConsumeToken(); } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - if (RParenLoc.isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return ExprError(); - return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, + T.getCloseLocation(), ControllingExpr.release(), move_arg(Types), move_arg(Exprs)); } @@ -2104,8 +2139,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// -bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, - llvm::SmallVectorImpl<SourceLocation> &CommaLocs, +bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs, void (Sema::*Completer)(Scope *S, Expr *Data, Expr **Args, @@ -2117,7 +2152,8 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, (Actions.*Completer)(getCurScope(), Data, Exprs.data(), Exprs.size()); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return true; } ExprResult Expr; @@ -2148,7 +2184,7 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, void Parser::ParseBlockId() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } // Parse the specifier-qualifier-list piece. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index b32eeda..60166e8 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "llvm/Support/ErrorHandling.h" @@ -28,8 +29,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) { case tok::kw_reinterpret_cast: return 3; case tok::kw_static_cast: return 4; default: - assert(0 && "Unknown type for digraph error message."); - return -1; + llvm_unreachable("Unknown type for digraph error message."); } } @@ -37,7 +37,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) { static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) { SourceManager &SM = PP.getSourceManager(); SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); - SourceLocation FirstEnd = FirstLoc.getFileLocWithOffset(First.getLength()); + SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength()); return FirstEnd == SM.getSpellingLoc(Second.getLocation()); } @@ -58,7 +58,7 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, // Update token information to reflect their change in token type. ColonToken.setKind(tok::coloncolon); - ColonToken.setLocation(ColonToken.getLocation().getFileLocWithOffset(-1)); + ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1)); ColonToken.setLength(2); DigraphToken.setKind(tok::less); DigraphToken.setLength(1); @@ -69,6 +69,31 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, PP.EnterToken(DigraphToken); } +// Check for '<::' which should be '< ::' instead of '[:' when following +// a template name. +void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, + bool EnteringContext, + IdentifierInfo &II, CXXScopeSpec &SS) { + if (!Next.is(tok::l_square) || Next.getLength() != 2) + return; + + Token SecondToken = GetLookAheadToken(2); + if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken)) + return; + + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, + TemplateName, ObjectType, EnteringContext, + Template, MemberOfUnknownSpecialization)) + return; + + FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, + /*AtDigraph*/false); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -161,12 +186,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); - SourceLocation ccLoc = ConsumeCodeCompletionToken(); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion // token will cause assertion in // Preprocessor::AnnotatePreviousCachedTokens. - SS.setEndLoc(ccLoc); + SS.setEndLoc(Tok.getLocation()); + cutOffParsing(); + return true; } } @@ -339,28 +365,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, continue; } - // Check for '<::' which should be '< ::' instead of '[:' when following - // a template name. - if (Next.is(tok::l_square) && Next.getLength() == 2) { - Token SecondToken = GetLookAheadToken(2); - if (SecondToken.is(tok::colon) && - AreTokensAdjacent(PP, Next, SecondToken)) { - TemplateTy Template; - UnqualifiedId TemplateName; - TemplateName.setIdentifier(&II, Tok.getLocation()); - bool MemberOfUnknownSpecialization; - if (Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - TemplateName, - ObjectType, - EnteringContext, - Template, - MemberOfUnknownSpecialization)) { - FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, - /*AtDigraph*/false); - } - } - } + CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); // nested-name-specifier: // type-name '<' @@ -396,7 +401,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. unsigned DiagID = diag::err_missing_dependent_template_keyword; - if (getLang().Microsoft) + if (getLang().MicrosoftExt) DiagID = diag::warn_missing_dependent_template_keyword; Diag(Tok.getLocation(), DiagID) @@ -504,6 +509,273 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { } +/// ParseLambdaExpression - Parse a C++0x lambda expression. +/// +/// lambda-expression: +/// lambda-introducer lambda-declarator[opt] compound-statement +/// +/// lambda-introducer: +/// '[' lambda-capture[opt] ']' +/// +/// lambda-capture: +/// capture-default +/// capture-list +/// capture-default ',' capture-list +/// +/// capture-default: +/// '&' +/// '=' +/// +/// capture-list: +/// capture +/// capture-list ',' capture +/// +/// capture: +/// identifier +/// '&' identifier +/// 'this' +/// +/// lambda-declarator: +/// '(' parameter-declaration-clause ')' attribute-specifier[opt] +/// 'mutable'[opt] exception-specification[opt] +/// trailing-return-type[opt] +/// +ExprResult Parser::ParseLambdaExpression() { + // Parse lambda-introducer. + LambdaIntroducer Intro; + + llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro)); + if (DiagID) { + Diag(Tok, DiagID.getValue()); + SkipUntil(tok::r_square); + } + + return ParseLambdaExpressionAfterIntroducer(Intro); +} + +/// TryParseLambdaExpression - Use lookahead and potentially tentative +/// parsing to determine if we are looking at a C++0x lambda expression, and parse +/// it if we are. +/// +/// If we are not looking at a lambda expression, returns ExprError(). +ExprResult Parser::TryParseLambdaExpression() { + assert(getLang().CPlusPlus0x + && Tok.is(tok::l_square) + && "Not at the start of a possible lambda expression."); + + const Token Next = NextToken(), After = GetLookAheadToken(2); + + // If lookahead indicates this is a lambda... + if (Next.is(tok::r_square) || // [] + Next.is(tok::equal) || // [= + (Next.is(tok::amp) && // [&] or [&, + (After.is(tok::r_square) || + After.is(tok::comma))) || + (Next.is(tok::identifier) && // [identifier] + After.is(tok::r_square))) { + return ParseLambdaExpression(); + } + + // If lookahead indicates this is an Objective-C message... + if (Next.is(tok::identifier) && After.is(tok::identifier)) { + return ExprError(); + } + + LambdaIntroducer Intro; + if (TryParseLambdaIntroducer(Intro)) + return ExprError(); + return ParseLambdaExpressionAfterIntroducer(Intro); +} + +/// ParseLambdaExpression - Parse a lambda introducer. +/// +/// Returns a DiagnosticID if it hit something unexpected. +llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { + typedef llvm::Optional<unsigned> DiagResult; + + assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + Intro.Range.setBegin(T.getOpenLocation()); + + bool first = true; + + // Parse capture-default. + if (Tok.is(tok::amp) && + (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { + Intro.Default = LCD_ByRef; + ConsumeToken(); + first = false; + } else if (Tok.is(tok::equal)) { + Intro.Default = LCD_ByCopy; + ConsumeToken(); + first = false; + } + + while (Tok.isNot(tok::r_square)) { + if (!first) { + if (Tok.isNot(tok::comma)) + return DiagResult(diag::err_expected_comma_or_rsquare); + ConsumeToken(); + } + + first = false; + + // Parse capture. + LambdaCaptureKind Kind = LCK_ByCopy; + SourceLocation Loc; + IdentifierInfo* Id = 0; + + if (Tok.is(tok::kw_this)) { + Kind = LCK_This; + Loc = ConsumeToken(); + } else { + if (Tok.is(tok::amp)) { + Kind = LCK_ByRef; + ConsumeToken(); + } + + if (Tok.is(tok::identifier)) { + Id = Tok.getIdentifierInfo(); + Loc = ConsumeToken(); + } else if (Tok.is(tok::kw_this)) { + // FIXME: If we want to suggest a fixit here, will need to return more + // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be + // Clear()ed to prevent emission in case of tentative parsing? + return DiagResult(diag::err_this_captured_by_reference); + } else { + return DiagResult(diag::err_expected_capture); + } + } + + Intro.addCapture(Kind, Loc, Id); + } + + T.consumeClose(); + Intro.Range.setEnd(T.getCloseLocation()); + + return DiagResult(); +} + +/// TryParseLambdaExpression - Tentatively parse a lambda introducer. +/// +/// Returns true if it hit something unexpected. +bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { + TentativeParsingAction PA(*this); + + llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro)); + + if (DiagID) { + PA.Revert(); + return true; + } + + PA.Commit(); + return false; +} + +/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda +/// expression. +ExprResult Parser::ParseLambdaExpressionAfterIntroducer( + LambdaIntroducer &Intro) { + // Parse lambda-declarator[opt]. + DeclSpec DS(AttrFactory); + Declarator D(DS, Declarator::PrototypeContext); + + if (Tok.is(tok::l_paren)) { + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope | + Scope::DeclScope); + + SourceLocation DeclLoc, DeclEndLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + DeclLoc = T.getOpenLocation(); + + // Parse parameter-declaration-clause. + ParsedAttributes Attr(AttrFactory); + llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; + SourceLocation EllipsisLoc; + + if (Tok.isNot(tok::r_paren)) + ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); + + T.consumeClose(); + DeclEndLoc = T.getCloseLocation(); + + // Parse 'mutable'[opt]. + SourceLocation MutableLoc; + if (Tok.is(tok::kw_mutable)) { + MutableLoc = ConsumeToken(); + DeclEndLoc = MutableLoc; + } + + // Parse exception-specification[opt]. + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector<ParsedType, 2> DynamicExceptions; + llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; + ESpecType = MaybeParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + + if (ESpecType != EST_None) + DeclEndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier[opt]. + MaybeParseCXX0XAttributes(Attr, &DeclEndLoc); + + // Parse trailing-return-type[opt]. + ParsedType TrailingReturnType; + if (Tok.is(tok::arrow)) { + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + PrototypeScope.Exit(); + + D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, + /*isVariadic=*/EllipsisLoc.isValid(), + EllipsisLoc, + ParamInfo.data(), ParamInfo.size(), + DS.getTypeQualifiers(), + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/SourceLocation(), + MutableLoc, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), + Attr, DeclEndLoc); + } + + // Parse compound-statement. + if (Tok.is(tok::l_brace)) { + // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using + // it. + ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope | + Scope::BreakScope | Scope::ContinueScope | + Scope::DeclScope); + + StmtResult Stmt(ParseCompoundStatementBody()); + + BodyScope.Exit(); + } else { + Diag(Tok, diag::err_expected_lambda_body); + } + + return ExprEmpty(); +} + /// ParseCXXCasts - This handles the various ways to cast expressions to another /// type. /// @@ -518,7 +790,7 @@ ExprResult Parser::ParseCXXCasts() { const char *CastName = 0; // For error messages switch (Kind) { - default: assert(0 && "Unknown C++ cast!"); abort(); + default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: CastName = "const_cast"; break; case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; @@ -551,21 +823,23 @@ ExprResult Parser::ParseCXXCasts() { if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<"); - SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; + SourceLocation LParenLoc, RParenLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, CastName)) + if (T.expectAndConsume(diag::err_expected_lparen_after, CastName)) return ExprError(); ExprResult Result = ParseExpression(); // Match the ')'. - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType()) Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, LAngleBracketLoc, DeclaratorInfo, RAngleBracketLoc, - LParenLoc, Result.take(), RParenLoc); + T.getOpenLocation(), Result.take(), + T.getCloseLocation()); return move(Result); } @@ -580,13 +854,13 @@ ExprResult Parser::ParseCXXTypeid() { assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); SourceLocation OpLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - SourceLocation RParenLoc; + SourceLocation LParenLoc, RParenLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); // typeid expressions are always parenthesized. - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "typeid")) + if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid")) return ExprError(); + LParenLoc = T.getOpenLocation(); ExprResult Result; @@ -594,8 +868,8 @@ ExprResult Parser::ParseCXXTypeid() { TypeResult Ty = ParseTypeName(); // Match the ')'. - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - + T.consumeClose(); + RParenLoc = T.getCloseLocation(); if (Ty.isInvalid() || RParenLoc.isInvalid()) return ExprError(); @@ -618,18 +892,11 @@ ExprResult Parser::ParseCXXTypeid() { if (Result.isInvalid()) SkipUntil(tok::r_paren); else { - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); + RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) return ExprError(); - // If we are a foo<int> that identifies a single function, resolve it now... - Expr* e = Result.get(); - if (e->getType() == Actions.Context.OverloadTy) { - ExprResult er = - Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e); - if (er.isUsable()) - Result = er.release(); - } Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } @@ -647,12 +914,10 @@ ExprResult Parser::ParseCXXUuidof() { assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); SourceLocation OpLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - SourceLocation RParenLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); // __uuidof expressions are always parenthesized. - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "__uuidof")) + if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof")) return ExprError(); ExprResult Result; @@ -661,13 +926,14 @@ ExprResult Parser::ParseCXXUuidof() { TypeResult Ty = ParseTypeName(); // Match the ')'. - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); if (Ty.isInvalid()) return ExprError(); - Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/true, - Ty.get().getAsOpaquePtr(), RParenLoc); + Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true, + Ty.get().getAsOpaquePtr(), + T.getCloseLocation()); } else { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); @@ -676,10 +942,11 @@ ExprResult Parser::ParseCXXUuidof() { if (Result.isInvalid()) SkipUntil(tok::r_paren); else { - RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); - Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/false, - Result.release(), RParenLoc); + Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), + /*isType=*/false, + Result.release(), T.getCloseLocation()); } } @@ -836,7 +1103,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { } else { GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); ExprVector Exprs(Actions); CommaLocsTy CommaLocs; @@ -849,7 +1117,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { } // Match the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); // TypeRep could be null, if it references an invalid typedef. if (!TypeRep) @@ -857,8 +1125,9 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); - return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs), - RParenLoc); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), + move_arg(Exprs), + T.getCloseLocation()); } } @@ -889,7 +1158,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, bool ConvertToBoolean) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return true; } if (!isCXXConditionDeclaration()) { @@ -969,6 +1239,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_void: case tok::kw_char: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_wchar_t: @@ -1022,10 +1293,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { switch (Tok.getKind()) { case tok::identifier: // foo::bar case tok::coloncolon: // ::foo::bar - assert(0 && "Annotation token should already be formed!"); + llvm_unreachable("Annotation token should already be formed!"); default: - assert(0 && "Not a simple-type-specifier token!"); - abort(); + llvm_unreachable("Not a simple-type-specifier token!"); // type-name case tok::annot_typename: { @@ -1074,6 +1344,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_int: DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); + break; case tok::kw_float: DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; @@ -1394,16 +1667,15 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Consume the 'new' or 'delete'. SymbolLocations[SymbolIdx++] = ConsumeToken(); if (Tok.is(tok::l_square)) { - // Consume the '['. - SourceLocation LBracketLoc = ConsumeBracket(); - // Consume the ']'. - SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, - LBracketLoc); - if (RBracketLoc.isInvalid()) + // Consume the '[' and ']'. + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return true; - SymbolLocations[SymbolIdx++] = LBracketLoc; - SymbolLocations[SymbolIdx++] = RBracketLoc; + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = isNew? OO_Array_New : OO_Array_Delete; } else { Op = isNew? OO_New : OO_Delete; @@ -1420,31 +1692,29 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, #include "clang/Basic/OperatorKinds.def" case tok::l_paren: { - // Consume the '('. - SourceLocation LParenLoc = ConsumeParen(); - // Consume the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, - LParenLoc); - if (RParenLoc.isInvalid()) + // Consume the '(' and ')'. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return true; - SymbolLocations[SymbolIdx++] = LParenLoc; - SymbolLocations[SymbolIdx++] = RParenLoc; + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Call; break; } case tok::l_square: { - // Consume the '['. - SourceLocation LBracketLoc = ConsumeBracket(); - // Consume the ']'. - SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, - LBracketLoc); - if (RBracketLoc.isInvalid()) + // Consume the '[' and ']'. + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return true; - SymbolLocations[SymbolIdx++] = LBracketLoc; - SymbolLocations[SymbolIdx++] = RBracketLoc; + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Subscript; break; } @@ -1452,10 +1722,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, case tok::code_completion: { // Code completion for the operator name. Actions.CodeCompleteOperatorName(getCurScope()); - - // Consume the operator token. - ConsumeCodeCompletionToken(); - + cutOffParsing(); // Don't try to parse any further. return true; } @@ -1758,13 +2025,16 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { Declarator DeclaratorInfo(DS, Declarator::CXXNewContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. - PlacementLParen = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + PlacementLParen = T.getOpenLocation(); if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } - PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen); + T.consumeClose(); + PlacementRParen = T.getCloseLocation(); if (PlacementRParen.isInvalid()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); @@ -1772,18 +2042,19 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { if (PlacementArgs.empty()) { // Reset the placement locations. There was no placement. - TypeIdParens = SourceRange(PlacementLParen, PlacementRParen); + TypeIdParens = T.getRange(); PlacementLParen = PlacementRParen = SourceLocation(); } else { // We still need the type. if (Tok.is(tok::l_paren)) { - TypeIdParens.setBegin(ConsumeParen()); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); MaybeParseGNUAttributes(DeclaratorInfo); ParseSpecifierQualifierList(DS); DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclarator(DeclaratorInfo); - TypeIdParens.setEnd(MatchRHSPunctuation(tok::r_paren, - TypeIdParens.getBegin())); + T.consumeClose(); + TypeIdParens = T.getRange(); } else { MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) @@ -1816,7 +2087,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { SourceLocation ConstructorLParen, ConstructorRParen; if (Tok.is(tok::l_paren)) { - ConstructorLParen = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; if (ParseExpressionList(ConstructorArgs, CommaLocs)) { @@ -1824,7 +2097,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } } - ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen); + T.consumeClose(); + ConstructorRParen = T.getCloseLocation(); if (ConstructorRParen.isInvalid()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); @@ -1851,7 +2125,9 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { // Parse the array dimensions. bool first = true; while (Tok.is(tok::l_square)) { - SourceLocation LLoc = ConsumeBracket(); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + ExprResult Size(first ? ParseExpression() : ParseConstantExpression()); if (Size.isInvalid()) { @@ -1861,15 +2137,17 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { } first = false; - SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc); + T.consumeClose(); ParsedAttributes attrs(AttrFactory); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, - Size.release(), LLoc, RLoc), - attrs, RLoc); + Size.release(), + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); - if (RLoc.isInvalid()) + if (T.getCloseLocation().isInvalid()) return; } } @@ -1885,7 +2163,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { /// '(' expression-list ')' /// bool Parser::ParseExpressionListOrTypeId( - llvm::SmallVectorImpl<Expr*> &PlacementArgs, + SmallVectorImpl<Expr*> &PlacementArgs, Declarator &D) { // The '(' was already consumed. if (isTypeIdInParens()) { @@ -1921,9 +2199,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { bool ArrayDelete = false; if (Tok.is(tok::l_square)) { ArrayDelete = true; - SourceLocation LHS = ConsumeBracket(); - SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS); - if (RHS.isInvalid()) + BalancedDelimiterTracker T(*this, tok::l_square); + + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return ExprError(); } @@ -1936,7 +2216,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { - default: assert(false && "Not a known unary type trait."); + default: llvm_unreachable("Not a known unary type trait."); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; @@ -2004,7 +2284,7 @@ static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { switch(kind) { - default: assert(false && "Not a known unary expression trait."); + default: llvm_unreachable("Not a known unary expression trait."); case tok::kw___is_lvalue_expr: return ET_IsLValueExpr; case tok::kw___is_rvalue_expr: return ET_IsRValueExpr; } @@ -2021,8 +2301,8 @@ ExprResult Parser::ParseUnaryTypeTrait() { UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); - SourceLocation LParen = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); // FIXME: Error reporting absolutely sucks! If the this fails to parse a type @@ -2030,12 +2310,12 @@ ExprResult Parser::ParseUnaryTypeTrait() { // specifiers. TypeResult Ty = ParseTypeName(); - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + T.consumeClose(); if (Ty.isInvalid()) return ExprError(); - return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), RParen); + return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), T.getCloseLocation()); } /// ParseBinaryTypeTrait - Parse the built-in binary type-trait @@ -2049,8 +2329,8 @@ ExprResult Parser::ParseBinaryTypeTrait() { BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); - SourceLocation LParen = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); TypeResult LhsTy = ParseTypeName(); @@ -2070,9 +2350,10 @@ ExprResult Parser::ParseBinaryTypeTrait() { return ExprError(); } - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + T.consumeClose(); - return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen); + return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), + T.getCloseLocation()); } /// ParseArrayTypeTrait - Parse the built-in array type-trait @@ -2086,8 +2367,8 @@ ExprResult Parser::ParseArrayTypeTrait() { ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); - SourceLocation LParen = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); TypeResult Ty = ParseTypeName(); @@ -2099,8 +2380,9 @@ ExprResult Parser::ParseArrayTypeTrait() { switch (ATT) { case ATT_ArrayRank: { - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); - return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, RParen); + T.consumeClose(); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, + T.getCloseLocation()); } case ATT_ArrayExtent: { if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { @@ -2109,9 +2391,10 @@ ExprResult Parser::ParseArrayTypeTrait() { } ExprResult DimExpr = ParseExpression(); - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + T.consumeClose(); - return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), RParen); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), + T.getCloseLocation()); } default: break; @@ -2129,15 +2412,16 @@ ExprResult Parser::ParseExpressionTrait() { ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); - SourceLocation LParen = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); ExprResult Expr = ParseExpression(); - SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + T.consumeClose(); - return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen); + return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), + T.getCloseLocation()); } @@ -2147,8 +2431,7 @@ ExprResult Parser::ParseExpressionTrait() { ExprResult Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParsedType &CastTy, - SourceLocation LParenLoc, - SourceLocation &RParenLoc) { + BalancedDelimiterTracker &Tracker) { assert(getLang().CPlusPlus && "Should only be called for C++!"); assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); assert(isTypeIdInParens() && "Not a type-id!"); @@ -2182,7 +2465,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // the context that follows them. if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { // We didn't find the ')' we expected. - MatchRHSPunctuation(tok::r_paren, LParenLoc); + Tracker.consumeClose(); return ExprError(); } @@ -2227,15 +2510,14 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParseDeclarator(DeclaratorInfo); // Match the ')'. - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, LParenLoc); + Tracker.consumeClose(); if (ParseAs == CompoundLiteral) { ExprType = CompoundLiteral; TypeResult Ty = ParseTypeName(); - return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc); + return ParseCompoundLiteralExpression(Ty.get(), + Tracker.getOpenLocation(), + Tracker.getCloseLocation()); } // We parsed '(' type-id ')' and the thing after it wasn't a '{'. @@ -2246,9 +2528,9 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc, - DeclaratorInfo, CastTy, - RParenLoc, Result.take()); + Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(), + DeclaratorInfo, CastTy, + Tracker.getCloseLocation(), Result.take()); return move(Result); } @@ -2258,7 +2540,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ExprType = SimpleExpr; Result = ParseExpression(); if (!Result.isInvalid() && Tok.is(tok::r_paren)) - Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), Result.take()); + Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(), + Tok.getLocation(), Result.take()); // Match the ')'. if (Result.isInvalid()) { @@ -2266,10 +2549,6 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, return ExprError(); } - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, LParenLoc); - + Tracker.consumeClose(); return move(Result); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp index 2c9278a..33abc93 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp @@ -90,7 +90,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!"); SourceLocation ColonLoc = ConsumeToken(); - Diag(Tok, diag::ext_gnu_old_style_field_designator) + Diag(NameLoc, diag::ext_gnu_old_style_field_designator) << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), NewSyntax.str()); @@ -139,7 +139,10 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // InMessageExpressionRAIIObject InMessage(*this, true); - SourceLocation StartLoc = ConsumeBracket(); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + SourceLocation StartLoc = T.getOpenLocation(); + ExprResult Idx; // If Objective-C is enabled and this is a typename (class message @@ -266,8 +269,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { StartLoc, EllipsisLoc)); } - SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(EndLoc); + T.consumeClose(); + Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc( + T.getCloseLocation()); } // Okay, we're done with the designator sequence. We know that there must be @@ -316,7 +320,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { ExprResult Parser::ParseBraceInitializer() { InMessageExpressionRAIIObject InMessage(*this, false); - SourceLocation LBraceLoc = ConsumeBrace(); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + SourceLocation LBraceLoc = T.getOpenLocation(); /// InitExprs - This is the actual list of expressions contained in the /// initializer. @@ -376,12 +382,13 @@ ExprResult Parser::ParseBraceInitializer() { // Handle trailing comma. if (Tok.is(tok::r_brace)) break; } - if (InitExprsOk && Tok.is(tok::r_brace)) + + bool closed = !T.consumeClose(); + + if (InitExprsOk && closed) return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs), - ConsumeBrace()); + T.getCloseLocation()); - // Match the '}'. - MatchRHSPunctuation(tok::r_brace, LBraceLoc); return ExprError(); // an error occurred. } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index 7641565..88044d1 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -29,57 +29,70 @@ using namespace clang; /// [OBJC] objc-protocol-definition /// [OBJC] objc-method-definition /// [OBJC] '@' 'end' -Decl *Parser::ParseObjCAtDirectives() { +Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, false); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCAtDirective(getCurScope()); + cutOffParsing(); + return DeclGroupPtrTy(); } - + + Decl *SingleDecl = 0; switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); + break; case tok::objc_interface: { ParsedAttributes attrs(AttrFactory); - return ParseObjCAtInterfaceDeclaration(AtLoc, attrs); + SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs); + break; } case tok::objc_protocol: { ParsedAttributes attrs(AttrFactory); - return ParseObjCAtProtocolDeclaration(AtLoc, attrs); + SingleDecl = ParseObjCAtProtocolDeclaration(AtLoc, attrs); + break; } case tok::objc_implementation: - return ParseObjCAtImplementationDeclaration(AtLoc); + SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc); + break; case tok::objc_end: return ParseObjCAtEndDeclaration(AtLoc); + break; case tok::objc_compatibility_alias: - return ParseObjCAtAliasDeclaration(AtLoc); + SingleDecl = ParseObjCAtAliasDeclaration(AtLoc); + break; case tok::objc_synthesize: - return ParseObjCPropertySynthesize(AtLoc); + SingleDecl = ParseObjCPropertySynthesize(AtLoc); + break; case tok::objc_dynamic: - return ParseObjCPropertyDynamic(AtLoc); + SingleDecl = ParseObjCPropertyDynamic(AtLoc); + break; default: Diag(AtLoc, diag::err_unexpected_at); SkipUntil(tok::semi); - return 0; + SingleDecl = 0; + break; } + return Actions.ConvertDeclToDeclGroup(SingleDecl); } /// /// objc-class-declaration: /// '@' 'class' identifier-list ';' /// -Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" - llvm::SmallVector<IdentifierInfo *, 8> ClassNames; - llvm::SmallVector<SourceLocation, 8> ClassLocs; + SmallVector<IdentifierInfo *, 8> ClassNames; + SmallVector<SourceLocation, 8> ClassLocs; while (1) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); - return 0; + return Actions.ConvertDeclToDeclGroup(0); } ClassNames.push_back(Tok.getIdentifierInfo()); ClassLocs.push_back(Tok.getLocation()); @@ -93,7 +106,7 @@ Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) - return 0; + return Actions.ConvertDeclToDeclGroup(0); return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), ClassLocs.data(), @@ -137,7 +150,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, // Code completion after '@interface'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -150,14 +164,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, SourceLocation nameLoc = ConsumeToken(); if (Tok.is(tok::l_paren) && !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. - // TODO(dgregor): Use the return value from the next line to provide better - // recovery. - ConsumeParen(); - SourceLocation categoryLoc, rparenLoc; + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + SourceLocation categoryLoc; IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } // For ObjC2, the category name is optional (not an error). @@ -169,24 +185,25 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, Diag(Tok, diag::err_expected_ident); // missing category name. return 0; } - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren, false); // don't stop at ';' + + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return 0; + + if (!attrs.empty()) { // categories don't support attributes. + Diag(nameLoc, diag::err_objc_no_attributes_on_category); + attrs.clear(); } - rparenLoc = ConsumeParen(); + // Next, we need to check for any protocol references. SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolRefs; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SmallVector<Decl *, 8> ProtocolRefs; + SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, LAngleLoc, EndProtoLoc)) return 0; - if (!attrs.empty()) // categories don't support attributes. - Diag(Tok, diag::err_objc_no_attributes_on_category); - Decl *CategoryType = Actions.ActOnStartCategoryInterface(atLoc, nameId, nameLoc, @@ -195,11 +212,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc); - if (Tok.is(tok::l_brace)) - ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, - atLoc); - ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc); + + ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); return CategoryType; } // Parse a class interface. @@ -212,7 +229,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, // Code completion of superclass names. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -223,8 +241,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, superClassLoc = ConsumeToken(); } // Next, we need to check for any protocol references. - llvm::SmallVector<Decl *, 8> ProtocolRefs; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SmallVector<Decl *, 8> ProtocolRefs; + SmallVector<SourceLocation, 8> ProtocolLocs; SourceLocation LAngleLoc, EndProtoLoc; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, @@ -241,7 +259,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); - ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); + ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); return ClsType; } @@ -249,17 +267,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, /// it's used, but instead it's been lifted to here to support VS2005. struct Parser::ObjCPropertyCallback : FieldCallback { Parser &P; - Decl *IDecl; - llvm::SmallVectorImpl<Decl *> &Props; + SmallVectorImpl<Decl *> &Props; ObjCDeclSpec &OCDS; SourceLocation AtLoc; tok::ObjCKeywordKind MethodImplKind; - ObjCPropertyCallback(Parser &P, Decl *IDecl, - llvm::SmallVectorImpl<Decl *> &Props, + ObjCPropertyCallback(Parser &P, + SmallVectorImpl<Decl *> &Props, ObjCDeclSpec &OCDS, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind) : - P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), MethodImplKind(MethodImplKind) { } @@ -292,7 +309,7 @@ struct Parser::ObjCPropertyCallback : FieldCallback { bool isOverridingProperty = false; Decl *Property = P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS, - GetterSel, SetterSel, IDecl, + GetterSel, SetterSel, &isOverridingProperty, MethodImplKind); if (!isOverridingProperty) @@ -314,20 +331,20 @@ struct Parser::ObjCPropertyCallback : FieldCallback { /// @required /// @optional /// -void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, - tok::ObjCKeywordKind contextKey) { - llvm::SmallVector<Decl *, 32> allMethods; - llvm::SmallVector<Decl *, 16> allProperties; - llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables; +void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, + Decl *CDecl) { + SmallVector<Decl *, 32> allMethods; + SmallVector<Decl *, 16> allProperties; + SmallVector<DeclGroupPtrTy, 8> allTUVariables; tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; SourceRange AtEnd; - + while (1) { // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { Decl *methodPrototype = - ParseObjCMethodPrototype(interfaceDecl, MethodImplKind, false); + ParseObjCMethodPrototype(MethodImplKind, false); allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. @@ -339,7 +356,6 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, Diag(Tok, diag::err_expected_minus_or_plus); ParseObjCMethodDecl(Tok.getLocation(), tok::minus, - interfaceDecl, MethodImplKind, false); continue; } @@ -358,7 +374,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, Actions.CodeCompleteOrdinaryName(getCurScope(), ObjCImpDecl? Sema::PCC_ObjCImplementation : Sema::PCC_ObjCInterface); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } // If we don't have an @ directive, parse it as a function definition. @@ -368,9 +384,6 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // erroneous r_brace would cause an infinite loop if not handled here. if (Tok.is(tok::r_brace)) break; - - // FIXME: as the name implies, this rule allows function definitions. - // We could pass a flag or check for functions during semantic analysis. ParsedAttributes attrs(AttrFactory); allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; @@ -379,8 +392,8 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // Otherwise, we have an @ directive, eat the @. SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, true); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCAtDirective(getCurScope()); + return cutOffParsing(); break; } @@ -433,9 +446,9 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, ObjCDeclSpec OCDS; // Parse property attribute list, if any. if (Tok.is(tok::l_paren)) - ParseObjCPropertyAttribute(OCDS, interfaceDecl); + ParseObjCPropertyAttribute(OCDS); - ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties, + ObjCPropertyCallback Callback(*this, allProperties, OCDS, AtLoc, MethodImplKind); // Parse all the comma separated declarators. @@ -450,8 +463,8 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // We break out of the big loop in two cases: when we see @end or when we see // EOF. In the former case, eat the @end. In the later case, emit an error. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtDirective(getCurScope(), ObjCImpDecl, true); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCAtDirective(getCurScope()); + return cutOffParsing(); } else if (Tok.isObjCAtKeyword(tok::objc_end)) ConsumeToken(); // the "end" identifier else @@ -459,7 +472,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. - Actions.ActOnAtEnd(getCurScope(), AtEnd, interfaceDecl, + Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods.data(), allMethods.size(), allProperties.data(), allProperties.size(), allTUVariables.data(), allTUVariables.size()); @@ -485,20 +498,21 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, /// weak /// unsafe_unretained /// -void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { +void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { assert(Tok.getKind() == tok::l_paren); - SourceLocation LHSLoc = ConsumeParen(); // consume '(' + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); while (1) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } const IdentifierInfo *II = Tok.getIdentifierInfo(); // If this is not an identifier at all, bail out early. if (II == 0) { - MatchRHSPunctuation(tok::r_paren, LHSLoc); + T.consumeClose(); return; } @@ -536,10 +550,10 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { if (Tok.is(tok::code_completion)) { if (IsSetter) - Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl); + Actions.CodeCompleteObjCPropertySetter(getCurScope()); else - Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCPropertyGetter(getCurScope()); + return cutOffParsing(); } @@ -577,7 +591,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { ConsumeToken(); } - MatchRHSPunctuation(tok::r_paren, LHSLoc); + T.consumeClose(); } /// objc-method-proto: @@ -590,14 +604,13 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { /// objc-method-attributes: [OBJC2] /// __attribute__((deprecated)) /// -Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl, - tok::ObjCKeywordKind MethodImplKind, +Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind, bool MethodDefinition) { assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); tok::TokenKind methodType = Tok.getKind(); SourceLocation mLoc = ConsumeToken(); - Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind, + Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind, MethodDefinition); // Since this rule is used for both method declarations and definitions, // the caller is (optionally) responsible for consuming the ';'. @@ -732,12 +745,15 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifiers objc-type-qualifier /// void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, - ObjCTypeNameContext Context) { + Declarator::TheContext Context) { + assert(Context == Declarator::ObjCParameterContext || + Context == Declarator::ObjCResultContext); + while (1) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPassingType(getCurScope(), DS, - Context == OTN_ParameterType); - ConsumeCodeCompletionToken(); + Context == Declarator::ObjCParameterContext); + return cutOffParsing(); } if (Tok.isNot(tok::identifier)) @@ -750,7 +766,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, ObjCDeclSpec::ObjCDeclQualifier Qual; switch (i) { - default: assert(0 && "Unknown decl qualifier"); + default: llvm_unreachable("Unknown decl qualifier"); case objc_in: Qual = ObjCDeclSpec::DQ_In; break; case objc_out: Qual = ObjCDeclSpec::DQ_Out; break; case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break; @@ -769,30 +785,95 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, } } +/// Take all the decl attributes out of the given list and add +/// them to the given attribute set. +static void takeDeclAttributes(ParsedAttributes &attrs, + AttributeList *list) { + while (list) { + AttributeList *cur = list; + list = cur->getNext(); + + if (!cur->isUsedAsTypeAttr()) { + // Clear out the next pointer. We're really completely + // destroying the internal invariants of the declarator here, + // but it doesn't matter because we're done with it. + cur->setNext(0); + attrs.add(cur); + } + } +} + +/// takeDeclAttributes - Take all the decl attributes from the given +/// declarator and add them to the given list. +static void takeDeclAttributes(ParsedAttributes &attrs, + Declarator &D) { + // First, take ownership of all attributes. + attrs.getPool().takeAllFrom(D.getAttributePool()); + attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool()); + + // Now actually move the attributes over. + takeDeclAttributes(attrs, D.getDeclSpec().getAttributes().getList()); + takeDeclAttributes(attrs, D.getAttributes()); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) + takeDeclAttributes(attrs, + const_cast<AttributeList*>(D.getTypeObject(i).getAttrs())); +} + /// objc-type-name: /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, - ObjCTypeNameContext Context) { + Declarator::TheContext context, + ParsedAttributes *paramAttrs) { + assert(context == Declarator::ObjCParameterContext || + context == Declarator::ObjCResultContext); + assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext)); + assert(Tok.is(tok::l_paren) && "expected ("); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + SourceLocation TypeStartLoc = Tok.getLocation(); + ObjCDeclContextSwitch ObjCDC(*this); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS, Context); + ParseObjCTypeQualifierList(DS, context); ParsedType Ty; if (isTypeSpecifierQualifier()) { - TypeResult TypeSpec = - ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS); - if (!TypeSpec.isInvalid()) - Ty = TypeSpec.get(); + // Parse an abstract declarator. + DeclSpec declSpec(AttrFactory); + declSpec.setObjCQualifiers(&DS); + ParseSpecifierQualifierList(declSpec); + Declarator declarator(declSpec, context); + ParseDeclarator(declarator); + + // If that's not invalid, extract a type. + if (!declarator.isInvalidType()) { + TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator); + if (!type.isInvalid()) + Ty = type.get(); + + // If we're parsing a parameter, steal all the decl attributes + // and add them to the decl spec. + if (context == Declarator::ObjCParameterContext) + takeDeclAttributes(*paramAttrs, declarator); + } + } else if (context == Declarator::ObjCResultContext && + Tok.is(tok::identifier)) { + if (!Ident_instancetype) + Ident_instancetype = PP.getIdentifierInfo("instancetype"); + + if (Tok.getIdentifierInfo() == Ident_instancetype) { + Ty = Actions.ActOnObjCInstanceType(Tok.getLocation()); + ConsumeToken(); + } } - + if (Tok.is(tok::r_paren)) - ConsumeParen(); + T.consumeClose(); else if (Tok.getLocation() == TypeStartLoc) { // If we didn't eat any tokens, then this isn't a type. Diag(Tok, diag::err_expected_type); @@ -800,7 +881,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, } else { // Otherwise, we found *something*, but didn't get a ')' in the right // place. Emit an error then return what we have as the type. - MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); } return Ty; } @@ -835,22 +916,22 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, /// Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, - Decl *IDecl, tok::ObjCKeywordKind MethodImplKind, bool MethodDefinition) { ParsingDeclRAIIObject PD(*this); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, - /*ReturnType=*/ ParsedType(), IDecl); - ConsumeCodeCompletionToken(); + /*ReturnType=*/ ParsedType()); + cutOffParsing(); + return 0; } // Parse the return type if present. ParsedType ReturnType; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType); + ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0); // If attributes exist before the method, parse them. ParsedAttributes methodAttrs(AttrFactory); @@ -859,8 +940,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, - ReturnType, IDecl); - ConsumeCodeCompletionToken(); + ReturnType); + cutOffParsing(); + return 0; } // Now parse the selector. @@ -876,7 +958,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, return 0; } - llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; + SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. if (getLang().ObjC2) @@ -885,7 +967,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, + mType, DSRet, ReturnType, selLoc, Sel, 0, CParamInfo.data(), CParamInfo.size(), methodAttrs.getList(), MethodImplKind, @@ -894,8 +976,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, return Result; } - llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; - llvm::SmallVector<Sema::ObjCArgInfo, 12> ArgInfos; + SmallVector<IdentifierInfo *, 12> KeyIdents; + SmallVector<SourceLocation, 12> KeyLocs; + SmallVector<Sema::ObjCArgInfo, 12> ArgInfos; ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); @@ -914,9 +997,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, + Declarator::ObjCParameterContext, + ¶mAttrs); // If attributes exist before the argument name, parse them. + // Regardless, collect all the attributes we've parsed so far. ArgInfo.ArgAttrs = 0; if (getLang().ObjC2) { MaybeParseGNUAttributes(paramAttrs); @@ -925,7 +1011,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { - ConsumeCodeCompletionToken(); KeyIdents.push_back(SelIdent); Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, @@ -933,8 +1018,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ReturnType, KeyIdents.data(), KeyIdents.size()); - KeyIdents.pop_back(); - break; + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -948,25 +1033,25 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfos.push_back(ArgInfo); KeyIdents.push_back(SelIdent); + KeyLocs.push_back(selLoc); // Make sure the attributes persist. allParamAttrs.takeAllFrom(paramAttrs.getPool()); // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { - ConsumeCodeCompletionToken(); Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, /*AtParameterName=*/false, ReturnType, KeyIdents.data(), KeyIdents.size()); - break; + cutOffParsing(); + return 0; } // Check for another keyword selector. - SourceLocation Loc; - SelIdent = ParseObjCSelectorPiece(Loc); + SelIdent = ParseObjCSelectorPiece(selLoc); if (!SelIdent && Tok.isNot(tok::colon)) break; // We have a selector or a colon, continue parsing. @@ -1001,23 +1086,18 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (getLang().ObjC2) MaybeParseGNUAttributes(methodAttrs); - if (KeyIdents.size() == 0) { - // Leave prototype scope. - PrototypeScope.Exit(); + if (KeyIdents.size() == 0) return 0; - } Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); Decl *Result = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, - selLoc, Sel, &ArgInfos[0], + mType, DSRet, ReturnType, + KeyLocs, Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs.getList(), MethodImplKind, isVariadic, MethodDefinition); - // Leave prototype scope. - PrototypeScope.Exit(); PD.complete(Result); return Result; @@ -1027,21 +1107,22 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, /// '<' identifier-list '>' /// bool Parser:: -ParseObjCProtocolReferences(llvm::SmallVectorImpl<Decl *> &Protocols, - llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs, +ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, + SmallVectorImpl<SourceLocation> &ProtocolLocs, bool WarnOnDeclarations, SourceLocation &LAngleLoc, SourceLocation &EndLoc) { assert(Tok.is(tok::less) && "expected <"); LAngleLoc = ConsumeToken(); // the "<" - llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents; + SmallVector<IdentifierLocPair, 8> ProtocolIdents; while (1) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), ProtocolIdents.size()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return true; } if (Tok.isNot(tok::identifier)) { @@ -1080,8 +1161,8 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C"); SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolDecl; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SmallVector<Decl *, 8> ProtocolDecl; + SmallVector<SourceLocation, 8> ProtocolLocs; bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, LAngleLoc, EndProtoLoc); DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), @@ -1116,11 +1197,13 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, tok::ObjCKeywordKind visibility, SourceLocation atLoc) { assert(Tok.is(tok::l_brace) && "expected {"); - llvm::SmallVector<Decl *, 32> AllIvarDecls; - + SmallVector<Decl *, 32> AllIvarDecls; + ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); + ObjCDeclContextSwitch ObjCDC(*this); - SourceLocation LBraceLoc = ConsumeBrace(); // the "{" + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); // While we still have something to read, read the instance variables. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -1140,7 +1223,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtVisibility(getCurScope()); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } switch (Tok.getObjCKeywordID()) { @@ -1160,26 +1243,28 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_ObjCInstanceVariableList); - ConsumeCodeCompletionToken(); + return cutOffParsing(); } struct ObjCIvarCallback : FieldCallback { Parser &P; Decl *IDecl; tok::ObjCKeywordKind visibility; - llvm::SmallVectorImpl<Decl *> &AllIvarDecls; + SmallVectorImpl<Decl *> &AllIvarDecls; ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V, - llvm::SmallVectorImpl<Decl *> &AllIvarDecls) : + SmallVectorImpl<Decl *> &AllIvarDecls) : P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { } Decl *invoke(FieldDeclarator &FD) { + P.Actions.ActOnObjCContainerStartDefinition(IDecl); // Install the declarator into the interface decl. Decl *Field = P.Actions.ActOnIvar(P.getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), - IDecl, FD.D, FD.BitfieldSize, visibility); + FD.D, FD.BitfieldSize, visibility); + P.Actions.ActOnObjCContainerFinishDefinition(); if (Field) AllIvarDecls.push_back(Field); return Field; @@ -1198,13 +1283,16 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, SkipUntil(tok::r_brace, true, true); } } - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - Actions.ActOnLastBitfield(RBraceLoc, interfaceDecl, AllIvarDecls); + T.consumeClose(); + + Actions.ActOnObjCContainerStartDefinition(interfaceDecl); + Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls); + Actions.ActOnObjCContainerFinishDefinition(); // Call ActOnFields() even if we don't have any decls. This is useful // for code rewriting tools that need to be aware of the empty list. Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, - AllIvarDecls.data(), AllIvarDecls.size(), - LBraceLoc, RBraceLoc, 0); + AllIvarDecls, + T.getOpenLocation(), T.getCloseLocation(), 0); return; } @@ -1232,7 +1320,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolDecl(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -1251,7 +1340,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, } if (Tok.is(tok::comma)) { // list of forward declarations. - llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs; + SmallVector<IdentifierLocPair, 8> ProtocolRefs; ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc)); // Parse the list of forward declarations. @@ -1282,8 +1371,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, // Last, and definitely not least, parse a protocol declaration. SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolRefs; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SmallVector<Decl *, 8> ProtocolRefs; + SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, LAngleLoc, EndProtoLoc)) @@ -1295,7 +1384,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc, attrs.getList()); - ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); + + ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType); return ProtoType; } @@ -1318,7 +1408,8 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( // Code completion after '@implementation'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationDecl(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -1337,7 +1428,8 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return 0; } if (Tok.is(tok::identifier)) { @@ -1356,6 +1448,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( Decl *ImplCatType = Actions.ActOnStartCategoryImplementation( atLoc, nameId, nameLoc, categoryId, categoryLoc); + ObjCImpDecl = ImplCatType; PendingObjCImpDecl.push_back(ObjCImpDecl); return 0; @@ -1378,29 +1471,38 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( superClassId, superClassLoc); if (Tok.is(tok::l_brace)) // we have ivars - ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, - tok::objc_private, atLoc); + ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc); + ObjCImpDecl = ImplClsType; PendingObjCImpDecl.push_back(ObjCImpDecl); - return 0; } -Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { assert(Tok.isObjCAtKeyword(tok::objc_end) && "ParseObjCAtEndDeclaration(): Expected @end"); - Decl *Result = ObjCImpDecl; ConsumeToken(); // the "end" identifier + SmallVector<Decl *, 8> DeclsInGroup; + Actions.DefaultSynthesizeProperties(getCurScope(), ObjCImpDecl); + for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) { + Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); + DeclsInGroup.push_back(D); + } + DeclsInGroup.push_back(ObjCImpDecl); + if (ObjCImpDecl) { - Actions.ActOnAtEnd(getCurScope(), atEnd, ObjCImpDecl); - ObjCImpDecl = 0; + Actions.ActOnAtEnd(getCurScope(), atEnd); PendingObjCImpDecl.pop_back(); } - else { + else // missing @implementation Diag(atEnd.getBegin(), diag::err_expected_implementation); - } - return Result; + + LateParsedObjCMethods.clear(); + ObjCImpDecl = 0; + return Actions.BuildDeclaratorGroup( + DeclsInGroup.data(), DeclsInGroup.size(), false); } Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() { @@ -1408,7 +1510,7 @@ Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() { if (PendingObjCImpDecl.empty()) return Actions.ConvertDeclToDeclGroup(0); Decl *ImpDecl = PendingObjCImpDecl.pop_back_val(); - Actions.ActOnAtEnd(getCurScope(), SourceRange(), ImpDecl); + Actions.ActOnAtEnd(getCurScope(), SourceRange()); return Actions.ConvertDeclToDeclGroup(ImpDecl); } @@ -1455,8 +1557,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope(), ObjCImpDecl); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -1474,9 +1577,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { ConsumeToken(); // consume '=' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId, - ObjCImpDecl); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -1486,7 +1589,7 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { propertyIvar = Tok.getIdentifierInfo(); propertyIvarLoc = ConsumeToken(); // consume ivar-name } - Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, propertyId, propertyIvar, propertyIvarLoc); if (Tok.isNot(tok::comma)) break; @@ -1509,8 +1612,9 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { ConsumeToken(); // consume dynamic while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope(), ObjCImpDecl); - ConsumeCodeCompletionToken(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); + cutOffParsing(); + return 0; } if (Tok.isNot(tok::identifier)) { @@ -1521,7 +1625,7 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name - Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, ObjCImpDecl, + Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, propertyId, 0, SourceLocation()); if (Tok.isNot(tok::comma)) @@ -1560,31 +1664,46 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lparen_after) << "@synchronized"; return StmtError(); } + + // The operand is surrounded with parentheses. ConsumeParen(); // '(' - ExprResult Res(ParseExpression()); - if (Res.isInvalid()) { - SkipUntil(tok::semi); - return StmtError(); - } - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_lbrace); - return StmtError(); + ExprResult operand(ParseExpression()); + + if (Tok.is(tok::r_paren)) { + ConsumeParen(); // ')' + } else { + if (!operand.isInvalid()) + Diag(Tok, diag::err_expected_rparen); + + // Skip forward until we see a left brace, but don't consume it. + SkipUntil(tok::l_brace, true, true); } - ConsumeParen(); // ')' + + // Require a compound statement. if (Tok.isNot(tok::l_brace)) { - Diag(Tok, diag::err_expected_lbrace); + if (!operand.isInvalid()) + Diag(Tok, diag::err_expected_lbrace); return StmtError(); } - // Enter a scope to hold everything within the compound stmt. Compound - // statements can always hold declarations. - ParseScope BodyScope(this, Scope::DeclScope); - StmtResult SynchBody(ParseCompoundStatementBody()); + // Check the @synchronized operand now. + if (!operand.isInvalid()) + operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take()); - BodyScope.Exit(); - if (SynchBody.isInvalid()) - SynchBody = Actions.ActOnNullStmt(Tok.getLocation()); - return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.take(), SynchBody.take()); + // Parse the compound statement within a new scope. + ParseScope bodyScope(this, Scope::DeclScope); + StmtResult body(ParseCompoundStatementBody()); + bodyScope.Exit(); + + // If there was a semantic or parse error earlier with the + // operand, fail now. + if (operand.isInvalid()) + return StmtError(); + + if (body.isInvalid()) + body = Actions.ActOnNullStmt(Tok.getLocation()); + + return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get()); } /// objc-try-catch-statement: @@ -1724,7 +1843,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// Decl *Parser::ParseObjCMethodDefinition() { - Decl *MDecl = ParseObjCMethodPrototype(ObjCImpDecl); + Decl *MDecl = ParseObjCMethodPrototype(); PrettyDeclStackTraceEntry CrashInfo(Actions, MDecl, Tok.getLocation(), "parsing Objective-C method"); @@ -1749,42 +1868,26 @@ Decl *Parser::ParseObjCMethodDefinition() { if (Tok.isNot(tok::l_brace)) return 0; } - SourceLocation BraceLoc = Tok.getLocation(); - - // Enter a scope for the method body. - ParseScope BodyScope(this, - Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); - - // Tell the actions module that we have entered a method definition with the - // specified Declarator for the method. - Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - - if (PP.isCodeCompletionEnabled()) { - if (trySkippingFunctionBodyForCodeCompletion()) { - BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(MDecl, 0); - } - } - - StmtResult FnBody(ParseCompoundStatementBody()); - - // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid()) - FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, - MultiStmtArg(Actions), false); - - // Leave the function body scope. - BodyScope.Exit(); - - // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); + // Allow the rest of sema to find private method decl implementations. + if (MDecl) + Actions.AddAnyMethodToGlobalPool(MDecl); + + // Consume the tokens and store them for later parsing. + LexedMethod* LM = new LexedMethod(this, MDecl); + LateParsedObjCMethods.push_back(LM); + CachedTokens &Toks = LM->Toks; + // Begin by storing the '{' token. + Toks.push_back(Tok); + ConsumeBrace(); + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); return MDecl; } StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtStatement(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); return StmtError(); } @@ -1818,7 +1921,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { case tok::code_completion: Actions.CodeCompleteObjCAtExpression(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); return ExprError(); case tok::string_literal: // primary-expression: string-literal @@ -1984,8 +2087,7 @@ ExprResult Parser::ParseObjCMessageExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMessageReceiver(getCurScope()); - ConsumeCodeCompletionToken(); - SkipUntil(tok::r_square); + cutOffParsing(); return ExprError(); } @@ -2116,22 +2218,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, 0, 0, false); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return ExprError(); } // Parse objc-selector SourceLocation Loc; IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); - SourceLocation SelectorLoc = Loc; - - llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; + SmallVector<IdentifierInfo *, 12> KeyIdents; + SmallVector<SourceLocation, 12> KeyLocs; ExprVector KeyExprs(Actions); if (Tok.is(tok::colon)) { while (1) { // Each iteration parses a single keyword argument. KeyIdents.push_back(selIdent); + KeyLocs.push_back(Loc); if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon); @@ -2162,8 +2265,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.size(), /*AtArgumentEpression=*/true); - ConsumeCodeCompletionToken(); - SkipUntil(tok::r_square); + cutOffParsing(); return ExprError(); } @@ -2196,8 +2298,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.data(), KeyIdents.size(), /*AtArgumentEpression=*/false); - ConsumeCodeCompletionToken(); - SkipUntil(tok::r_square); + cutOffParsing(); return ExprError(); } @@ -2248,24 +2349,26 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation RBracLoc = ConsumeBracket(); // consume ']' unsigned nKeys = KeyIdents.size(); - if (nKeys == 0) + if (nKeys == 0) { KeyIdents.push_back(selIdent); + KeyLocs.push_back(Loc); + } Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); if (SuperLoc.isValid()) return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel, - LBracLoc, SelectorLoc, RBracLoc, + LBracLoc, KeyLocs, RBracLoc, MultiExprArg(Actions, KeyExprs.take(), KeyExprs.size())); else if (ReceiverType) return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel, - LBracLoc, SelectorLoc, RBracLoc, + LBracLoc, KeyLocs, RBracLoc, MultiExprArg(Actions, KeyExprs.take(), KeyExprs.size())); return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel, - LBracLoc, SelectorLoc, RBracLoc, + LBracLoc, KeyLocs, RBracLoc, MultiExprArg(Actions, KeyExprs.take(), KeyExprs.size())); @@ -2278,7 +2381,7 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string // expressions. At this point, we know that the only valid thing that starts // with '@' is an @"". - llvm::SmallVector<SourceLocation, 4> AtLocs; + SmallVector<SourceLocation, 4> AtLocs; ExprVector AtStrings(Actions); AtLocs.push_back(AtLoc); AtStrings.push_back(Res.release()); @@ -2312,17 +2415,19 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode"); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); TypeResult Ty = ParseTypeName(); - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); if (Ty.isInvalid()) return ExprError(); - return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, - Ty.get(), RParenLoc)); + return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, + T.getOpenLocation(), Ty.get(), + T.getCloseLocation())); } /// objc-protocol-expression @@ -2334,7 +2439,8 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol"); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected_ident)); @@ -2342,10 +2448,11 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { IdentifierInfo *protocolId = Tok.getIdentifierInfo(); ConsumeToken(); - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, - LParenLoc, RParenLoc)); + T.getOpenLocation(), + T.getCloseLocation())); } /// objc-selector-expression @@ -2356,15 +2463,16 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector"); - llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; - SourceLocation LParenLoc = ConsumeParen(); + SmallVector<IdentifierInfo *, 12> KeyIdents; SourceLocation sLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), KeyIdents.size()); - ConsumeCodeCompletionToken(); - MatchRHSPunctuation(tok::r_paren, LParenLoc); + cutOffParsing(); return ExprError(); } @@ -2391,8 +2499,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), KeyIdents.size()); - ConsumeCodeCompletionToken(); - MatchRHSPunctuation(tok::r_paren, LParenLoc); + cutOffParsing(); return ExprError(); } @@ -2404,8 +2511,52 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { break; } } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, - LParenLoc, RParenLoc)); + T.getOpenLocation(), + T.getCloseLocation())); } + +Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { + + assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + + // MDecl might be null due to error in method prototype, etc. + Decl *MDecl = LM.D; + // Consume the previously pushed token. + ConsumeAnyToken(); + + assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'"); + SourceLocation BraceLoc = Tok.getLocation(); + // Enter a scope for the method body. + ParseScope BodyScope(this, + Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a method definition with the + // specified Declarator for the method. + Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); + + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(MDecl, 0); + } + } + + StmtResult FnBody(ParseCompoundStatementBody()); + + // If the function body could not be parsed, make a bogus compoundstmt. + if (FnBody.isInvalid()) + FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, + MultiStmtArg(Actions), false); + + // Leave the function body scope. + BodyScope.Exit(); + + return Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index c30ab75..2ccb6ea 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -38,7 +38,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, SourceLocation VisLoc = VisTok.getLocation(); Token Tok; - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); @@ -49,20 +49,20 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, VisType = 0; } else if (PushPop && PushPop->isStr("push")) { IsPush = true; - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "visibility"; return; } - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); VisType = Tok.getIdentifierInfo(); if (!VisType) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "visibility"; return; } - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "visibility"; @@ -73,7 +73,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, << "visibility"; return; } - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "visibility"; @@ -297,7 +297,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, } // Lex the declaration reference(s). - llvm::SmallVector<Token, 5> Identifiers; + SmallVector<Token, 5> Identifiers; SourceLocation RParenLoc; bool LexID = true; @@ -451,8 +451,11 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, } OpenCLOptions &f = Actions.getOpenCLOptions(); - if (ename->isStr("all")) { -#define OPENCLEXT(nm) f.nm = state; + // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, + // overriding all previously issued extension directives, but only if the + // behavior is set to disable." + if (state == 0 && ename->isStr("all")) { +#define OPENCLEXT(nm) f.nm = 0; #include "clang/Basic/OpenCLExtensions.def" } #define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index b91bca5..a2b7cdd 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -79,7 +79,7 @@ StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { const char *SemiError = 0; StmtResult Res; - + ParenBraceBracketBalancer BalancerRAIIObj(*this); ParsedAttributesWithRange attrs(AttrFactory); @@ -100,20 +100,25 @@ Retry: case tok::code_completion: Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); - ConsumeCodeCompletionToken(); - return ParseStatementOrDeclaration(Stmts, OnlyStatement); - + cutOffParsing(); + return StmtError(); + case tok::identifier: { Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement return ParseLabeledStatement(attrs); } - + if (Next.isNot(tok::coloncolon)) { CXXScopeSpec SS; IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); + + if (getLang().CPlusPlus) + CheckForTemplateAndDigraph(Next, ParsedType(), + /*EnteringContext=*/false, *Name, SS); + Sema::NameClassification Classification = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next); switch (Classification.getKind()) { @@ -125,11 +130,11 @@ Retry: Tok.setKind(Name->getTokenID()); goto Retry; } - + // Fall through via the normal error path. // FIXME: This seems like it could only happen for context-sensitive // keywords. - + case Sema::NC_Error: // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. @@ -137,33 +142,33 @@ Retry: if (Tok.is(tok::semi)) ConsumeToken(); return StmtError(); - + case Sema::NC_Unknown: // Either we don't know anything about this identifier, or we know that - // we're in a syntactic context we haven't handled yet. - break; - + // we're in a syntactic context we haven't handled yet. + break; + case Sema::NC_Type: Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Classification.getType()); Tok.setAnnotationEndLoc(NameLoc); PP.AnnotateCachedTokens(Tok); break; - + case Sema::NC_Expression: Tok.setKind(tok::annot_primary_expr); setExprAnnotation(Tok, Classification.getExpression()); Tok.setAnnotationEndLoc(NameLoc); PP.AnnotateCachedTokens(Tok); break; - + case Sema::NC_TypeTemplate: case Sema::NC_FunctionTemplate: { ConsumeToken(); // the identifier UnqualifiedId Id; Id.setIdentifier(Name, NameLoc); if (AnnotateTemplateIdToken( - TemplateTy::make(Classification.getTemplateName()), + TemplateTy::make(Classification.getTemplateName()), Classification.getTemplateNameKind(), SS, Id, SourceLocation(), /*AllowTypeAnnotation=*/false)) { @@ -172,10 +177,10 @@ Retry: SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); if (Tok.is(tok::semi)) ConsumeToken(); - return StmtError(); + return StmtError(); } - - // If the next token is '::', jump right into parsing a + + // If the next token is '::', jump right into parsing a // nested-name-specifier. We don't want to leave the template-id // hanging. if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){ @@ -184,22 +189,22 @@ Retry: SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); if (Tok.is(tok::semi)) ConsumeToken(); - return StmtError(); + return StmtError(); } - + // We've annotated a template-id, so try again now. goto Retry; } - + case Sema::NC_NestedNameSpecifier: // FIXME: Implement this! break; } } - + // Fall through } - + default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; @@ -224,10 +229,8 @@ Retry: case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(attrs); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' - SourceLocation LeadingEmptyMacroLoc; - if (Tok.hasLeadingEmptyMacro()) - LeadingEmptyMacroLoc = PP.getLastEmptyMacroExpansionLoc(); - return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc); + bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); + return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro); } case tok::kw_if: // C99 6.8.4.1: if-statement @@ -297,7 +300,7 @@ Retry: StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; - + // FIXME: Use the attributes // expression[opt] ';' ExprResult Expr(ParseExpression()); @@ -310,18 +313,18 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { ConsumeToken(); return StmtError(); } - + if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && Actions.CheckCaseExpression(Expr.get())) { // If a constant expression is followed by a colon inside a switch block, // suggest a missing case keyword. Diag(OldToken, diag::err_expected_case_before_expression) << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); - + // Recover parsing as a case statement. return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr); } - + // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); @@ -458,12 +461,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); - + LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); if (AttributeList *Attrs = attrs.getList()) Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); - + return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, SubStmt.get()); } @@ -499,7 +502,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, // DeepestParsedCaseStmt - This is the deepest statement we have parsed, which // gets updated each time a new case is parsed, and whose body is unset so // far. When parsing 'case 4', this is the 'case 3' node. - StmtTy *DeepestParsedCaseStmt = 0; + Stmt *DeepestParsedCaseStmt = 0; // While we have case statements, eat and stack them. SourceLocation ColonLoc; @@ -509,14 +512,15 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(getCurScope()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return StmtError(); } - + /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. /// Disable this form of error recovery while we're parsing the case /// expression. ColonProtectionRAIIObject ColonProtection(*this); - + ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); MissingCase = false; if (LHS.isInvalid()) { @@ -537,7 +541,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, return StmtError(); } } - + ColonProtection.restore(); if (Tok.is(tok::colon)) { @@ -554,7 +558,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, << FixItHint::CreateInsertion(ExpectedLoc, ":"); ColonLoc = ExpectedLoc; } - + StmtResult Case = Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc, RHS.get(), ColonLoc); @@ -631,7 +635,7 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { << FixItHint::CreateInsertion(ExpectedLoc, ":"); ColonLoc = ExpectedLoc; } - + // Diagnose the common error "switch (X) {... default: }", which is not valid. if (Tok.is(tok::r_brace)) { SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); @@ -704,8 +708,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { Tok.getLocation(), "in compound statement ('{}')"); InMessageExpressionRAIIObject InMessage(*this, false); - - SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) + return StmtError(); StmtVector Stmts(Actions); @@ -714,40 +719,40 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___label__)) { SourceLocation LabelLoc = ConsumeToken(); Diag(LabelLoc, diag::ext_gnu_local_label); - - llvm::SmallVector<Decl *, 8> DeclsInGroup; + + SmallVector<Decl *, 8> DeclsInGroup; while (1) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); break; } - + IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc)); - + if (!Tok.is(tok::comma)) break; ConsumeToken(); } - + DeclSpec DS(AttrFactory); DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), DeclsInGroup.size()); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); - + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); if (R.isUsable()) Stmts.push_back(R.release()); } - + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (Tok.is(tok::annot_pragma_unused)) { HandlePragmaUnused(); continue; } - if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsStatement(Stmts); continue; @@ -803,13 +808,15 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // We broke out of the while loop because we found a '}' or EOF. if (Tok.isNot(tok::r_brace)) { Diag(Tok, diag::err_expected_rbrace); - Diag(LBraceLoc, diag::note_matching) << "{"; + Diag(T.getOpenLocation(), diag::note_matching) << "{"; return StmtError(); } - SourceLocation RBraceLoc = ConsumeBrace(); - return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, move_arg(Stmts), - isStmtExpr); + if (T.consumeClose()) + return StmtError(); + + return Actions.ActOnCompoundStmt(T.getOpenLocation(), T.getCloseLocation(), + move_arg(Stmts), isStmtExpr); } /// ParseParenExprOrCondition: @@ -827,13 +834,15 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean) { - SourceLocation LParenLoc = ConsumeParen(); - if (getLang().CPlusPlus) + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + if (getLang().CPlusPlus) ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); else { ExprResult = ParseExpression(); DeclResult = 0; - + // If required, convert to a boolean value. if (!ExprResult.isInvalid() && ConvertToBoolean) ExprResult @@ -852,7 +861,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, } // Otherwise the condition is valid or the rparen is present. - MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); return false; } @@ -950,9 +959,13 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { C99orCXX && Tok.isNot(tok::l_brace)); ElseStmt = ParseStatement(); - + // Pop the 'else' scope if needed. InnerScope.Exit(); + } else if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteAfterIf(getCurScope()); + cutOffParsing(); + return StmtError(); } IfScope.Exit(); @@ -1027,7 +1040,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar); if (Switch.isInvalid()) { - // Skip the switch body. + // Skip the switch body. // FIXME: This is not optimal recovery, but parsing the body is more // dangerous due to the presence of case and default statements, which // will have no place to connect back with the switch. @@ -1038,7 +1051,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { SkipUntil(tok::semi); return move(Switch); } - + // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -1063,7 +1076,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { if (Body.isInvalid()) // FIXME: Remove the case statement list from the Switch statement. Body = Actions.ActOnNullStmt(Tok.getLocation()); - + return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get()); } @@ -1196,16 +1209,17 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { } // Parse the parenthesized condition. - SourceLocation LPLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); ExprResult Cond = ParseExpression(); - SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc); + T.consumeClose(); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); - return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, LPLoc, - Cond.get(), RPLoc); + return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(), + Cond.get(), T.getCloseLocation()); } /// ParseForStatement @@ -1265,7 +1279,9 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { ParseScope ForScope(this, ScopeFlags); - SourceLocation LParenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ExprResult Value; bool ForEach = false, ForRange = false; @@ -1276,14 +1292,15 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { ForRangeInit ForRangeInit; FullExprArg ThirdPart(Actions); Decl *SecondVar = 0; - + if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), + Actions.CodeCompleteOrdinaryName(getCurScope(), C99orCXXorObjC? Sema::PCC_ForInit : Sema::PCC_Expression); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return StmtError(); } - + // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. @@ -1302,13 +1319,16 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; StmtVector Stmts(Actions); - DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, + DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, DeclEnd, attrs, false, MightBeForRangeStmt ? &ForRangeInit : 0); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInit.ParsedForRangeDecl()) { + if (!getLang().CPlusPlus0x) + Diag(ForRangeInit.ColonLoc, diag::ext_for_range); + ForRange = true; } else if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); @@ -1316,10 +1336,11 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' - + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCForCollection(getCurScope(), DG); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return StmtError(); } Collection = ParseExpression(); } else { @@ -1342,10 +1363,11 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { ConsumeToken(); } else if (ForEach) { ConsumeToken(); // consume 'in' - + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy()); - ConsumeCodeCompletionToken(); + cutOffParsing(); + return StmtError(); } Collection = ParseExpression(); } else { @@ -1373,7 +1395,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { else { Second = ParseExpression(); if (!Second.isInvalid()) - Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc, + Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc, Second.get()); } SecondPartIsInvalid = Second.isInvalid(); @@ -1399,18 +1421,27 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { } } // Match the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + T.consumeClose(); // We need to perform most of the semantic analysis for a C++0x for-range // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. StmtResult ForRangeStmt; - if (ForRange) - ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc, + if (ForRange) { + ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, T.getOpenLocation(), FirstPart.take(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), - RParenLoc); + T.getCloseLocation()); + + + // Similarly, we need to do the semantic analysis for a for-range + // statement immediately in order to close over temporaries correctly. + } else if (ForEach) { + if (!Collection.isInvalid()) + Collection = + Actions.ActOnObjCForCollectionOperand(ForLoc, Collection.take()); + } // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -1439,18 +1470,18 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { return StmtError(); if (ForEach) - // FIXME: It isn't clear how to communicate the late destruction of - // C++ temporaries used to create the collection. - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, - FirstPart.take(), - Collection.take(), RParenLoc, - Body.take()); + return Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(), + FirstPart.take(), + Collection.take(), + T.getCloseLocation(), + Body.take()); if (ForRange) return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take()); - return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, - SecondVar, ThirdPart, RParenLoc, Body.take()); + return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.take(), + SecondPart, SecondVar, ThirdPart, + T.getCloseLocation(), Body.take()); } /// ParseGotoStatement @@ -1529,11 +1560,10 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { if (Tok.isNot(tok::semi)) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteReturn(getCurScope()); - ConsumeCodeCompletionToken(); - SkipUntil(tok::semi, false, true); + cutOffParsing(); return StmtError(); } - + // FIXME: This is a hack to allow something like C++0x's generalized // initializer lists, but only enough of this feature to allow Clang to // parse libstdc++ 4.5's headers. @@ -1552,30 +1582,105 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { return Actions.ActOnReturnStmt(ReturnLoc, R.take()); } -/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this -/// routine is called to skip/ignore tokens that comprise the MS asm statement. -StmtResult Parser::FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc) { - SourceLocation EndLoc; - if (Tok.is(tok::l_brace)) { - unsigned short savedBraceCount = BraceCount; - do { - EndLoc = Tok.getLocation(); - ConsumeAnyToken(); - } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); - } else { - // From the MS website: If used without braces, the __asm keyword means - // that the rest of the line is an assembly-language statement. - SourceManager &SrcMgr = PP.getSourceManager(); +/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, +/// this routine is called to collect the tokens for an MS asm statement. +StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { + SourceManager &SrcMgr = PP.getSourceManager(); + SourceLocation EndLoc = AsmLoc; + do { + bool InBraces = false; + unsigned short savedBraceCount = 0; + bool InAsmComment = false; + FileID FID; + unsigned LineNo = 0; + unsigned NumTokensRead = 0; + SourceLocation LBraceLoc; + + if (Tok.is(tok::l_brace)) { + // Braced inline asm: consume the opening brace. + InBraces = true; + savedBraceCount = BraceCount; + EndLoc = LBraceLoc = ConsumeBrace(); + ++NumTokensRead; + } else { + // Single-line inline asm; compute which line it is on. + std::pair<FileID, unsigned> ExpAsmLoc = + SrcMgr.getDecomposedExpansionLoc(EndLoc); + FID = ExpAsmLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); + } + SourceLocation TokLoc = Tok.getLocation(); - unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc); do { + // If we hit EOF, we're done, period. + if (Tok.is(tok::eof)) + break; + // When we consume the closing brace, we're done. + if (InBraces && BraceCount == savedBraceCount) + break; + + if (!InAsmComment && Tok.is(tok::semi)) { + // A semicolon in an asm is the start of a comment. + InAsmComment = true; + if (InBraces) { + // Compute which line the comment is on. + std::pair<FileID, unsigned> ExpSemiLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + FID = ExpSemiLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); + } + } else if (!InBraces || InAsmComment) { + // If end-of-line is significant, check whether this token is on a + // new line. + std::pair<FileID, unsigned> ExpLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + if (ExpLoc.first != FID || + SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { + // If this is a single-line __asm, we're done. + if (!InBraces) + break; + // We're no longer in a comment. + InAsmComment = false; + } else if (!InAsmComment && Tok.is(tok::r_brace)) { + // Single-line asm always ends when a closing brace is seen. + // FIXME: This is compatible with Apple gcc's -fasm-blocks; what + // does MSVC do here? + break; + } + } + + // Consume the next token; make sure we don't modify the brace count etc. + // if we are in a comment. EndLoc = TokLoc; - ConsumeAnyToken(); + if (InAsmComment) + PP.Lex(Tok); + else + ConsumeAnyToken(); TokLoc = Tok.getLocation(); - } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) && - Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && - Tok.isNot(tok::eof)); - } + ++NumTokensRead; + } while (1); + + if (InBraces && BraceCount != savedBraceCount) { + // __asm without closing brace (this can happen at EOF). + Diag(Tok, diag::err_expected_rbrace); + Diag(LBraceLoc, diag::note_matching) << "{"; + return StmtError(); + } else if (NumTokensRead == 0) { + // Empty __asm. + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + // Multiple adjacent asm's form together into a single asm statement + // in the AST. + if (!Tok.is(tok::kw_asm)) + break; + EndLoc = ConsumeToken(); + } while (1); + // FIXME: Need to actually grab the data and pass it on to Sema. Ideally, + // what Sema wants is a string of the entire inline asm, with one instruction + // per line and all the __asm keywords stripped out, and a way of mapping + // from any character of that string to its location in the original source + // code. I'm not entirely sure how to go about that, though. Token t; t.setKind(tok::string_literal); t.setLiteralData("\"/*FIXME: not done*/\""); @@ -1611,20 +1716,24 @@ StmtResult Parser::FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc) { /// asm-clobbers ',' asm-string-literal /// /// [MS] ms-asm-statement: -/// '__asm' assembly-instruction ';'[opt] -/// '__asm' '{' assembly-instruction-list '}' ';'[opt] +/// ms-asm-block +/// ms-asm-block ms-asm-statement +/// +/// [MS] ms-asm-block: +/// '__asm' ms-asm-line '\n' +/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] /// -/// [MS] assembly-instruction-list: -/// assembly-instruction ';'[opt] -/// assembly-instruction-list ';' assembly-instruction ';'[opt] +/// [MS] ms-asm-instruction-block +/// ms-asm-line +/// ms-asm-line '\n' ms-asm-instruction-block /// StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); - if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { + if (getLang().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { msAsm = true; - return FuzzyParseMicrosoftAsmStatement(AsmLoc); + return ParseMicrosoftAsmStatement(AsmLoc); } DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); @@ -1643,25 +1752,26 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { SkipUntil(tok::r_paren); return StmtError(); } - Loc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); ExprResult AsmString(ParseAsmStringLiteral()); if (AsmString.isInvalid()) return StmtError(); - llvm::SmallVector<IdentifierInfo *, 4> Names; + SmallVector<IdentifierInfo *, 4> Names; ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); if (Tok.is(tok::r_paren)) { // We have a simple asm expression like 'asm("foo")'. - SourceLocation RParenLoc = ConsumeParen(); + T.consumeClose(); return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, - /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, + /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers), - RParenLoc); + T.getCloseLocation()); } // Parse Outputs, if present. @@ -1670,12 +1780,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // In C++ mode, parse "::" like ": :". AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); - + if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } - + unsigned NumOutputs = Names.size(); // Parse Inputs, if present. @@ -1688,7 +1798,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); } - + if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); @@ -1721,12 +1831,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); + T.consumeClose(); return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers), - RParenLoc); + T.getCloseLocation()); } /// ParseAsmOperands - Parse the asm-operands production as used by @@ -1742,9 +1852,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { /// // // FIXME: Avoid unnecessary std::string trashing. -bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, - llvm::SmallVectorImpl<ExprTy *> &Constraints, - llvm::SmallVectorImpl<ExprTy *> &Exprs) { +bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, + SmallVectorImpl<Expr *> &Constraints, + SmallVectorImpl<Expr *> &Exprs) { // 'asm-operands' isn't present? if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; @@ -1752,7 +1862,8 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, while (1) { // Read the [id] if present. if (Tok.is(tok::l_square)) { - SourceLocation Loc = ConsumeBracket(); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); @@ -1764,7 +1875,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, ConsumeToken(); Names.push_back(II); - MatchRHSPunctuation(tok::r_square, Loc); + T.consumeClose(); } else Names.push_back(0); @@ -1782,9 +1893,10 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, } // Read the parenthesized expression. - SourceLocation OpenLoc = ConsumeParen(); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); ExprResult Res(ParseExpression()); - MatchRHSPunctuation(tok::r_paren, OpenLoc); + T.consumeClose(); if (Res.isInvalid()) { SkipUntil(tok::r_paren); return true; @@ -1808,7 +1920,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { return Actions.ActOnFinishFunctionBody(Decl, 0); } } - + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1841,6 +1953,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { // Constructor initializer list? if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); + else + Actions.ActOnDefaultCtorInitializers(Decl); if (PP.isCodeCompletionEnabled()) { if (trySkippingFunctionBodyForCodeCompletion()) { @@ -1977,8 +2091,8 @@ StmtResult Parser::ParseCXXCatchBlock() { SourceLocation CatchLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) return StmtError(); // C++ 3.3.2p3: @@ -1999,7 +2113,8 @@ StmtResult Parser::ParseCXXCatchBlock() { } else ConsumeToken(); - if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return StmtError(); if (Tok.isNot(tok::l_brace)) @@ -2018,7 +2133,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { bool Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - + if (Tok.isNot(tok::l_brace)) { Diag(Tok, diag::err_expected_lbrace); return; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 9eab40a..3d68a4a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -26,12 +26,16 @@ using namespace clang; Decl * Parser::ParseDeclarationStartingWithTemplate(unsigned Context, SourceLocation &DeclEnd, - AccessSpecifier AS) { - if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) + AccessSpecifier AS, + AttributeList *AccessAttrs) { + ObjCDeclContextSwitch ObjCDC(*this); + + if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(), - DeclEnd); - - return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); + DeclEnd); + } + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, + AccessAttrs); } /// \brief RAII class that manages the template parameter depth. @@ -75,7 +79,8 @@ namespace { Decl * Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, - AccessSpecifier AS) { + AccessSpecifier AS, + AttributeList *AccessAttrs) { assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Token does not start a template declaration."); @@ -129,7 +134,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; - llvm::SmallVector<Decl*, 4> TemplateParams; + SmallVector<Decl*, 4> TemplateParams; if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a }. @@ -159,7 +164,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, isSpecialization, LastParamListWasEmpty), ParsingTemplateParams, - DeclEnd, AS); + DeclEnd, AS, AccessAttrs); } /// \brief Parse a single declaration that declares a template, @@ -188,13 +193,15 @@ Parser::ParseSingleDeclarationAfterTemplate( const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, - AccessSpecifier AS) { + AccessSpecifier AS, + AttributeList *AccessAttrs) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && "Template information required"); if (Context == Declarator::MemberContext) { // We are parsing a member template. - ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams); + ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, + &DiagsFromTParams); return 0; } @@ -289,7 +296,7 @@ Parser::ParseSingleDeclarationAfterTemplate( /// /// \returns true if an error occurred, false otherwise. bool Parser::ParseTemplateParameters(unsigned Depth, - llvm::SmallVectorImpl<Decl*> &TemplateParams, + SmallVectorImpl<Decl*> &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { // Get the template parameter list. @@ -322,7 +329,7 @@ bool Parser::ParseTemplateParameters(unsigned Depth, /// template-parameter-list ',' template-parameter bool Parser::ParseTemplateParameterList(unsigned Depth, - llvm::SmallVectorImpl<Decl*> &TemplateParams) { + SmallVectorImpl<Decl*> &TemplateParams) { while (1) { if (Decl *TmpParam = ParseTemplateParameter(Depth, TemplateParams.size())) { @@ -468,8 +475,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { Ellipsis = true; EllipsisLoc = ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(EllipsisLoc, diag::ext_variadic_templates); + Diag(EllipsisLoc, + getLang().CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); } // Grab the template parameter name (if given) @@ -516,7 +525,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); - llvm::SmallVector<Decl*,8> TemplateParams; + SmallVector<Decl*,8> TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { ParseScope TemplateParmScope(this, Scope::TemplateParamScope); @@ -540,8 +549,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::ellipsis)) { EllipsisLoc = ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(EllipsisLoc, diag::ext_variadic_templates); + Diag(EllipsisLoc, + getLang().CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); } // Get the identifier, if given. @@ -558,7 +569,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { return 0; } - TemplateParamsTy *ParamList = + TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams.data(), @@ -1157,6 +1168,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { FD = cast<FunctionDecl>(LMT.D); // Reinject the template parameters. + SmallVector<ParseScope*, 4> TemplateParamScopeStack; DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); @@ -1164,17 +1176,31 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { } else { Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + // Get the list of DeclContext to reenter. + SmallVector<DeclContext*, 4> DeclContextToReenter; DeclContext *DD = FD->getLexicalParent(); while (DD && DD->isRecord()) { - if (ClassTemplatePartialSpecializationDecl* MD = - dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD)) - Actions.ActOnReenterTemplateScope(getCurScope(), MD); - else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD)) - Actions.ActOnReenterTemplateScope(getCurScope(), - MD->getDescribedClassTemplate()); - + DeclContextToReenter.push_back(DD); DD = DD->getLexicalParent(); } + + // Reenter template scopes from outmost to innermost. + SmallVector<DeclContext*, 4>::reverse_iterator II = + DeclContextToReenter.rbegin(); + for (; II != DeclContextToReenter.rend(); ++II) { + if (ClassTemplatePartialSpecializationDecl* MD = + dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { + TemplateParamScopeStack.push_back(new ParseScope(this, + Scope::TemplateParamScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), MD); + } else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { + TemplateParamScopeStack.push_back(new ParseScope(this, + Scope::TemplateParamScope, + MD->getDescribedClassTemplate() != 0 )); + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + } + } } assert(!LMT.Toks.empty() && "Empty body!"); @@ -1205,21 +1231,25 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LMT.D, FnScope); - return; - } - if (Tok.is(tok::colon)) { - ParseConstructorInitializer(LMT.D); + } else { + if (Tok.is(tok::colon)) + ParseConstructorInitializer(LMT.D); + else + Actions.ActOnDefaultCtorInitializers(LMT.D); - // Error recovery. - if (!Tok.is(tok::l_brace)) { + if (Tok.is(tok::l_brace)) { + ParseFunctionStatementBody(LMT.D, FnScope); + Actions.MarkAsLateParsedTemplate(FD, false); + } else Actions.ActOnFinishFunctionBody(LMT.D, 0); - return; - } - } else - Actions.ActOnDefaultCtorInitializers(LMT.D); + } - ParseFunctionStatementBody(LMT.D, FnScope); - Actions.MarkAsLateParsedTemplate(FD, false); + // Exit scopes. + FnScope.Exit(); + SmallVector<ParseScope*, 4>::reverse_iterator I = + TemplateParamScopeStack.rbegin(); + for (; I != TemplateParamScopeStack.rend(); ++I) + delete *I; DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D); if (grp) @@ -1229,15 +1259,10 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { /// \brief Lex a delayed template function for late parsing. void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { tok::TokenKind kind = Tok.getKind(); - // We may have a constructor initializer or function-try-block here. - if (kind == tok::colon || kind == tok::kw_try) - ConsumeAndStoreUntil(tok::l_brace, Toks); - else { - Toks.push_back(Tok); - ConsumeBrace(); + if (!ConsumeAndStoreFunctionPrologue(Toks)) { + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } - // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index 2ba0fc6..d53839f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -377,6 +377,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { /// /// [C++0x] attribute-specifier: /// '[' '[' attribute-list ']' ']' +/// alignment-specifier /// /// [C++0x] attribute-list: /// attribute[opt] @@ -409,6 +410,9 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { /// any token but '(', ')', '[', ']', '{', or '}' bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, tok::TokenKind *After) { + if (Tok.is(tok::kw_alignas)) + return true; + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) return false; @@ -552,7 +556,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___fastcall) || - Tok.is(tok::kw___thiscall)) + Tok.is(tok::kw___thiscall) || + Tok.is(tok::kw___unaligned)) return TPResult::True(); // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous()) @@ -605,8 +610,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { // Obviously starts an expression. case tok::numeric_constant: case tok::char_constant: + case tok::wide_char_constant: + case tok::utf16_char_constant: + case tok::utf32_char_constant: case tok::string_literal: case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: case tok::l_square: case tok::l_paren: case tok::amp: @@ -674,6 +685,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_const: case tok::kw_double: case tok::kw_enum: + case tok::kw_half: case tok::kw_float: case tok::kw_int: case tok::kw_long: @@ -705,8 +717,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___unaligned: case tok::kw___vector: case tok::kw___pixel: + case tok::kw__Atomic: return TPResult::False(); default: @@ -863,6 +877,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_virtual: case tok::kw_explicit: + // Modules + case tok::kw___module_private__: + // type-specifier: // simple-type-specifier // class-specifier @@ -896,7 +913,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: + case tok::kw___ptr32: case tok::kw___forceinline: + case tok::kw___unaligned: return TPResult::True(); // Borland @@ -976,6 +995,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: @@ -1016,6 +1036,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___underlying_type: return TPResult::True(); + // C1x _Atomic + case tok::kw__Atomic: + return TPResult::True(); + default: return TPResult::False(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 5c50290..c909643 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -72,7 +72,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions) /// If a crash happens while the parser is active, print out a line indicating /// what the current token is. -void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const { +void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { const Token &Tok = P.getCurToken(); if (Tok.is(tok::eof)) { OS << "<eof> parser at end of file\n"; @@ -122,34 +122,6 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, << FixItHint::CreateInsertion(EndLoc, ")"); } -/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), -/// this helper function matches and consumes the specified RHS token if -/// present. If not present, it emits a corresponding diagnostic indicating -/// that the parser failed to match the RHS of the token at LHSLoc. -SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, - SourceLocation LHSLoc) { - - if (Tok.is(RHSTok)) - return ConsumeAnyToken(); - - SourceLocation R = Tok.getLocation(); - const char *LHSName = "unknown"; - diag::kind DID = diag::err_parse_error; - switch (RHSTok) { - default: break; - case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; - case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; - case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; - case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; - case tok::greatergreatergreater: - LHSName = "<<<"; DID = diag::err_expected_ggg; break; - } - Diag(Tok, DID); - Diag(LHSLoc, diag::note_matching) << LHSName; - SkipUntil(RHSTok); - return R; -} - static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { switch (ExpectedTok) { case tok::semi: return Tok.is(tok::colon); // : for ; @@ -298,6 +270,9 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, case tok::string_literal: case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: ConsumeStringToken(); break; @@ -440,6 +415,7 @@ void Parser::Initialize() { ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); } + Ident_instancetype = 0; Ident_final = 0; Ident_override = 0; @@ -550,7 +526,12 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS) { DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); ParenBraceBracketBalancer BalancerRAIIObj(*this); - + + if (PP.isCodeCompletionReached()) { + cutOffParsing(); + return DeclGroupPtrTy(); + } + Decl *SingleDecl = 0; switch (Tok.getKind()) { case tok::semi: @@ -590,10 +571,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, break; } case tok::at: - // @ is not a legal token unless objc is enabled, no need to check for ObjC. - /// FIXME: ParseObjCAtDirectives should return a DeclGroup for things like - /// @class foo, bar; - SingleDecl = ParseObjCAtDirectives(); + return ParseObjCAtDirectives(); break; case tok::minus: case tok::plus: @@ -608,8 +586,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Actions.CodeCompleteOrdinaryName(getCurScope(), ObjCImpDecl? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); - ConsumeCodeCompletionToken(); - return ParseExternalDeclaration(attrs); + cutOffParsing(); + return DeclGroupPtrTy(); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -676,6 +654,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParseMicrosoftIfExistsExternalDeclaration(); return DeclGroupPtrTy(); + case tok::kw___import_module__: + return ParseModuleImport(); + default: dont_know: // We can't tell whether this is a function-definition or declaration yet. @@ -808,6 +789,11 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, AccessSpecifier AS) { ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); + // Must temporarily exit the objective-c container scope for + // parsing c constructs and re-enter objc container scope + // afterwards. + ObjCDeclContextSwitch ObjCDC(*this); + return ParseDeclarationOrFunctionDefinition(DS, AS); } @@ -877,9 +863,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); + D.setFunctionDefinition(true); Decl *DP = Actions.HandleDeclarator(ParentScope, D, - move(TemplateParameterLists), - /*IsFunctionDefinition=*/true); + move(TemplateParameterLists)); D.complete(DP); D.getMutableDeclSpec().abort(); @@ -1133,13 +1119,12 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { ConsumeToken(); } - if (Tok.isNot(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; return ExprError(); } - Loc = ConsumeParen(); - ExprResult Result(ParseAsmStringLiteral()); if (Result.isInvalid()) { @@ -1148,9 +1133,10 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { *EndLoc = Tok.getLocation(); ConsumeAnyToken(); } else { - Loc = MatchRHSPunctuation(tok::r_paren, Loc); + // Close the paren and get the location of the end bracket + T.consumeClose(); if (EndLoc) - *EndLoc = Loc; + *EndLoc = T.getCloseLocation(); } return move(Result); @@ -1190,7 +1176,7 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. -bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { +bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) && "Cannot be a type or scope token!"); @@ -1208,7 +1194,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - if (getLang().Microsoft) + if (getLang().MicrosoftExt) Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); else Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); @@ -1264,13 +1250,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { return true; if (Tok.is(tok::identifier)) { + IdentifierInfo *CorrectedII = 0; // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), ParsedType(), - /*NonTrivialTypeSourceInfo*/true)) { + /*NonTrivialTypeSourceInfo*/true, + NeedType ? &CorrectedII : NULL)) { + // A FixIt was applied as a result of typo correction + if (CorrectedII) + Tok.setIdentifierInfo(CorrectedII); // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); @@ -1405,20 +1396,27 @@ bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) { return Tok.is(tok::equal); } -void Parser::CodeCompletionRecovery() { +SourceLocation Parser::handleUnexpectedCodeCompletionToken() { + assert(Tok.is(tok::code_completion)); + PrevTokLocation = Tok.getLocation(); + for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->getFlags() & Scope::FnScope) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction); - return; + cutOffParsing(); + return PrevTokLocation; } if (S->getFlags() & Scope::ClassScope) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); - return; + cutOffParsing(); + return PrevTokLocation; } } Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); + cutOffParsing(); + return PrevTokLocation; } // Anchor the Parser::FieldCallback vtable to this translation unit. @@ -1463,13 +1461,12 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { Token Condition = Tok; SourceLocation IfExistsLoc = ConsumeToken(); - SourceLocation LParenLoc = Tok.getLocation(); - if (Tok.isNot(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; SkipUntil(tok::semi); return true; } - ConsumeParen(); // eat the '('. // Parse nested-name-specifier. CXXScopeSpec SS; @@ -1488,7 +1485,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { return true; } - if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) return true; // Check if the symbol exists. @@ -1533,3 +1531,86 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { } ConsumeBrace(); } + +Parser::DeclGroupPtrTy Parser::ParseModuleImport() { + assert(Tok.is(tok::kw___import_module__) && + "Improper start to module import"); + SourceLocation ImportLoc = ConsumeToken(); + + // Parse the module name. + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_module_expected_ident); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + + IdentifierInfo &ModuleName = *Tok.getIdentifierInfo(); + SourceLocation ModuleNameLoc = ConsumeToken(); + DeclResult Import = Actions.ActOnModuleImport(ImportLoc, ModuleName, ModuleNameLoc); + ExpectAndConsumeSemi(diag::err_module_expected_semi); + if (Import.isInvalid()) + return DeclGroupPtrTy(); + + return Actions.ConvertDeclToDeclGroup(Import.get()); +} + +bool Parser::BalancedDelimiterTracker::consumeOpen() { + // Try to consume the token we are holding + if (P.Tok.is(Kind)) { + P.QuantityTracker.push(Kind); + Cleanup = true; + if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { + LOpen = P.ConsumeAnyToken(); + return false; + } else { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + } + } + return true; +} + +bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, + const char *Msg, + tok::TokenKind SkipToToc ) { + LOpen = P.Tok.getLocation(); + if (!P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) { + P.QuantityTracker.push(Kind); + Cleanup = true; + if (P.QuantityTracker.getDepth(Kind) < MaxDepth) { + return false; + } else { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + } + } + return true; +} + +bool Parser::BalancedDelimiterTracker::consumeClose() { + if (P.Tok.is(Close)) { + LClose = P.ConsumeAnyToken(); + if (Cleanup) + P.QuantityTracker.pop(Kind); + + Cleanup = false; + return false; + } else { + const char *LHSName = "unknown"; + diag::kind DID = diag::err_parse_error; + switch (Close) { + default: break; + case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; + case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; + case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; + case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; + case tok::greatergreatergreater: + LHSName = "<<<"; DID = diag::err_expected_ggg; break; + } + P.Diag(P.Tok, DID); + P.Diag(LOpen, diag::note_matching) << LHSName; + if (P.SkipUntil(Close)) + LClose = P.Tok.getLocation(); + } + return true; +} diff --git a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h index 3765f92..ef17aee 100644 --- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h +++ b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h @@ -30,9 +30,9 @@ namespace clang { class ExtensionRAIIObject { void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT - Diagnostic &Diags; + DiagnosticsEngine &Diags; public: - ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { + ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { Diags.IncrementAllExtensionsSilenced(); } diff --git a/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp b/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp index 085dfd8..4297dc8 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp @@ -12,12 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/Rewrite/DeltaTree.h" -#include "llvm/Support/Casting.h" +#include "clang/Basic/LLVM.h" #include <cstring> #include <cstdio> using namespace clang; -using llvm::cast; -using llvm::dyn_cast; /// The DeltaTree class is a multiway search tree (BTree) structure with some /// fancy features. B-Trees are generally more memory and cache efficient diff --git a/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp index e50793e..632c0de 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp @@ -25,7 +25,7 @@ using namespace clang; -FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, +FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const LangOptions &LangOpts, FixItOptions *FixItOpts) : Diags(Diags), @@ -41,7 +41,7 @@ FixItRewriter::~FixItRewriter() { Diags.setClient(Client); } -bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) { +bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); if (!RewriteBuf) return true; RewriteBuf->write(OS); @@ -78,15 +78,15 @@ bool FixItRewriter::IncludeInDiagnosticCounts() const { return Client ? Client->IncludeInDiagnosticCounts() : true; } -void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { +void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(DiagLevel, Info); + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); Client->HandleDiagnostic(DiagLevel, Info); // Skip over any diagnostics that are ignored or notes. - if (DiagLevel <= Diagnostic::Note) + if (DiagLevel <= DiagnosticsEngine::Note) return; // Make sure that we can perform all of the modifications we @@ -107,7 +107,8 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, Diag(Info.getLocation(), diag::note_fixit_in_macro); // If this was an error, refuse to perform any rewriting. - if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) { + if (DiagLevel == DiagnosticsEngine::Error || + DiagLevel == DiagnosticsEngine::Fatal) { if (++NumFailures == 1) Diag(Info.getLocation(), diag::note_fixit_unfixed_error); } @@ -155,4 +156,9 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { Diags.setClient(this); } +DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { + return new FixItRewriter(Diags, Diags.getSourceManager(), + Rewrite.getLangOpts(), FixItOpts); +} + FixItOptions::~FixItOptions() {} diff --git a/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp index 33e79ed..f00e7fd 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp @@ -28,8 +28,8 @@ using namespace clang; //===----------------------------------------------------------------------===// ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) return CreateHTMLPrinter(OS, CI.getPreprocessor()); return 0; } @@ -38,7 +38,7 @@ FixItAction::FixItAction() {} FixItAction::~FixItAction() {} ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return new ASTConsumer(); } @@ -67,7 +67,7 @@ public: } // end anonymous namespace bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, - llvm::StringRef Filename) { + StringRef Filename) { const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); if (!FEOpts.FixItSuffix.empty()) { FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, @@ -91,8 +91,8 @@ void FixItAction::EndSourceFileAction() { //===----------------------------------------------------------------------===// ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) return CreateObjCRewriter(InFile, OS, CI.getDiagnostics(), CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros); @@ -101,7 +101,7 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, void RewriteMacrosAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); if (!OS) return; RewriteMacrosInInput(CI.getPreprocessor(), OS); @@ -109,7 +109,7 @@ void RewriteMacrosAction::ExecuteAction() { void RewriteTestAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); if (!OS) return; DoRewriteTest(CI.getPreprocessor(), OS); diff --git a/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp index f66bfcb..6a89265 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp @@ -32,12 +32,12 @@ using namespace clang; namespace { class HTMLPrinter : public ASTConsumer { Rewriter R; - llvm::raw_ostream *Out; + raw_ostream *Out; Preprocessor &PP; bool SyntaxHighlight, HighlightMacros; public: - HTMLPrinter(llvm::raw_ostream *OS, Preprocessor &pp, + HTMLPrinter(raw_ostream *OS, Preprocessor &pp, bool _SyntaxHighlight, bool _HighlightMacros) : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), HighlightMacros(_HighlightMacros) {} @@ -47,7 +47,7 @@ namespace { }; } -ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS, +ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS, Preprocessor &PP, bool SyntaxHighlight, bool HighlightMacros) { diff --git a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp index 0b54755..ba39602 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp @@ -33,8 +33,8 @@ using namespace clang; void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, const char *StartTag, const char *EndTag) { SourceManager &SM = R.getSourceMgr(); - B = SM.getInstantiationLoc(B); - E = SM.getInstantiationLoc(E); + B = SM.getExpansionLoc(B); + E = SM.getExpansionLoc(E); FileID FID = SM.getFileID(B); assert(SM.getFileID(E) == FID && "B/E not in the same file!"); @@ -140,10 +140,10 @@ void html::EscapeText(Rewriter &R, FileID FID, unsigned NumSpaces = 8-(ColNo&7); if (EscapeSpaces) RB.ReplaceText(FilePos, 1, - llvm::StringRef(" " + StringRef(" " " ", 6*NumSpaces)); else - RB.ReplaceText(FilePos, 1, llvm::StringRef(" ", NumSpaces)); + RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces)); ColNo += NumSpaces; break; } @@ -277,7 +277,7 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, const char* FileEnd = Buf->getBufferEnd(); SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); - SourceLocation EndLoc = StartLoc.getFileLocWithOffset(FileEnd-FileStart); + SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart); std::string s; llvm::raw_string_ostream os(s); @@ -397,8 +397,15 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, "<span class='comment'>", "</span>"); break; + case tok::utf8_string_literal: + // Chop off the u part of u8 prefix + ++TokOffs; + --TokLen; + // FALL THROUGH to chop the 8 case tok::wide_string_literal: - // Chop off the L prefix + case tok::utf16_string_literal: + case tok::utf32_string_literal: + // Chop off the L, u, U or 8 prefix ++TokOffs; --TokLen; // FALL THROUGH. @@ -433,17 +440,6 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { } } -namespace { -/// IgnoringDiagClient - This is a diagnostic client that just ignores all -/// diags. -class IgnoringDiagClient : public DiagnosticClient { - void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { - // Just ignore it. - } -}; -} - /// HighlightMacros - This uses the macro table state from the end of the /// file, to re-expand macros and insert (into the HTML) information about the /// macro expansions. This won't be perfectly perfect, but it will be @@ -486,14 +482,14 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Temporarily change the diagnostics object so that we ignore any generated // diagnostics from this pass. - Diagnostic TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), - new IgnoringDiagClient); + DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), + new IgnoringDiagConsumer); // FIXME: This is a huge hack; we reuse the input preprocessor because we want // its state, but we aren't actually changing it (we hope). This should really // construct a copy of the preprocessor. Preprocessor &TmpPP = const_cast<Preprocessor&>(PP); - Diagnostic *OldDiags = &TmpPP.getDiagnostics(); + DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics(); TmpPP.setDiagnostics(TmpDiags); // Inform the preprocessor that we don't want comments. @@ -519,7 +515,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // expansion by inserting a start tag before the macro expansion and // end tag after it. std::pair<SourceLocation, SourceLocation> LLoc = - SM.getInstantiationRange(Tok.getLocation()); + SM.getExpansionRange(Tok.getLocation()); // Ignore tokens whose instantiation location was not the main file. if (SM.getFileID(LLoc.first) != FID) { @@ -542,7 +538,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // instantiation. It would be really nice to pop up a window with all the // spelling of the tokens or something. while (!Tok.is(tok::eof) && - SM.getInstantiationLoc(Tok.getLocation()) == LLoc.first) { + SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) { // Insert a newline if the macro expansion is getting large. if (LineLen > 60) { Expansion += "<br>"; diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp index 0453098..d569100 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp @@ -87,7 +87,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP, /// RewriteMacrosInInput - Implement -rewrite-macros mode. -void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { +void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) { SourceManager &SM = PP.getSourceManager(); Rewriter Rewrite; @@ -112,7 +112,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { // that aren't in the preprocessed view, we have macros that expand to no // tokens, or macro arguments etc. while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { - SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation()); + SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation()); // If PPTok is from a different source file, ignore it. if (!SM.isFromMainFile(PPLoc)) { @@ -197,7 +197,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { while (PPOffs < RawOffs) { Expansion += ' ' + PP.getSpelling(PPTok); PP.Lex(PPTok); - PPLoc = SM.getInstantiationLoc(PPTok.getLocation()); + PPLoc = SM.getExpansionLoc(PPTok.getLocation()); PPOffs = SM.getFileOffset(PPLoc); } Expansion += ' '; diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp index 8202164..6a392ea 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp @@ -55,7 +55,7 @@ namespace { }; Rewriter Rewrite; - Diagnostic &Diags; + DiagnosticsEngine &Diags; const LangOptions &LangOpts; unsigned RewriteFailedDiag; unsigned TryFinallyContainsReturnDiag; @@ -67,14 +67,14 @@ namespace { const char *MainFileStart, *MainFileEnd; SourceLocation LastIncLoc; - llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; - llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; + SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; + SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs; llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols; llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls; llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames; - llvm::SmallVector<Stmt *, 32> Stmts; - llvm::SmallVector<int, 8> ObjCBcLabelNo; + SmallVector<Stmt *, 32> Stmts; + SmallVector<int, 8> ObjCBcLabelNo; // Remember all the @protocol(<expr>) expressions. llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls; @@ -113,7 +113,7 @@ namespace { bool IsHeader; std::string InFileName; - llvm::raw_ostream* OutFile; + raw_ostream* OutFile; bool SilenceRewriteMacroWarning; bool objc_impl_method; @@ -121,16 +121,16 @@ namespace { std::string Preamble; // Block expressions. - llvm::SmallVector<BlockExpr *, 32> Blocks; - llvm::SmallVector<int, 32> InnerDeclRefsCount; - llvm::SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs; + SmallVector<BlockExpr *, 32> Blocks; + SmallVector<int, 32> InnerDeclRefsCount; + SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs; - llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs; + SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs; // Block related declarations. - llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls; + SmallVector<ValueDecl *, 8> BlockByCopyDecls; llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet; - llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls; + SmallVector<ValueDecl *, 8> BlockByRefDecls; llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; @@ -161,13 +161,18 @@ namespace { // Top Level Driver code. virtual void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + if (isa<ObjCClassDecl>((*I))) { + RewriteForwardClassDecl(D); + break; + } HandleTopLevelSingleDecl(*I); + } } void HandleTopLevelSingleDecl(Decl *D); void HandleDeclInMainFile(Decl *D); - RewriteObjC(std::string inFile, llvm::raw_ostream *OS, - Diagnostic &D, const LangOptions &LOpts, + RewriteObjC(std::string inFile, raw_ostream *OS, + DiagnosticsEngine &D, const LangOptions &LOpts, bool silenceMacroWarn); ~RewriteObjC() {} @@ -219,7 +224,7 @@ namespace { << Old->getSourceRange(); } - void InsertText(SourceLocation Loc, llvm::StringRef Str, + void InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter = true) { // If insertion succeeded or warning disabled return with no warning. if (!Rewrite.InsertText(Loc, Str, InsertAfter) || @@ -230,7 +235,7 @@ namespace { } void ReplaceText(SourceLocation Start, unsigned OrigLength, - llvm::StringRef Str) { + StringRef Str) { // If removal succeeded or warning disabled return with no warning. if (!Rewrite.ReplaceText(Start, OrigLength, Str) || SilenceRewriteMacroWarning) @@ -241,7 +246,11 @@ namespace { // Syntactic Rewriting. void RewriteInclude(); - void RewriteForwardClassDecl(ObjCClassDecl *Dcl); + void RewriteForwardClassDecl(DeclGroupRef D); + void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG); + void RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl, + const std::string &typedefString); + void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, ObjCImplementationDecl *IMD, ObjCCategoryImplDecl *CID); @@ -332,17 +341,17 @@ namespace { void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, MethodIterator MethodEnd, bool IsInstanceMethod, - llvm::StringRef prefix, - llvm::StringRef ClassName, + StringRef prefix, + StringRef ClassName, std::string &Result); void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - llvm::StringRef prefix, - llvm::StringRef ClassName, + StringRef prefix, + StringRef ClassName, std::string &Result); void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots, - llvm::StringRef prefix, - llvm::StringRef ClassName, + StringRef prefix, + StringRef ClassName, std::string &Result); void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, std::string &Result); @@ -367,24 +376,24 @@ namespace { void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - llvm::StringRef funcName, std::string Tag); + StringRef funcName, std::string Tag); std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - llvm::StringRef funcName, std::string Tag); + StringRef funcName, std::string Tag); std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, std::string Desc); std::string SynthesizeBlockDescriptor(std::string DescTag, std::string ImplTag, - int i, llvm::StringRef funcName, + int i, StringRef funcName, unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, - llvm::StringRef FunName); + StringRef FunName); void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockDeclRefExprs(Stmt *S); void GetInnerBlockDeclRefExprs(Stmt *S, - llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, + SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts); // We avoid calling Type::isBlockPointerType(), since it operates on the @@ -411,8 +420,14 @@ namespace { else if (T->isObjCQualifiedClassType()) T = Context->getObjCClassType(); else if (T->isObjCObjectPointerType() && - T->getPointeeType()->isObjCQualifiedInterfaceType()) - T = Context->getObjCIdType(); + T->getPointeeType()->isObjCQualifiedInterfaceType()) { + if (const ObjCObjectPointerType * OBJPT = + T->getAsObjCInterfacePointerType()) { + const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); + T = QualType(IFaceT, 0); + T = Context->getPointerType(T); + } + } } // FIXME: This predicate seems like it would be useful to add to ASTContext. @@ -439,9 +454,9 @@ namespace { const char *&RParen); void RewriteCastExpr(CStyleCastExpr *CE); - FunctionDecl *SynthBlockInitFunctionDecl(llvm::StringRef name); + FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); Stmt *SynthBlockInitExpr(BlockExpr *Exp, - const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs); + const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs); void QuoteDoublequotes(std::string &From, std::string &To) { for (unsigned i = 0; i < From.length(); i++) { @@ -456,6 +471,8 @@ namespace { const QualType *args, unsigned numArgs, bool variadic = false) { + if (result == Context->getObjCInstanceType()) + result = Context->getObjCIdType(); FunctionProtoType::ExtProtoInfo fpi; fpi.Variadic = variadic; return Context->getFunctionType(result, args, numArgs, fpi); @@ -505,22 +522,23 @@ static bool IsHeaderFile(const std::string &Filename) { return Ext == "h" || Ext == "hh" || Ext == "H"; } -RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS, - Diagnostic &D, const LangOptions &LOpts, +RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS, + DiagnosticsEngine &D, const LangOptions &LOpts, bool silenceMacroWarn) : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), SilenceRewriteMacroWarning(silenceMacroWarn) { IsHeader = IsHeaderFile(inFile); - RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, + RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, "rewriting sub-expression within a macro (may not be correct)"); - TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning, + TryFinallyContainsReturnDiag = Diags.getCustomDiagID( + DiagnosticsEngine::Warning, "rewriter doesn't support user-specified control flow semantics " "for @try/@finally (code may not execute properly)"); } ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, - llvm::raw_ostream* OS, - Diagnostic &Diags, + raw_ostream* OS, + DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning) { return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); @@ -572,7 +590,7 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "struct objc_selector; struct objc_class;\n"; Preamble += "struct __rw_objc_super { struct objc_object *object; "; Preamble += "struct objc_object *superClass; "; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { // Add a constructor for creating temporary objects. Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) " ": "; @@ -583,7 +601,7 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "typedef struct objc_object Protocol;\n"; Preamble += "#define _REWRITER_typedef_Protocol\n"; Preamble += "#endif\n"; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; } else @@ -592,9 +610,9 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret"; Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret"; Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret"; Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; @@ -660,7 +678,7 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; Preamble += "#endif\n"; Preamble += "#endif\n"; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. @@ -690,7 +708,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { // #included file. If the former, rewrite it now. If the later, check to see // if we rewrote the #include/#import. SourceLocation Loc = D->getLocation(); - Loc = SM->getInstantiationLoc(Loc); + Loc = SM->getExpansionLoc(Loc); // If this is for a builtin, ignore it. if (Loc.isInvalid()) return; @@ -717,8 +735,23 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { // Recurse into linkage specifications for (DeclContext::decl_iterator DI = LSD->decls_begin(), DIEnd = LSD->decls_end(); - DI != DIEnd; ++DI) + DI != DIEnd; ) { + if (isa<ObjCClassDecl>((*DI))) { + SmallVector<Decl *, 8> DG; + Decl *D = (*DI); + SourceLocation Loc = D->getLocation(); + while (DI != DIEnd && + isa<ObjCClassDecl>(D) && D->getLocation() == Loc) { + DG.push_back(D); + ++DI; + D = (*DI); + } + RewriteForwardClassDecl(DG); + continue; + } HandleTopLevelSingleDecl(*DI); + ++DI; + } } // If we have a decl in the main file, see if we should rewrite it. if (SM->isFromMainFile(Loc)) @@ -731,7 +764,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { void RewriteObjC::RewriteInclude() { SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - llvm::StringRef MainBuf = SM->getBufferData(MainFileID); + StringRef MainBuf = SM->getBufferData(MainFileID); const char *MainBufStart = MainBuf.begin(); const char *MainBufEnd = MainBuf.end(); size_t ImportLen = strlen("import"); @@ -747,7 +780,7 @@ void RewriteObjC::RewriteInclude() { if (!strncmp(BufPtr, "import", ImportLen)) { // replace import with include SourceLocation ImportLoc = - LocStart.getFileLocWithOffset(BufPtr-MainBufStart); + LocStart.getLocWithOffset(BufPtr-MainBufStart); ReplaceText(ImportLoc, ImportLen, "include"); BufPtr += ImportLen; } @@ -777,7 +810,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, const char *semiBuf = strchr(startBuf, ';'); assert((*semiBuf == ';') && "@synthesize: can't find ';'"); SourceLocation onePastSemiLoc = - startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + startLoc.getLocWithOffset(semiBuf-startBuf+1); if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) return; // FIXME: is this correct? @@ -821,7 +854,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { if (i) Getr += ", "; std::string ParamStr = FT->getArgType(i).getAsString( - Context->PrintingPolicy); + Context->getPrintingPolicy()); Getr += ParamStr; } if (FT->isVariadic()) { @@ -886,55 +919,73 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, InsertText(onePastSemiLoc, Setr); } -void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { - // Get the start location and compute the semi location. - SourceLocation startLoc = ClassDecl->getLocation(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); +static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, + std::string &typedefString) { + typedefString += "#ifndef _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "#define _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "typedef struct objc_object "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n#endif\n"; +} + +void RewriteObjC::RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl, + const std::string &typedefString) { + SourceLocation startLoc = ClassDecl->getLocation(); + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiPtr = strchr(startBuf, ';'); + // Replace the @class with typedefs corresponding to the classes. + ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); +} - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. +void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) { std::string typedefString; - typedefString += "// @class "; - for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); - I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = I->getInterface(); - typedefString += ForwardDecl->getNameAsString(); - if (I+1 != E) - typedefString += ", "; - else + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { + ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(*I); + ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl(); + if (I == D.begin()) { + // Translate to typedef's that forward reference structs with the same name + // as the class. As a convenience, we include the original declaration + // as a comment. + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); } - - for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); - I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = I->getInterface(); - typedefString += "#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n#endif\n"; - } - - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); + DeclGroupRef::iterator I = D.begin(); + RewriteForwardClassEpilogue(cast<ObjCClassDecl>(*I), typedefString); +} + +void RewriteObjC::RewriteForwardClassDecl( + const llvm::SmallVector<Decl*, 8> &D) { + std::string typedefString; + for (unsigned i = 0; i < D.size(); i++) { + ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(D[i]); + ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl(); + if (i == 0) { + typedefString += "// @class "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n"; + } + RewriteOneForwardClassDecl(ForwardDecl, typedefString); + } + RewriteForwardClassEpilogue(cast<ObjCClassDecl>(D[0]), typedefString); } void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { // When method is a synthesized one, such as a getter/setter there is // nothing to rewrite. - if (Method->isSynthesized()) + if (Method->isImplicit()) return; SourceLocation LocStart = Method->getLocStart(); SourceLocation LocEnd = Method->getLocEnd(); - if (SM->getInstantiationLineNumber(LocEnd) > - SM->getInstantiationLineNumber(LocStart)) { + if (SM->getExpansionLineNumber(LocEnd) > + SM->getExpansionLineNumber(LocStart)) { InsertText(LocStart, "#if 0\n"); ReplaceText(LocEnd, 1, ";\n#endif\n"); } else { @@ -1001,12 +1052,12 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { const char *endBuf = SM->getCharacterData(LocEnd); for (const char *p = startBuf; p < endBuf; p++) { if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); } else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); + SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); } @@ -1016,7 +1067,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) { SourceLocation LocStart = PDecl->getLocation(); if (LocStart.isInvalid()) - assert(false && "Invalid SourceLocation"); + llvm_unreachable("Invalid SourceLocation"); // FIXME: handle forward protocol that are declared across multiple lines. ReplaceText(LocStart, 0, "// "); } @@ -1037,11 +1088,11 @@ void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, PointeeTy = BPT->getPointeeType(); if ((FPRetType = PointeeTy->getAs<FunctionType>())) { ResultStr += FPRetType->getResultType().getAsString( - Context->PrintingPolicy); + Context->getPrintingPolicy()); ResultStr += "(*"; } } else - ResultStr += T.getAsString(Context->PrintingPolicy); + ResultStr += T.getAsString(Context->getPrintingPolicy()); } void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, @@ -1089,7 +1140,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, if (OMD->isInstanceMethod()) { QualType selfTy = Context->getObjCInterfaceType(IDecl); selfTy = Context->getPointerType(selfTy); - if (!LangOpts.Microsoft) { + if (!LangOpts.MicrosoftExt) { if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl))) ResultStr += "struct "; } @@ -1099,10 +1150,10 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, } else ResultStr += Context->getObjCClassType().getAsString( - Context->PrintingPolicy); + Context->getPrintingPolicy()); ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(Context->PrintingPolicy); + ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); ResultStr += " _cmd"; // Method arguments. @@ -1118,9 +1169,9 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, QualType QT = PDecl->getType(); // Make sure we convert "t (^)(...)" to "t (*)(...)". if (convertBlockPointerToFunctionPointer(QT)) - QT.getAsStringInternal(Name, Context->PrintingPolicy); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); else - PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy); + PDecl->getType().getAsStringInternal(Name, Context->getPrintingPolicy()); ResultStr += Name; } } @@ -1137,7 +1188,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { if (i) ResultStr += ", "; std::string ParamStr = FT->getArgType(i).getAsString( - Context->PrintingPolicy); + Context->getPrintingPolicy()); ResultStr += ParamStr; } if (FT->isVariadic()) { @@ -1265,8 +1316,6 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr * } assert(OMD && "RewritePropertyOrImplicitSetter - null OMD"); - llvm::SmallVector<Expr *, 1> ExprVec; - ExprVec.push_back(newStmt); ObjCMessageExpr *MsgExpr; if (Super) @@ -1278,7 +1327,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr * /*IsInstanceSuper=*/true, SuperTy, Sel, SelectorLoc, OMD, - &ExprVec[0], 1, + newStmt, /*FIXME:*/SourceLocation()); else { // FIXME. Refactor this into common code with that in @@ -1295,7 +1344,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr * /*FIXME: */SourceLocation(), cast<Expr>(Receiver), Sel, SelectorLoc, OMD, - &ExprVec[0], 1, + newStmt, /*FIXME:*/SourceLocation()); } Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); @@ -1354,7 +1403,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) { /*IsInstanceSuper=*/true, SuperTy, Sel, SelectorLoc, OMD, - 0, 0, + ArrayRef<Expr*>(), PropOrGetterRefExpr->getLocEnd()); else { assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null"); @@ -1368,7 +1417,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) { PropOrGetterRefExpr->getLocStart(), cast<Expr>(Receiver), Sel, SelectorLoc, OMD, - 0, 0, + ArrayRef<Expr*>(), PropOrGetterRefExpr->getLocEnd()); } @@ -1611,7 +1660,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, SourceLocation startLoc = S->getLocStart(); const char *startBuf = SM->getCharacterData(startLoc); - llvm::StringRef elementName; + StringRef elementName; std::string elementTypeAsString; std::string buf; buf = "\n{\n\t"; @@ -1624,7 +1673,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // Simply use 'id' for all qualified types. elementTypeAsString = "id"; else - elementTypeAsString = ElementType.getAsString(Context->PrintingPolicy); + elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); buf += elementTypeAsString; buf += " "; elementName = D->getName(); @@ -1640,7 +1689,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // Simply use 'id' for all qualified types. elementTypeAsString = "id"; else - elementTypeAsString = VD->getType().getAsString(Context->PrintingPolicy); + elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); } // struct __objcFastEnumerationState enumState = { 0 }; @@ -1667,7 +1716,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // Replace ')' in for '(' type elem in collection ')' with ';' SourceLocation rightParenLoc = S->getRParenLoc(); const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf); + SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); buf = ";\n\t"; // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState @@ -1744,7 +1793,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // Insert all these *after* the statement body. // FIXME: If this should support Obj-C++, support CXXTryStmt if (isa<CompoundStmt>(S->getBody())) { - SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1); + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); InsertText(endBodyLoc, buf); } else { /* Need to treat single statements specially. For example: @@ -1757,7 +1806,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, const char *stmtBuf = SM->getCharacterData(OrigEnd); const char *semiBuf = strchr(stmtBuf, ';'); assert(semiBuf && "Can't find ';'"); - SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1); + SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); InsertText(endBodyLoc, buf); } Stmts.pop_back(); @@ -1789,7 +1838,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { SourceLocation endLoc = S->getSynchBody()->getLocStart(); const char *endBuf = SM->getCharacterData(endLoc); while (*endBuf != ')') endBuf--; - SourceLocation rparenLoc = startLoc.getFileLocWithOffset(endBuf-startBuf); + SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf); buf = ");\n"; // declare a new scope with two variables, _stack and _rethrow. buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; @@ -1812,9 +1861,15 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { std::string syncBuf; syncBuf += " objc_sync_exit("; - Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - S->getSynchExpr()); + + Expr *syncExpr = S->getSynchExpr(); + CastKind CK = syncExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : + syncExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, syncExpr); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, @@ -1875,7 +1930,7 @@ void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { const char *semiBuf = strchr(startBuf, ';'); assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); std::string buf; buf = "{ objc_exception_try_exit(&_stack); return"; @@ -1898,7 +1953,7 @@ void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { const char *semiBuf = strchr(startBuf, ';'); assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); std::string buf; buf = "{ objc_exception_try_exit(&_stack);"; @@ -1936,7 +1991,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { SourceLocation lastCurlyLoc = startLoc; if (S->getNumCatchStmts()) { - startLoc = startLoc.getFileLocWithOffset(1); + startLoc = startLoc.getLocWithOffset(1); buf = " /* @catch begin */ else {\n"; buf += " id _caught = objc_exception_extract(&_stack);\n"; buf += " objc_exception_try_enter (&_stack);\n"; @@ -2007,7 +2062,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // declares the @catch parameter). ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); } else { - assert(false && "@catch rewrite bug"); + llvm_unreachable("@catch rewrite bug"); } } // Complete the catch list... @@ -2017,7 +2072,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { "bogus @catch body location"); // Insert the last (implicit) else clause *before* the right curly brace. - bodyLoc = bodyLoc.getFileLocWithOffset(-1); + bodyLoc = bodyLoc.getLocWithOffset(-1); buf = "} /* last catch end */\n"; buf += "else {\n"; buf += " _rethrow = _caught;\n"; @@ -2045,9 +2100,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { assert(*SM->getCharacterData(endLoc) == '}' && "bogus @finally body location"); - startLoc = startLoc.getFileLocWithOffset(1); + startLoc = startLoc.getLocWithOffset(1); InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); - endLoc = endLoc.getFileLocWithOffset(-1); + endLoc = endLoc.getLocWithOffset(-1); InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); // Set lastCurlyLoc @@ -2071,7 +2126,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { RewriteTryReturnStmts(S->getTryBody()); } // Now emit the final closing curly brace... - lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); + lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1); InsertText(lastCurlyLoc, " } /* @try scope end */\n"); return 0; } @@ -2100,7 +2155,7 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { const char *semiBuf = strchr(startBuf, ';'); assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf); + SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); ReplaceText(semiLoc, 1, ");"); return 0; } @@ -2111,8 +2166,8 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { std::string StrEncoding; Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, - false, false, StrType, - SourceLocation()); + StringLiteral::Ascii, false, + StrType, SourceLocation()); ReplaceStmt(Exp, Replacement); // Replace this subexpr in the parent. @@ -2125,12 +2180,12 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { SynthSelGetUidFunctionDecl(); assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); // Create a call to sel_registerName("selName"). - llvm::SmallVector<Expr*, 8> SelExprs; + SmallVector<Expr*, 8> SelExprs; QualType argType = Context->getPointerType(Context->CharTy); SelExprs.push_back(StringLiteral::Create(*Context, Exp->getSelector().getAsString(), - false, false, argType, - SourceLocation())); + StringLiteral::Ascii, false, + argType, SourceLocation())); CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, &SelExprs[0], SelExprs.size()); ReplaceStmt(Exp, SelExp); @@ -2231,8 +2286,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { const char *startRef = 0, *endRef = 0; if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf); - SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1); + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); // Comment out the protocol references. InsertText(LessLoc, "/*"); InsertText(GreaterLoc, "*/"); @@ -2276,8 +2331,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { const char *startRef = 0, *endRef = 0; if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1); + SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); + SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); // Comment out the protocol references. InsertText(LessLoc, "/*"); InsertText(GreaterLoc, "*/"); @@ -2299,9 +2354,9 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { // Get the locations of the startRef, endRef. SourceLocation LessLoc = - Loc.getFileLocWithOffset(startRef-startFuncBuf); + Loc.getLocWithOffset(startRef-startFuncBuf); SourceLocation GreaterLoc = - Loc.getFileLocWithOffset(endRef-startFuncBuf+1); + Loc.getLocWithOffset(endRef-startFuncBuf+1); // Comment out the protocol references. InsertText(LessLoc, "/*"); InsertText(GreaterLoc, "*/"); @@ -2330,7 +2385,7 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { } // FIXME. This will not work for multiple declarators; as in: // __typeof__(a) b,c,d; - std::string TypeAsString(QT.getAsString(Context->PrintingPolicy)); + std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); const char *startBuf = SM->getCharacterData(DeclLoc); if (ND->getInit()) { @@ -2342,13 +2397,13 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { startLoc = ECE->getLParenLoc(); else startLoc = E->getLocStart(); - startLoc = SM->getInstantiationLoc(startLoc); + startLoc = SM->getExpansionLoc(startLoc); const char *endBuf = SM->getCharacterData(startLoc); ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); } else { SourceLocation X = ND->getLocEnd(); - X = SM->getInstantiationLoc(X); + X = SM->getExpansionLoc(X); const char *endBuf = SM->getCharacterData(X); ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); } @@ -2357,7 +2412,7 @@ void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { // SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); void RewriteObjC::SynthSelGetUidFunctionDecl() { IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getFuncType = getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); @@ -2380,7 +2435,7 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { } void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { - std::string TypeString(Type.getAsString(Context->PrintingPolicy)); + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); const char *argPtr = TypeString.c_str(); if (!strchr(argPtr, '^')) { Str += TypeString; @@ -2396,7 +2451,7 @@ void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD) { QualType Type = VD->getType(); - std::string TypeString(Type.getAsString(Context->PrintingPolicy)); + std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); const char *argPtr = TypeString.c_str(); int paren = 0; while (*argPtr) { @@ -2430,7 +2485,7 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { if (!proto) return; QualType Type = proto->getResultType(); - std::string FdStr = Type.getAsString(Context->PrintingPolicy); + std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); FdStr += " "; FdStr += FD->getName(); FdStr += "("; @@ -2451,7 +2506,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { if (SuperContructorFunctionDecl) return; IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; QualType argT = Context->getObjCIdType(); assert(!argT.isNull() && "Can't find 'id' type"); ArgTys.push_back(argT); @@ -2469,7 +2524,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); void RewriteObjC::SynthMsgSendFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; QualType argT = Context->getObjCIdType(); assert(!argT.isNull() && "Can't find 'id' type"); ArgTys.push_back(argT); @@ -2490,7 +2545,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); void RewriteObjC::SynthMsgSendSuperFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), SourceLocation(), &Context->Idents.get("objc_super")); @@ -2514,7 +2569,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); void RewriteObjC::SynthMsgSendStretFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; QualType argT = Context->getObjCIdType(); assert(!argT.isNull() && "Can't find 'id' type"); ArgTys.push_back(argT); @@ -2537,7 +2592,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper_stret"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), SourceLocation(), &Context->Idents.get("objc_super")); @@ -2561,7 +2616,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { // SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); void RewriteObjC::SynthMsgSendFpretFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; QualType argT = Context->getObjCIdType(); assert(!argT.isNull() && "Can't find 'id' type"); ArgTys.push_back(argT); @@ -2582,7 +2637,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { // SynthGetClassFunctionDecl - id objc_getClass(const char *name); void RewriteObjC::SynthGetClassFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size()); @@ -2598,7 +2653,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() { void RewriteObjC::SynthGetSuperClassFunctionDecl() { IdentifierInfo *getSuperClassIdent = &Context->Idents.get("class_getSuperclass"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.push_back(Context->getObjCClassType()); QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), &ArgTys[0], ArgTys.size()); @@ -2615,7 +2670,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { // SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); void RewriteObjC::SynthGetMetaClassFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size()); @@ -2667,7 +2722,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { SourceLocation()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_BitCast, Unop); + CK_CPointerToObjCPointerCast, Unop); ReplaceStmt(Exp, cast); // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return cast; @@ -2770,7 +2825,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } // Synthesize a call to objc_msgSend(). - llvm::SmallVector<Expr*, 8> MsgExprs; + SmallVector<Expr*, 8> MsgExprs; switch (Exp->getReceiverKind()) { case ObjCMessageExpr::SuperClass: { MsgSendFlavor = MsgSendSuperFunctionDecl; @@ -2780,7 +2835,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - llvm::SmallVector<Expr*, 4> InitExprs; + SmallVector<Expr*, 4> InitExprs; // set the receiver to self, the first argument to all methods. InitExprs.push_back( @@ -2793,11 +2848,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ); // set the 'receiver'. // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - llvm::SmallVector<Expr*, 8> ClsExprs; + SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, ClassDecl->getIdentifier()->getName(), - false, false, argType, SourceLocation())); + StringLiteral::Ascii, false, + argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), @@ -2806,7 +2862,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // (Class)objc_getClass("CurrentClass") CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCClassType(), - CK_BitCast, Cls); + CK_CPointerToObjCPointerCast, Cls); ClsExprs.clear(); ClsExprs.push_back(ArgExpr); Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, @@ -2823,7 +2879,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, QualType superType = getSuperStructType(); Expr *SuperRep; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { SynthSuperContructorFunctionDecl(); // Simulate a contructor call... DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, @@ -2868,14 +2924,14 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } case ObjCMessageExpr::Class: { - llvm::SmallVector<Expr*, 8> ClsExprs; + SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ObjCInterfaceDecl *Class = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); IdentifierInfo *clsName = Class->getIdentifier(); ClsExprs.push_back(StringLiteral::Create(*Context, clsName->getName(), - false, false, + StringLiteral::Ascii, false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], @@ -2891,7 +2947,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - llvm::SmallVector<Expr*, 4> InitExprs; + SmallVector<Expr*, 4> InitExprs; InitExprs.push_back( NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), @@ -2902,11 +2958,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ); // set the 'receiver'. // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - llvm::SmallVector<Expr*, 8> ClsExprs; + SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, ClassDecl->getIdentifier()->getName(), - false, false, argType, SourceLocation())); + StringLiteral::Ascii, false, argType, + SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), @@ -2931,7 +2988,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, QualType superType = getSuperStructType(); Expr *SuperRep; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { SynthSuperContructorFunctionDecl(); // Simulate a contructor call... DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, @@ -2975,19 +3032,25 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, Expr *recExpr = Exp->getInstanceReceiver(); while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) recExpr = CE->getSubExpr(); + CastKind CK = recExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : recExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, recExpr); + CK, recExpr); MsgExprs.push_back(recExpr); break; } } // Create a call to sel_registerName("selName"), it will be the 2nd argument. - llvm::SmallVector<Expr*, 8> SelExprs; + SmallVector<Expr*, 8> SelExprs; QualType argType = Context->getPointerType(Context->CharTy); SelExprs.push_back(StringLiteral::Create(*Context, Exp->getSelector().getAsString(), - false, false, argType, SourceLocation())); + StringLiteral::Ascii, false, + argType, SourceLocation())); CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, &SelExprs[0], SelExprs.size(), StartLoc, @@ -3005,16 +3068,42 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, type = Context->getObjCIdType(); // Make sure we convert "type (^)(...)" to "type (*)(...)". (void)convertBlockPointerToFunctionPointer(type); - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK_BitCast, - userExpr); + const Expr *SubExpr = ICE->IgnoreParenImpCasts(); + CastKind CK; + if (SubExpr->getType()->isIntegralType(*Context) && + type->isBooleanType()) { + CK = CK_IntegralToBoolean; + } else if (type->isObjCObjectPointerType()) { + if (SubExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (SubExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + } else { + CK = CK_BitCast; + } + + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); } // Make id<P...> cast into an 'id' cast. else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { if (CE->getType()->isObjCQualifiedIdType()) { while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) userExpr = CE->getSubExpr(); + CastKind CK; + if (userExpr->getType()->isIntegralType(*Context)) { + CK = CK_IntegralToPointer; + } else if (userExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (userExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, userExpr); + CK, userExpr); } } MsgExprs.push_back(userExpr); @@ -3025,7 +3114,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } // Generate the funky cast. CastExpr *cast; - llvm::SmallVector<QualType, 8> ArgTypes; + SmallVector<QualType, 8> ArgTypes; QualType returnType; // Push 'id' and 'SEL', the 2 implicit arguments. @@ -3045,8 +3134,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, (void)convertBlockPointerToFunctionPointer(t); ArgTypes.push_back(t); } - returnType = OMD->getResultType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() : OMD->getResultType(); + returnType = Exp->getType(); + convertToUnqualifiedObjCType(returnType); (void)convertBlockPointerToFunctionPointer(returnType); } else { returnType = Context->getObjCIdType(); @@ -3251,7 +3340,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // SynthesizeObjCInternalStruct is ever called recursively. Result += "\nstruct "; Result += CDecl->getNameAsString(); - if (LangOpts.Microsoft) + if (LangOpts.MicrosoftExt) Result += "_IMPL"; if (NumIvars > 0) { @@ -3275,7 +3364,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // This clause is segregated to avoid breaking the common case. if (BufferContainsPPDirectives(startBuf, cursor)) { SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : - CDecl->getClassLoc(); + CDecl->getAtStartLoc(); const char *endHeader = SM->getCharacterData(L); endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts); @@ -3299,7 +3388,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // insert the super class structure definition. SourceLocation OnePastCurly = - LocStart.getFileLocWithOffset(cursor-startBuf+1); + LocStart.getLocWithOffset(cursor-startBuf+1); InsertText(OnePastCurly, Result); } cursor++; // past '{' @@ -3307,7 +3396,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // Now comment out any visibility specifiers. while (cursor < endBuf) { if (*cursor == '@') { - SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); // Skip whitespace. for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) /*scan*/; @@ -3324,20 +3413,20 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, // of user code, then scan the ivar list and use needToScanForQualifiers // for type checking. else if (*cursor == '<') { - SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); InsertText(atLoc, "/* "); cursor = strchr(cursor, '>'); cursor++; - atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + atLoc = LocStart.getLocWithOffset(cursor-startBuf); InsertText(atLoc, " */"); } else if (*cursor == '^') { // rewrite block specifier. - SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf); ReplaceText(caretLoc, 1, "*"); } cursor++; } // Don't forget to add a ';'!! - InsertText(LocEnd.getFileLocWithOffset(1), ";"); + InsertText(LocEnd.getLocWithOffset(1), ";"); } else { // we don't have any instance variables - insert super struct. endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); Result += " {\n struct "; @@ -3349,7 +3438,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, } // Mark this struct as having been generated. if (!ObjCSynthesizedStructs.insert(CDecl)) - assert(false && "struct already synthesize- SynthesizeObjCInternalStruct"); + llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct"); } // RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or @@ -3358,8 +3447,8 @@ template<typename MethodIterator> void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, MethodIterator MethodEnd, bool IsInstanceMethod, - llvm::StringRef prefix, - llvm::StringRef ClassName, + StringRef prefix, + StringRef ClassName, std::string &Result) { if (MethodBegin == MethodEnd) return; @@ -3428,8 +3517,8 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, /// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. void RewriteObjC:: -RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, llvm::StringRef prefix, - llvm::StringRef ClassName, std::string &Result) { +RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, StringRef prefix, + StringRef ClassName, std::string &Result) { static bool objc_protocol_methods = false; // Output struct protocol_methods holder of method selector and type. @@ -3570,13 +3659,13 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, llvm::StringRef prefix, // Mark this protocol as having been generated. if (!ObjCSynthesizedProtocols.insert(PDecl)) - assert(false && "protocol already synthesized"); + llvm_unreachable("protocol already synthesized"); } void RewriteObjC:: RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols, - llvm::StringRef prefix, llvm::StringRef ClassName, + StringRef prefix, StringRef ClassName, std::string &Result) { if (Protocols.empty()) return; @@ -3634,7 +3723,7 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, FullCategoryName += IDecl->getNameAsString(); // Build _objc_method_list for class's instance methods if needed - llvm::SmallVector<ObjCMethodDecl *, 32> + SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); // If any of our property implementations have associated getters or @@ -3742,7 +3831,7 @@ void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCIvarDecl *ivar, } else { Result += "__OFFSETOFIVAR__(struct "; Result += ivar->getContainingInterface()->getNameAsString(); - if (LangOpts.Microsoft) + if (LangOpts.MicrosoftExt) Result += "_IMPL"; Result += ", "; Result += ivar->getNameAsString(); @@ -3804,7 +3893,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, Result += "\n"; ObjCInterfaceDecl::ivar_iterator IVI, IVE; - llvm::SmallVector<ObjCIvarDecl *, 8> IVars; + SmallVector<ObjCIvarDecl *, 8> IVars; if (!IDecl->ivar_empty()) { for (ObjCInterfaceDecl::ivar_iterator IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end(); @@ -3843,7 +3932,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, } // Build _objc_method_list for class's instance methods if needed - llvm::SmallVector<ObjCMethodDecl *, 32> + SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); // If any of our property implementations have associated getters or @@ -3986,7 +4075,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, // class has size. Must synthesize its size. Result += ",sizeof(struct "; Result += CDecl->getNameAsString(); - if (LangOpts.Microsoft) + if (LangOpts.MicrosoftExt) Result += "_IMPL"; Result += ")"; } @@ -4104,7 +4193,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) { ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; Result += "};\n\n"; - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { if (ProtocolExprDecls.size()) { Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n"; Result += "#pragma data_seg(push, \".objc_protocol$B\")\n"; @@ -4144,12 +4233,12 @@ static bool HasLocalVariableExternalStorage(ValueDecl *VD) { } std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - llvm::StringRef funcName, + StringRef funcName, std::string Tag) { const FunctionType *AFT = CE->getFunctionType(); QualType RT = AFT->getResultType(); std::string StructRef = "struct " + Tag; - std::string S = "static " + RT.getAsString(Context->PrintingPolicy) + " __" + + std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" + funcName.str() + "_" + "block_func_" + utostr(i); BlockDecl *BD = CE->getBlockDecl(); @@ -4173,9 +4262,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, ParamStr = (*AI)->getNameAsString(); QualType QT = (*AI)->getType(); if (convertBlockPointerToFunctionPointer(QT)) - QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); + QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); else - QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); + QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); S += ParamStr; } if (FT->isVariadic()) { @@ -4188,7 +4277,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, // Create local declarations to avoid rewriting all closure decl ref exprs. // First, emit a declaration for all "by ref" decls. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); @@ -4199,7 +4288,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { S += " "; // Handle nested closure invocation. For example: @@ -4224,7 +4313,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, QualType QT = (*I)->getType(); if (HasLocalVariableExternalStorage(*I)) QT = Context->getPointerType(QT); - QT.getAsStringInternal(Name, Context->PrintingPolicy); + QT.getAsStringInternal(Name, Context->getPrintingPolicy()); S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; } @@ -4238,7 +4327,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, } std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - llvm::StringRef funcName, + StringRef funcName, std::string Tag) { std::string StructRef = "struct " + Tag; std::string S = "static void __"; @@ -4250,12 +4339,15 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, S += "*src) {"; for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); S += "_Block_object_assign((void*)&dst->"; S += (*I)->getNameAsString(); S += ", (void*)src->"; S += (*I)->getNameAsString(); if (BlockByRefDeclsPtrSet.count((*I))) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; else S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } @@ -4268,10 +4360,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, S += "*src) {"; for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), E = ImportedBlockDecls.end(); I != E; ++I) { + ValueDecl *VD = (*I); S += "_Block_object_dispose((void*)src->"; S += (*I)->getNameAsString(); if (BlockByRefDeclsPtrSet.count((*I))) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else if (VD->getType()->isBlockPointerType()) + S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; else S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } @@ -4294,7 +4389,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, if (BlockDeclRefs.size()) { // Output all "by copy" declarations. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { S += " "; std::string FieldName = (*I)->getNameAsString(); @@ -4316,14 +4411,14 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, QualType QT = (*I)->getType(); if (HasLocalVariableExternalStorage(*I)) QT = Context->getPointerType(QT); - QT.getAsStringInternal(FieldName, Context->PrintingPolicy); - QT.getAsStringInternal(ArgName, Context->PrintingPolicy); + QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); + QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); Constructor += ", " + ArgName; } S += FieldName + ";\n"; } // Output all "by ref" declarations. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string FieldName = (*I)->getNameAsString(); @@ -4342,7 +4437,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += ", int flags=0)"; // Initialize all "by copy" arguments. bool firsTime = true; - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); if (firsTime) { @@ -4357,7 +4452,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += Name + "(_" + Name + ")"; } // Initialize all "by ref" arguments. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); if (firsTime) { @@ -4396,7 +4491,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, std::string ImplTag, int i, - llvm::StringRef FunName, + StringRef FunName, unsigned hasCopy) { std::string S = "\nstatic struct " + DescTag; @@ -4423,7 +4518,7 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, } void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - llvm::StringRef FunName) { + StringRef FunName) { // Insert declaration for the function in which block literal is used. if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); @@ -4512,7 +4607,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - llvm::StringRef FuncName = FD->getName(); + StringRef FuncName = FD->getName(); SynthesizeBlockLiterals(FunLocStart, FuncName); } @@ -4564,7 +4659,7 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { } void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, - llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, + SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) { for (Stmt::child_range CI = S->children(); CI; ++CI) if (*CI) { @@ -4603,7 +4698,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); // FTP will be null for closures that don't take arguments. // Generate a funky cast. - llvm::SmallVector<QualType, 8> ArgTypes; + SmallVector<QualType, 8> ArgTypes; QualType Res = FT->getResultType(); bool HasBlockType = convertBlockPointerToFunctionPointer(Res); @@ -4673,7 +4768,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); // Generate a funky cast. - llvm::SmallVector<QualType, 8> ArgTypes; + SmallVector<QualType, 8> ArgTypes; // Push the block argument type. ArgTypes.push_back(PtrBlock); @@ -4716,7 +4811,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { CK_BitCast, ME); PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); - llvm::SmallVector<Expr*, 8> BlkExprs; + SmallVector<Expr*, 8> BlkExprs; // Add the implicit argument. BlkExprs.push_back(BlkCast); // Add the user arguments. @@ -4767,7 +4862,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { FD->getType(), VK_LValue, OK_Ordinary); - llvm::StringRef Name = VD->getName(); + StringRef Name = VD->getName(); FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, @@ -4835,7 +4930,7 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { switch (*argPtr) { case '^': // Replace the '^' with '*'. - LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); + LocStart = LocStart.getLocWithOffset(argPtr-startBuf); ReplaceText(LocStart, 1, "*"); break; } @@ -4855,7 +4950,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { parenCount++; // advance the location to startArgList. - DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf); + DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); assert((DeclLoc.isValid()) && "Invalid DeclLoc"); const char *argPtr = startArgList; @@ -4864,7 +4959,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { switch (*argPtr) { case '^': // Replace the '^' with '*'. - DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); + DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); ReplaceText(DeclLoc, 1, "*"); break; case '(': @@ -4957,14 +5052,14 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) DeclT = FD->getType(); else - assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled"); + llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); const char *startBuf = SM->getCharacterData(DeclLoc); const char *endBuf = startBuf; // scan backward (from the decl location) for the end of the previous decl. while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) startBuf--; - SourceLocation Start = DeclLoc.getFileLocWithOffset(startBuf-endBuf); + SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); std::string buf; unsigned OrigLength=0; // *startBuf != '^' if we are dealing with a pointer to function that @@ -5108,7 +5203,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { DeclLoc = ND->getLocation(); const char *startBuf = SM->getCharacterData(DeclLoc); SourceLocation X = ND->getLocEnd(); - X = SM->getInstantiationLoc(X); + X = SM->getExpansionLoc(X); const char *endBuf = SM->getCharacterData(X); std::string Name(ND->getNameAsString()); std::string ByrefType; @@ -5130,7 +5225,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { QualType T = Ty; (void)convertBlockPointerToFunctionPointer(T); - T.getAsStringInternal(Name, Context->PrintingPolicy); + T.getAsStringInternal(Name, Context->getPrintingPolicy()); ByrefType += " " + Name + ";\n"; ByrefType += "};\n"; @@ -5203,7 +5298,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { startLoc = ECE->getLParenLoc(); else startLoc = E->getLocStart(); - startLoc = SM->getInstantiationLoc(startLoc); + startLoc = SM->getExpansionLoc(startLoc); endBuf = SM->getCharacterData(startLoc); ByrefType += " " + Name; ByrefType += " = {(void*)"; @@ -5235,7 +5330,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { const char *semiBuf = strchr(startInitializerBuf, ';'); assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); SourceLocation semiLoc = - startLoc.getFileLocWithOffset(semiBuf-startInitializerBuf); + startLoc.getLocWithOffset(semiBuf-startInitializerBuf); InsertText(semiLoc, "}"); } @@ -5271,7 +5366,7 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { } } -FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) { +FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) { IdentifierInfo *ID = &Context->Idents.get(name); QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), @@ -5280,7 +5375,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) { } Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, - const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) { + const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) { const BlockDecl *block = Exp->getBlockDecl(); Blocks.push_back(Exp); @@ -5343,7 +5438,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, VK_RValue, SourceLocation()); - llvm::SmallVector<Expr*, 4> InitExprs; + SmallVector<Expr*, 4> InitExprs; // Initialize the block function. FD = SynthBlockInitFunctionDecl(Func); @@ -5376,7 +5471,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, if (BlockDeclRefs.size()) { Expr *Exp; // Output all "by copy" declarations. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { if (isObjCType((*I)->getType())) { // FIXME: Conform to ABI ([[obj retain] autorelease]). @@ -5410,7 +5505,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, InitExprs.push_back(Exp); } // Output all "by ref" declarations. - for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { ValueDecl *ND = (*I); std::string Name(ND->getNameAsString()); @@ -5557,7 +5652,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { } if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - llvm::SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs; + SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs; llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts; InnerContexts.insert(BE->getBlockDecl()); ImportedLocalExternalDecls.clear(); @@ -5568,12 +5663,20 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { CurrentBody = BE->getBody(); CollectPropertySetters(CurrentBody); PropParentMap = 0; + // block literal on rhs of a property-dot-sytax assignment + // must be replaced by its synthesize ast so getRewrittenText + // works as expected. In this case, what actually ends up on RHS + // is the blockTranscribed which is the helper function for the + // block literal; as in: self.c = ^() {[ace ARR];}; + bool saveDisableReplaceStmt = DisableReplaceStmt; + DisableReplaceStmt = false; RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); + DisableReplaceStmt = saveDisableReplaceStmt; CurrentBody = SaveCurrentBody; PropParentMap = 0; ImportedLocalExternalDecls.clear(); // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.ConvertToString(BE->getBody()); + std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); @@ -5866,8 +5969,8 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { ClassImplementation.push_back(CI); else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D)) CategoryImplementation.push_back(CI); - else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D)) - RewriteForwardClassDecl(CD); + else if (isa<ObjCClassDecl>(D)) + llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl"); else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { RewriteObjCQualifiedInterfaceTypes(VD); if (isTopLevelBlockPointerType(VD->getType())) @@ -5881,7 +5984,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } } else if (VD->getType()->isRecordType()) { RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) RewriteRecordBody(RD); } if (VD->getInit()) { @@ -5913,7 +6016,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { return; } if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) RewriteRecordBody(RD); return; } diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp index cfedd4b..6c211b2 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp @@ -12,11 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/Rewrite/RewriteRope.h" -#include "llvm/Support/Casting.h" +#include "clang/Basic/LLVM.h" #include <algorithm> using namespace clang; -using llvm::dyn_cast; -using llvm::cast; /// RewriteRope is a "strong" string class, designed to make insertions and /// deletions in the middle of the string nearly constant time (really, they are diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp index 3620700..c446324 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp @@ -16,7 +16,7 @@ #include "clang/Rewrite/TokenRewriter.h" #include "llvm/Support/raw_ostream.h" -void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) { +void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { SourceManager &SM = PP.getSourceManager(); const LangOptions &LangOpts = PP.getLangOptions(); diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp index 92f5160..464b299cc 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp @@ -17,10 +17,9 @@ #include "clang/AST/Decl.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/SourceManager.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; -llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const { +raw_ostream &RewriteBuffer::write(raw_ostream &os) const { // FIXME: eliminate the copy by writing out each chunk at a time os << std::string(begin(), end()); return os; @@ -84,7 +83,7 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, } } -void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str, +void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, bool InsertAfter) { // Nothing to insert, exit early. @@ -101,7 +100,7 @@ void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str, /// buffer with a new string. This is effectively a combined "remove+insert" /// operation. void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, - llvm::StringRef NewStr) { + StringRef NewStr) { unsigned RealOffset = getMappedOffset(OrigOffset, true); Buffer.erase(RealOffset, OrigLength); Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); @@ -222,7 +221,7 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { return I->second; I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); - llvm::StringRef MB = SourceMgr->getBufferData(FID); + StringRef MB = SourceMgr->getBufferData(FID); I->second.Initialize(MB.begin(), MB.end()); return I->second; @@ -230,10 +229,8 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { /// InsertText - Insert the specified string at the specified location in the /// original buffer. -bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str, +bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter, bool indentNewLines) { - using llvm::StringRef; - if (!isRewritable(Loc)) return true; FileID FID; unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); @@ -256,7 +253,7 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str, indentSpace = MB.substr(lineOffs, i-lineOffs); } - llvm::SmallVector<StringRef, 4> lines; + SmallVector<StringRef, 4> lines; Str.split(lines, "\n"); for (unsigned i = 0, e = lines.size(); i != e; ++i) { @@ -273,7 +270,7 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str, return false; } -bool Rewriter::InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str) { +bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { if (!isRewritable(Loc)) return true; FileID FID; unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); @@ -298,7 +295,7 @@ bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, /// buffer with a new string. This is effectively a combined "remove/insert" /// operation. bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, - llvm::StringRef NewStr) { + StringRef NewStr) { if (!isRewritable(Start)) return true; FileID StartFileID; unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); @@ -317,7 +314,7 @@ bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { FileID FID; unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), FID); - llvm::StringRef MB = SourceMgr->getBufferData(FID); + StringRef MB = SourceMgr->getBufferData(FID); return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); } @@ -349,8 +346,6 @@ std::string Rewriter::ConvertToString(Stmt *From) { bool Rewriter::IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent) { - using llvm::StringRef; - if (range.isInvalid()) return true; if (!isRewritable(range.getBegin())) return true; if (!isRewritable(range.getEnd())) return true; @@ -400,7 +395,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range, if (!startSpace.startswith(parentSpace)) return true; - llvm::StringRef indent = startSpace.substr(parentSpace.size()); + StringRef indent = startSpace.substr(parentSpace.size()); // Indent the lines between start/end offsets. RewriteBuffer &RB = getEditBuffer(FID); diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 7a14855e..babb8af 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -25,14 +26,23 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/UninitializedValues.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include <algorithm> +#include <vector> using namespace clang; @@ -86,7 +96,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); @@ -101,7 +111,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += reachable_code::ScanReachableFromBlock(b, live); + count += reachable_code::ScanReachableFromBlock(&b, live); continue; } } @@ -126,31 +136,23 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { if (!live[B.getBlockID()]) continue; + // Skip blocks which contain an element marked as no-return. They don't + // represent actually viable edges into the exit block, so mark them as + // abnormal. + if (B.hasNoReturnElement()) { + HasAbnormalEdge = true; + continue; + } + // Destructors can appear after the 'return' in the CFG. This is // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); - bool hasNoReturnDtor = false; - - for ( ; ri != re ; ++ri) { - CFGElement CE = *ri; - - // FIXME: The right solution is to just sever the edges in the - // CFG itself. - if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>()) - if (iDtor->isNoReturn(AC.getASTContext())) { - hasNoReturnDtor = true; - HasFakeEdge = true; - break; - } - - if (isa<CFGStmt>(CE)) + + for ( ; ri != re ; ++ri) + if (isa<CFGStmt>(*ri)) break; - } - - if (hasNoReturnDtor) - continue; - + // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { @@ -163,7 +165,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } CFGStmt CS = cast<CFGStmt>(*ri); - Stmt *S = CS.getStmt(); + const Stmt *S = CS.getStmt(); if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; @@ -187,34 +189,13 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { HasAbnormalEdge = true; continue; } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) - == B.succ_end()) { - HasAbnormalEdge = true; - continue; - } - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - QualType calleeType = CEE->getType(); - if (calleeType == AC.getASTContext().BoundMemberTy) { - calleeType = Expr::findBoundMemberType(CEE); - assert(!calleeType.isNull() && "analyzing unresolved call?"); - } - if (getFunctionExtInfo(calleeType).getNoReturn()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } + if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) + == B.succ_end()) { + HasAbnormalEdge = true; + continue; } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; + + HasPlainEdge = true; } if (!HasPlainEdge) { if (HasLiveReturn) @@ -258,7 +239,23 @@ struct CheckFallThroughDiagnostics { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) isVirtualMethod = Method->isVirtual(); - if (!isVirtualMethod) + // Don't suggest that template instantiations be marked "noreturn" + bool isTemplateInstantiation = false; + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) { + switch (Function->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + break; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + isTemplateInstantiation = true; + break; + } + } + + if (!isVirtualMethod && !isTemplateInstantiation) D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function; else @@ -284,25 +281,25 @@ struct CheckFallThroughDiagnostics { return D; } - bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, + bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { return (ReturnsVoid || D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!HasNoReturn || D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } // For blocks. return ReturnsVoid && !HasNoReturn && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } }; @@ -340,7 +337,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, } } - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) @@ -369,9 +366,17 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) - S.Diag(Compound->getLBracLoc(), - CD.diag_NeverFallThroughOrReturn); + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 1 << MD; + } else { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); + } + } break; case NeverFallThrough: break; @@ -415,13 +420,58 @@ public: }; } +static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { + // Don't issue a fixit if there is already an initializer. + if (VD->getInit()) + return false; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType VariableTy = VD->getType().getCanonicalType(); + + if (VariableTy->isObjCObjectPointerType() || + VariableTy->isBlockPointerType()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (VariableTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (VariableTy->isEnumeralType()) + return false; + else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { + if (S.Context.getLangOptions().CPlusPlus0x) + initialization = " = nullptr"; + // Check if 'NULL' is defined. + else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) + initialization = " = NULL"; + else + initialization = " = 0"; + } + else if (VariableTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() + << FixItHint::CreateInsertion(loc, initialization); + return true; + } + return false; +} + /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed /// as a warning. If a pariticular use is one we omit warnings for, returns /// false. static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, - const Expr *E, bool isAlwaysUninit) { + const Expr *E, bool isAlwaysUninit, + bool alwaysReportSelfInit = false) { bool isSelfInit = false; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { @@ -441,7 +491,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, // TODO: Should we suppress maybe-uninitialized warnings for // variables initialized in this way? if (const Expr *Initializer = VD->getInit()) { - if (DRE == Initializer->IgnoreParenImpCasts()) + if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) return false; ContainsReference CR(S.Context, DRE); @@ -469,54 +519,15 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, } // Report where the variable was declared when the use wasn't within - // the initializer of that declaration. - if (!isSelfInit) + // the initializer of that declaration & we didn't already suggest + // an initialization fixit. + if (!isSelfInit && !SuggestInitializationFixit(S, VD)) S.Diag(VD->getLocStart(), diag::note_uninit_var_def) << VD->getDeclName(); return true; } -static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { - // Don't issue a fixit if there is already an initializer. - if (VD->getInit()) - return; - - // Suggest possible initialization (if any). - const char *initialization = 0; - QualType VariableTy = VD->getType().getCanonicalType(); - - if (VariableTy->isObjCObjectPointerType() || - VariableTy->isBlockPointerType()) { - // Check if 'nil' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) - initialization = " = nil"; - else - initialization = " = 0"; - } - else if (VariableTy->isRealFloatingType()) - initialization = " = 0.0"; - else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) - initialization = " = false"; - else if (VariableTy->isEnumeralType()) - return; - else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { - // Check if 'NULL' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) - initialization = " = NULL"; - else - initialization = " = 0"; - } - else if (VariableTy->isScalarType()) - initialization = " = 0"; - - if (initialization) { - SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); - S.Diag(loc, diag::note_var_fixit_add_initialization) - << FixItHint::CreateInsertion(loc, initialization); - } -} - typedef std::pair<const Expr*, bool> UninitUse; namespace { @@ -530,8 +541,8 @@ struct SLocSort { class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector<UninitUse, 2> UsesVec; - typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap; + typedef SmallVector<UninitUse, 2> UsesVec; + typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap; UsesMap *uses; public: @@ -539,17 +550,26 @@ public: ~UninitValsDiagReporter() { flushDiagnostics(); } - - void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, - bool isAlwaysUninit) { + + std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) { if (!uses) uses = new UsesMap(); - - UsesVec *&vec = (*uses)[vd]; + + UsesMap::mapped_type &V = (*uses)[vd]; + UsesVec *&vec = V.first; if (!vec) vec = new UsesVec(); - vec->push_back(std::make_pair(ex, isAlwaysUninit)); + return V; + } + + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, + bool isAlwaysUninit) { + getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit)); + } + + void handleSelfInit(const VarDecl *vd) { + getUses(vd).second = true; } void flushDiagnostics() { @@ -558,28 +578,34 @@ public: for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) { const VarDecl *vd = i->first; - UsesVec *vec = i->second; - - bool fixitIssued = false; - - // Sort the uses by their SourceLocations. While not strictly - // guaranteed to produce them in line/column order, this will provide - // a stable ordering. - std::sort(vec->begin(), vec->end(), SLocSort()); - - for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; - ++vi) { - if (!DiagnoseUninitializedUse(S, vd, vi->first, - /*isAlwaysUninit=*/vi->second)) - continue; - - // Suggest a fixit hint the first time we diagnose a use of a variable. - if (!fixitIssued) { - SuggestInitializationFixit(S, vd); - fixitIssued = true; + const UsesMap::mapped_type &V = i->second; + + UsesVec *vec = V.first; + bool hasSelfInit = V.second; + + // Specially handle the case where we have uses of an uninitialized + // variable, but the root cause is an idiomatic self-init. We want + // to report the diagnostic at the self-init since that is the root cause. + if (!vec->empty() && hasSelfInit) + DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(), + true, /* alwaysReportSelfInit */ true); + else { + // Sort the uses by their SourceLocations. While not strictly + // guaranteed to produce them in line/column order, this will provide + // a stable ordering. + std::sort(vec->begin(), vec->end(), SLocSort()); + + for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; + ++vi) { + if (DiagnoseUninitializedUse(S, vd, vi->first, + /*isAlwaysUninit=*/vi->second)) + // Skip further diagnostics for this variable. We try to warn only + // on the first point at which a variable is used uninitialized. + break; } } - + + // Release the uses vector. delete vec; } delete uses; @@ -587,6 +613,132 @@ public: }; } + +//===----------------------------------------------------------------------===// +// -Wthread-safety +//===----------------------------------------------------------------------===// +namespace clang { +namespace thread_safety { +typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag; +typedef llvm::SmallVector<DelayedDiag, 4> DiagList; + +struct SortDiagBySourceLocation { + Sema &S; + SortDiagBySourceLocation(Sema &S) : S(S) {} + + bool operator()(const DelayedDiag &left, const DelayedDiag &right) { + // Although this call will be slow, this is only called when outputting + // multiple warnings. + return S.getSourceManager().isBeforeInTranslationUnit(left.first, + right.first); + } +}; + +class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { + Sema &S; + DiagList Warnings; + + // Helper functions + void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(DiagID) << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + public: + ThreadSafetyReporter(Sema &S) : S(S) {} + + /// \brief Emit all buffered diagnostics in order of sourcelocation. + /// We need to output diagnostics produced while iterating through + /// the lockset in deterministic order, so this function orders diagnostics + /// and outputs them. + void emitDiagnostics() { + SortDiagBySourceLocation SortDiagBySL(S); + sort(Warnings.begin(), Warnings.end(), SortDiagBySL); + for (DiagList::iterator I = Warnings.begin(), E = Warnings.end(); + I != E; ++I) + S.Diag(I->first, I->second); + } + + void handleInvalidLockExp(SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc); + } + + void handleDoubleLock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_double_lock, LockName, Loc); + } + + void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc, + LockErrorKind LEK){ + unsigned DiagID = 0; + switch (LEK) { + case LEK_LockedSomePredecessors: + DiagID = diag::warn_lock_at_end_of_scope; + break; + case LEK_LockedSomeLoopIterations: + DiagID = diag::warn_expecting_lock_held_on_loop; + break; + case LEK_LockedAtEndOfFunction: + DiagID = diag::warn_no_unlock; + break; + } + warnLockMismatch(DiagID, LockName, Loc); + } + + + void handleExclusiveAndShared(Name LockName, SourceLocation Loc1, + SourceLocation Loc2) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName; + PartialDiagnostic Note = + S.PDiag(diag::note_lock_exclusive_and_shared) << LockName; + Warnings.push_back(DelayedDiag(Loc1, Warning)); + Warnings.push_back(DelayedDiag(Loc2, Note)); + } + + void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, + AccessKind AK, SourceLocation Loc) { + assert((POK == POK_VarAccess || POK == POK_VarDereference) + && "Only works for variables"); + unsigned DiagID = POK == POK_VarAccess? + diag::warn_variable_requires_any_lock: + diag::warn_var_deref_requires_any_lock; + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << getLockKindFromAccessKind(AK); + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK, + Name LockName, LockKind LK, SourceLocation Loc) { + unsigned DiagID = 0; + switch (POK) { + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock; + break; + } + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << LockName << LK; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } +}; +} +} + //===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. @@ -595,6 +747,7 @@ public: clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; enableCheckUnreachable = 0; + enableThreadSafetyAnalysis = 0; } clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) @@ -608,14 +761,18 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) MaxUninitAnalysisVariablesPerFunction(0), NumUninitAnalysisBlockVisits(0), MaxUninitAnalysisBlockVisitsPerFunction(0) { - Diagnostic &D = S.getDiagnostics(); + DiagnosticsEngine &D = S.getDiagnostics(); DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) != - Diagnostic::Ignored); + DiagnosticsEngine::Ignored); + DefaultPolicy.enableThreadSafetyAnalysis = (unsigned) + (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) != + DiagnosticsEngine::Ignored); + } static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) { - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -635,7 +792,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // don't bother trying. // (2) The code already has problems; running the analysis just takes more // time. - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Do not do any analysis for declarations in system headers if we are // going to just ignore them. @@ -656,17 +813,43 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, const Stmt *Body = D->getBody(); assert(Body); + AnalysisContext AC(D, 0); + // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. - AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false, - /*addImplicitDtors=*/true, /*addInitializers=*/true); + AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; + AC.getCFGBuildOptions().AddEHEdges = false; + AC.getCFGBuildOptions().AddInitializers = true; + AC.getCFGBuildOptions().AddImplicitDtors = true; + + // Force that certain expressions appear as CFGElements in the CFG. This + // is used to speed up various analyses. + // FIXME: This isn't the right factoring. This is here for initial + // prototyping, but we need a way for analyses to say what expressions they + // expect to always be CFGElements and then fill in the BuildOptions + // appropriately. This is essentially a layering violation. + if (P.enableCheckUnreachable) { + // Unreachable code analysis requires a linearized CFG. + AC.getCFGBuildOptions().setAllAlwaysAdd(); + } + else { + AC.getCFGBuildOptions() + .setAlwaysAdd(Stmt::BinaryOperatorClass) + .setAlwaysAdd(Stmt::BlockExprClass) + .setAlwaysAdd(Stmt::CStyleCastExprClass) + .setAlwaysAdd(Stmt::DeclRefExprClass) + .setAlwaysAdd(Stmt::ImplicitCastExprClass) + .setAlwaysAdd(Stmt::UnaryOperatorClass); + } + // Construct the analysis context with the specified CFG build options. + // Emit delayed diagnostics. if (!fscope->PossiblyUnreachableDiags.empty()) { bool analyzed = false; // Register the expressions with the CFGBuilder. - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -676,7 +859,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (AC.getCFG()) { analyzed = true; - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) @@ -716,11 +899,18 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check for unreachable code if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - + + // Check for thread safety violations + if (P.enableThreadSafetyAnalysis) { + thread_safety::ThreadSafetyReporter Reporter(S); + thread_safety::runThreadSafetyAnalysis(AC, Reporter); + Reporter.emitDiagnostics(); + } + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) - != Diagnostic::Ignored || + != DiagnosticsEngine::Ignored || Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart()) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); UninitVariablesAnalysisStats stats; diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp index 5a8330b..13a0ede 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp @@ -98,7 +98,7 @@ AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, } AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - llvm::StringRef AttrName = Name->getName(); + StringRef AttrName = Name->getName(); // Normalize the attribute name, __foo__ becomes foo. if (AttrName.startswith("__") && AttrName.endswith("__")) @@ -159,10 +159,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("address_space", AT_address_space) .Case("opencl_image_access", AT_opencl_image_access) .Case("always_inline", AT_always_inline) - .Case("returns_twice", IgnoredAttribute) + .Case("returns_twice", AT_returns_twice) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("objc_method_family", AT_objc_method_family) + .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer) .Case("ext_vector_type", AT_ext_vector_type) .Case("neon_vector_type", AT_neon_vector_type) .Case("neon_polyvector_type", AT_neon_polyvector_type) @@ -170,15 +171,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) .Case("carries_dependency", AT_carries_dependency) + .Case("ns_bridged", AT_ns_bridged) .Case("ns_consumed", AT_ns_consumed) .Case("ns_consumes_self", AT_ns_consumes_self) .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased) .Case("ns_returns_not_retained", AT_ns_returns_not_retained) .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_audited_transfer", AT_cf_audited_transfer) .Case("cf_consumed", AT_cf_consumed) .Case("cf_returns_not_retained", AT_cf_returns_not_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased) + .Case("cf_unknown_transfer", AT_cf_unknown_transfer) .Case("ns_consumes_self", AT_ns_consumes_self) .Case("ns_consumed", AT_ns_consumed) .Case("objc_ownership", AT_objc_ownership) @@ -209,5 +213,23 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("uuid", AT_uuid) .Case("pcs", AT_pcs) .Case("ms_struct", AT_MsStruct) + .Case("guarded_var", AT_guarded_var) + .Case("pt_guarded_var", AT_pt_guarded_var) + .Case("scoped_lockable", AT_scoped_lockable) + .Case("lockable", AT_lockable) + .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis) + .Case("guarded_by", AT_guarded_by) + .Case("pt_guarded_by", AT_pt_guarded_by) + .Case("acquired_after", AT_acquired_after) + .Case("acquired_before", AT_acquired_before) + .Case("exclusive_lock_function", AT_exclusive_lock_function) + .Case("exclusive_locks_required", AT_exclusive_locks_required) + .Case("exclusive_trylock_function", AT_exclusive_trylock_function) + .Case("lock_returned", AT_lock_returned) + .Case("locks_excluded", AT_locks_excluded) + .Case("shared_lock_function", AT_shared_lock_function) + .Case("shared_locks_required", AT_shared_locks_required) + .Case("shared_trylock_function", AT_shared_trylock_function) + .Case("unlock_function", AT_unlock_function) .Default(UnknownAttribute); } diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index d7dc5b2..da98603 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -26,7 +26,6 @@ #include <functional> using namespace clang; -using llvm::StringRef; //===----------------------------------------------------------------------===// // Code completion context implementation @@ -68,7 +67,7 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_OtherWithMacros: case CCC_ObjCInstanceMessage: case CCC_ObjCClassMessage: - case CCC_ObjCSuperclass: + case CCC_ObjCInterfaceName: case CCC_ObjCCategoryName: return false; } @@ -191,14 +190,36 @@ CodeCompletionString::Chunk::CreateCurrentParameter( CodeCompletionString::CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, unsigned Priority, - CXAvailabilityKind Availability) - : NumChunks(NumChunks), Priority(Priority), Availability(Availability) + CXAvailabilityKind Availability, + const char **Annotations, + unsigned NumAnnotations) + : NumChunks(NumChunks), NumAnnotations(NumAnnotations) + , Priority(Priority), Availability(Availability) { + assert(NumChunks <= 0xffff); + assert(NumAnnotations <= 0xffff); + Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1); for (unsigned I = 0; I != NumChunks; ++I) StoredChunks[I] = Chunks[I]; + + const char **StoredAnnotations = reinterpret_cast<const char **>(StoredChunks + NumChunks); + for (unsigned I = 0; I != NumAnnotations; ++I) + StoredAnnotations[I] = Annotations[I]; +} + +unsigned CodeCompletionString::getAnnotationCount() const { + return NumAnnotations; +} + +const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const { + if (AnnotationNr < NumAnnotations) + return reinterpret_cast<const char * const*>(end())[AnnotationNr]; + else + return 0; } + std::string CodeCompletionString::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); @@ -228,14 +249,14 @@ const char *CodeCompletionString::getTypedText() const { return 0; } -const char *CodeCompletionAllocator::CopyString(llvm::StringRef String) { +const char *CodeCompletionAllocator::CopyString(StringRef String) { char *Mem = (char *)Allocate(String.size() + 1, 1); std::copy(String.begin(), String.end(), Mem); Mem[String.size()] = 0; return Mem; } -const char *CodeCompletionAllocator::CopyString(llvm::Twine String) { +const char *CodeCompletionAllocator::CopyString(Twine String) { // FIXME: It would be more efficient to teach Twine to tell us its size and // then add a routine there to fill in an allocated char* with the contents // of the string. @@ -245,11 +266,13 @@ const char *CodeCompletionAllocator::CopyString(llvm::Twine String) { CodeCompletionString *CodeCompletionBuilder::TakeString() { void *Mem = Allocator.Allocate( - sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), + sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() + + sizeof(const char *) * Annotations.size(), llvm::alignOf<CodeCompletionString>()); CodeCompletionString *Result = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), - Priority, Availability); + Priority, Availability, + Annotations.data(), Annotations.size()); Chunks.clear(); return Result; } @@ -329,7 +352,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case CodeCompletionResult::RK_Declaration: - OS << Results[I].Declaration; + OS << *Results[I].Declaration; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS @@ -377,7 +400,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -void CodeCompletionResult::computeCursorKindAndAvailability() { +void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { switch (Kind) { case RK_Declaration: // Set the availability based on attributes. @@ -419,13 +442,16 @@ void CodeCompletionResult::computeCursorKindAndAvailability() { // Do nothing: Patterns can come with cursor kinds! break; } + + if (!Accessible) + Availability = CXAvailability_NotAccessible; } /// \brief Retrieve the name that should be used to order a result. /// /// If the name needs to be constructed as a string, that string will be /// saved into Saved and the returned StringRef will refer to it. -static llvm::StringRef getOrderedName(const CodeCompletionResult &R, +static StringRef getOrderedName(const CodeCompletionResult &R, std::string &Saved) { switch (R.Kind) { case CodeCompletionResult::RK_Keyword: @@ -460,8 +486,8 @@ static llvm::StringRef getOrderedName(const CodeCompletionResult &R, bool clang::operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y) { std::string XSaved, YSaved; - llvm::StringRef XStr = getOrderedName(X, XSaved); - llvm::StringRef YStr = getOrderedName(Y, YSaved); + StringRef XStr = getOrderedName(X, XSaved); + StringRef YStr = getOrderedName(Y, YSaved); int cmp = XStr.compare_lower(YStr); if (cmp) return cmp < 0; diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index c87f2cf..f0a763e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/LocInfoType.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" @@ -27,7 +28,7 @@ using namespace clang; -static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, +static DiagnosticBuilder Diag(DiagnosticsEngine &D, SourceLocation Loc, unsigned DiagID) { return D.Report(Loc, DiagID); } @@ -242,6 +243,7 @@ bool Declarator::isDeclarationOfFunction() const { } switch (DS.getTypeSpecType()) { + case TST_atomic: case TST_auto: case TST_bool: case TST_char: @@ -255,6 +257,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_enum: case TST_error: case TST_float: + case TST_half: case TST_int: case TST_struct: case TST_union: @@ -371,6 +374,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_char16: return "char16_t"; case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; + case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; case DeclSpec::TST_bool: return "_Bool"; @@ -388,6 +392,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; + case DeclSpec::TST_atomic: return "_Atomic"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); @@ -403,21 +408,24 @@ const char *DeclSpec::getSpecifierName(TQ T) { llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, +bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID, - const LangOptions &Lang) { - // OpenCL prohibits extern, auto, register, and static + unsigned &DiagID) { + // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class + // specifiers are not supported." // It seems sensible to prohibit private_extern too - if (Lang.OpenCL) { - switch (S) { + // The cl_clang_storage_class_specifiers extension enables support for + // these storage-class specifiers. + if (S.getLangOptions().OpenCL && + !S.getOpenCLOptions().cl_clang_storage_class_specifiers) { + switch (SC) { case SCS_extern: case SCS_private_extern: case SCS_auto: case SCS_register: case SCS_static: DiagID = diag::err_not_opencl_storage_class_specifier; - PrevSpec = getSpecifierName(S); + PrevSpec = getSpecifierName(SC); return true; default: break; @@ -425,17 +433,30 @@ bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { + // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + bool isInvalid = true; + if (TypeSpecType == TST_unspecified && S.getLangOptions().CPlusPlus) { + if (SC == SCS_auto) + return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID); + if (StorageClassSpec == SCS_auto) { + isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc, + PrevSpec, DiagID); + assert(!isInvalid && "auto SCS -> TST recovery failed"); + } + } + // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and // the new storage class is 'typedef'. - if (!(SCS_extern_in_linkage_spec && + if (isInvalid && + !(SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern && - S == SCS_typedef)) - return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); + SC == SCS_typedef)) + return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID); } - StorageClassSpec = S; + StorageClassSpec = SC; StorageClassSpecLoc = Loc; - assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield"); + assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield"); return false; } @@ -637,7 +658,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, TypeQualifiers |= T; switch (T) { - default: assert(0 && "Unknown type qualifier!"); + default: llvm_unreachable("Unknown type qualifier!"); case TQ_const: TQ_constLoc = Loc; break; case TQ_restrict: TQ_restrictLoc = Loc; break; case TQ_volatile: TQ_volatileLoc = Loc; break; @@ -682,6 +703,18 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, return false; } +bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + if (isModulePrivateSpecified()) { + PrevSpec = "__module_private__"; + DiagID = diag::ext_duplicate_declspec; + return true; + } + + ModulePrivateLoc = Loc; + return false; +} + bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'constexpr constexpr' is ok. @@ -732,7 +765,7 @@ void DeclSpec::SaveStorageSpecifierAsWritten() { /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. -void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { +void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); SaveStorageSpecifierAsWritten(); @@ -836,6 +869,27 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } } + // If no type specifier was provided and we're parsing a language where + // the type specifier is not optional, but we got 'auto' as a storage + // class specifier, then assume this is an attempt to use C++0x's 'auto' + // type specifier. + // FIXME: Does Microsoft really support implicit int in C++? + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().MicrosoftExt && + TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { + TypeSpecType = TST_auto; + StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified; + TSTLoc = TSTNameLoc = StorageClassSpecLoc; + StorageClassSpecLoc = SourceLocation(); + } + // Diagnose if we've recovered from an ill-formed 'auto' storage class + // specifier in a pre-C++0x dialect of C++. + if (!PP.getLangOptions().CPlusPlus0x && TypeSpecType == TST_auto) + Diag(D, TSTLoc, diag::ext_auto_type_specifier); + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().CPlusPlus0x && + StorageClassSpec == SCS_auto) + Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) + << FixItHint::CreateRemoval(StorageClassSpecLoc); + // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. @@ -844,7 +898,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); + SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, diag::err_friend_storage_spec) << SpecName @@ -854,7 +908,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); - + // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. @@ -902,7 +956,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, Specifiers |= VS; switch (VS) { - default: assert(0 && "Unknown specifier!"); + default: llvm_unreachable("Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; case VS_Final: VS_finalLoc = Loc; break; } @@ -912,7 +966,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *VirtSpecifiers::getSpecifierName(Specifier VS) { switch (VS) { - default: assert(0 && "Unknown specifier"); + default: llvm_unreachable("Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; } diff --git a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp index c6744ed..d6c1ad1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp @@ -21,7 +21,7 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, const NamedDecl *D, - llvm::StringRef Msg) { + StringRef Msg) { DelayedDiagnostic DD; DD.Kind = Deprecation; DD.Triggered = false; diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp index 95420a3..a643267 100644 --- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp @@ -73,7 +73,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { } } - assert(0 && "Didn't find this decl on its identifier's chain!"); + llvm_unreachable("Didn't find this decl on its identifier's chain!"); } bool diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index 59bc263..3e74dfc 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -1,4 +1,4 @@ -//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===// +//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file implements the JumpScopeChecker class, which is used to diagnose -// jumps that enter a VLA scope in an invalid way. +// jumps that enter a protected scope in an invalid way. // //===----------------------------------------------------------------------===// @@ -58,12 +58,12 @@ class JumpScopeChecker { : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} }; - llvm::SmallVector<GotoScope, 48> Scopes; + SmallVector<GotoScope, 48> Scopes; llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; - llvm::SmallVector<Stmt*, 16> Jumps; + SmallVector<Stmt*, 16> Jumps; - llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; - llvm::SmallVector<LabelDecl*, 4> IndirectJumpTargets; + SmallVector<IndirectGotoStmt*, 4> IndirectJumps; + SmallVector<LabelDecl*, 4> IndirectJumpTargets; public: JumpScopeChecker(Stmt *Body, Sema &S); private: @@ -76,8 +76,8 @@ private: void VerifyIndirectJumps(); void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, LabelDecl *Target, unsigned TargetScope); - void CheckJump(Stmt *From, Stmt *To, - SourceLocation DiagLoc, unsigned JumpDiag); + void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, + unsigned JumpDiag, unsigned JumpDiagWarning); unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; @@ -476,7 +476,8 @@ void JumpScopeChecker::VerifyJumps() { // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), - diag::err_goto_into_protected_scope); + diag::err_goto_into_protected_scope, + diag::warn_goto_into_protected_scope); continue; } @@ -484,7 +485,8 @@ void JumpScopeChecker::VerifyJumps() { if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { LabelDecl *Target = IGS->getConstantTarget(); CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), - diag::err_goto_into_protected_scope); + diag::err_goto_into_protected_scope, + diag::warn_goto_into_protected_scope); continue; } @@ -493,7 +495,7 @@ void JumpScopeChecker::VerifyJumps() { SC = SC->getNextSwitchCase()) { assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); CheckJump(SS, SC, SC->getLocStart(), - diag::err_switch_into_protected_scope); + diag::err_switch_into_protected_scope, 0); } } } @@ -532,10 +534,10 @@ void JumpScopeChecker::VerifyIndirectJumps() { // indirect goto. For most code bases, this substantially cuts // down on the number of jump sites we'll have to consider later. typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; - llvm::SmallVector<JumpScope, 32> JumpScopes; + SmallVector<JumpScope, 32> JumpScopes; { llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; - for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator + for (SmallVectorImpl<IndirectGotoStmt*>::iterator I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { IndirectGotoStmt *IG = *I; assert(LabelAndGotoScopes.count(IG) && @@ -554,7 +556,7 @@ void JumpScopeChecker::VerifyIndirectJumps() { // label whose address was taken somewhere in the function. // For most code bases, there will be only one such scope. llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; - for (llvm::SmallVectorImpl<LabelDecl*>::iterator + for (SmallVectorImpl<LabelDecl*>::iterator I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); I != E; ++I) { LabelDecl *TheLabel = *I; @@ -599,7 +601,7 @@ void JumpScopeChecker::VerifyIndirectJumps() { // Walk through all the jump sites, checking that they can trivially // reach this label scope. - for (llvm::SmallVectorImpl<JumpScope>::iterator + for (SmallVectorImpl<JumpScope>::iterator I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { unsigned Scope = I->first; @@ -660,10 +662,20 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, S.Diag(Scopes[I].Loc, Scopes[I].InDiag); } +/// Return true if a particular error+note combination must be downgraded +/// to a warning in Microsoft mode. +static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) +{ + return (JumpDiag == diag::err_goto_into_protected_scope && + (InDiagNote == diag::note_protected_by_variable_init || + InDiagNote == diag::note_protected_by_variable_nontriv_destructor)); +} + + /// CheckJump - Validate that the specified jump statement is valid: that it is /// jumping within or out of its current scope, not into a deeper one. -void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, - SourceLocation DiagLoc, unsigned JumpDiag) { +void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, + unsigned JumpDiagError, unsigned JumpDiagWarning) { assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); unsigned FromScope = LabelAndGotoScopes[From]; @@ -679,19 +691,30 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, if (CommonScope == ToScope) return; // Pull out (and reverse) any scopes we might need to diagnose skipping. - llvm::SmallVector<unsigned, 10> ToScopes; - for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) - if (Scopes[I].InDiag) - ToScopes.push_back(I); - - // If the only scopes present are cleanup scopes, we're okay. - if (ToScopes.empty()) return; + SmallVector<unsigned, 10> ToScopesError; + SmallVector<unsigned, 10> ToScopesWarning; + for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { + if (S.getLangOptions().MicrosoftMode && JumpDiagWarning != 0 && + IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) + ToScopesWarning.push_back(I); + else if (Scopes[I].InDiag) + ToScopesError.push_back(I); + } - S.Diag(DiagLoc, JumpDiag); + // Handle warnings. + if (!ToScopesWarning.empty()) { + S.Diag(DiagLoc, JumpDiagWarning); + for (unsigned i = 0, e = ToScopesWarning.size(); i != e; ++i) + S.Diag(Scopes[ToScopesWarning[i]].Loc, Scopes[ToScopesWarning[i]].InDiag); + } - // Emit diagnostics for whatever is left in ToScopes. - for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) - S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag); + // Handle errors. + if (!ToScopesError.empty()) { + S.Diag(DiagLoc, JumpDiagError); + // Emit diagnostics note for whatever is left in ToScopesError. + for (unsigned i = 0, e = ToScopesError.size(); i != e; ++i) + S.Diag(Scopes[ToScopesError[i]].Loc, Scopes[ToScopesError[i]].InDiag); + } } void Sema::DiagnoseInvalidJumps(Stmt *Body) { diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp new file mode 100644 index 0000000..8bd2213 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp @@ -0,0 +1,92 @@ +//===--- MultiInitializer.cpp - Initializer expression group ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MultiInitializer class, which can represent a list +// initializer or a parentheses-wrapped group of expressions in a C++ member +// initializer. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/MultiInitializer.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Sema.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +InitListExpr *MultiInitializer::getInitList() const { + return cast<InitListExpr>(InitListOrExpressions.get<Expr*>()); +} + +SourceLocation MultiInitializer::getStartLoc() const { + return isInitializerList() ? getInitList()->getLBraceLoc() : LParenLoc; +} + +SourceLocation MultiInitializer::getEndLoc() const { + return isInitializerList() ? getInitList()->getRBraceLoc() : RParenLoc; +} + +MultiInitializer::iterator MultiInitializer::begin() const { + return isInitializerList() ? getInitList()->getInits() : getExpressions(); +} + +MultiInitializer::iterator MultiInitializer::end() const { + if (isInitializerList()) { + InitListExpr *ILE = getInitList(); + return ILE->getInits() + ILE->getNumInits(); + } + return getExpressions() + NumInitializers; +} + +bool MultiInitializer::isTypeDependent() const { + if (isInitializerList()) + return getInitList()->isTypeDependent(); + for (iterator I = begin(), E = end(); I != E; ++I) { + if ((*I)->isTypeDependent()) + return true; + } + return false; +} + +bool MultiInitializer::DiagnoseUnexpandedParameterPack(Sema &SemaRef) const { + if (isInitializerList()) + return SemaRef.DiagnoseUnexpandedParameterPack(getInitList()); + for (iterator I = begin(), E = end(); I != E; ++I) { + if (SemaRef.DiagnoseUnexpandedParameterPack(*I)) + return true; + } + return false; +} + +Expr *MultiInitializer::CreateInitExpr(ASTContext &Ctx, QualType T) const { + if (isInitializerList()) + return InitListOrExpressions.get<Expr*>(); + + return new (Ctx) ParenListExpr(Ctx, LParenLoc, getExpressions(), + NumInitializers, RParenLoc, T); +} + +ExprResult MultiInitializer::PerformInit(Sema &SemaRef, + InitializedEntity Entity, + InitializationKind Kind) const { + Expr *Single; + Expr **Args; + unsigned NumArgs; + if (isInitializerList()) { + Single = InitListOrExpressions.get<Expr*>(); + Args = &Single; + NumArgs = 1; + } else { + Args = getExpressions(); + NumArgs = NumInitializers; + } + InitializationSequence InitSeq(SemaRef, Entity, Kind, Args, NumArgs); + return InitSeq.Perform(SemaRef, Entity, Kind, + MultiExprArg(SemaRef, Args, NumArgs), 0); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index fdf3bb3..533b21c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -34,6 +34,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; @@ -54,99 +55,54 @@ void FunctionScopeInfo::Clear() { BlockScopeInfo::~BlockScopeInfo() { } +PrintingPolicy Sema::getPrintingPolicy() const { + PrintingPolicy Policy = Context.getPrintingPolicy(); + Policy.Bool = getLangOptions().Bool; + if (!Policy.Bool) { + if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) { + Policy.Bool = BoolMacro->isObjectLike() && + BoolMacro->getNumTokens() == 1 && + BoolMacro->getReplacementToken(0).is(tok::kw__Bool); + } + } + + return Policy; +} + void Sema::ActOnTranslationUnitScope(Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); VAListTagName = PP.getIdentifierInfo("__va_list_tag"); - if (!Context.isInt128Installed() && // May be set by ASTReader. - PP.getTargetInfo().getPointerWidth(0) >= 64) { - TypeSourceInfo *TInfo; - - // Install [u]int128_t for 64-bit targets. - TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty); - PushOnScopeChains(TypedefDecl::Create(Context, CurContext, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("__int128_t"), - TInfo), TUScope); - - TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty); - PushOnScopeChains(TypedefDecl::Create(Context, CurContext, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("__uint128_t"), - TInfo), TUScope); - Context.setInt128Installed(); - } - - - if (!PP.getLangOptions().ObjC1) return; - - // Built-in ObjC types may already be set by ASTReader (hence isNull checks). - if (Context.getObjCSelType().isNull()) { - // Create the built-in typedef for 'SEL'. - QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); - TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT); - TypedefDecl *SelTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("SEL"), SelInfo); - PushOnScopeChains(SelTypedef, TUScope); - Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); - Context.ObjCSelRedefinitionType = Context.getObjCSelType(); - } - - // Synthesize "@class Protocol; - if (Context.getObjCProtoType().isNull()) { - ObjCInterfaceDecl *ProtocolDecl = - ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Protocol"), - SourceLocation(), true); - Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); - PushOnScopeChains(ProtocolDecl, TUScope, false); - } - // Create the built-in typedef for 'id'. - if (Context.getObjCIdType().isNull()) { - QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0); - T = Context.getObjCObjectPointerType(T); - TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T); - TypedefDecl *IdTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("id"), IdInfo); - PushOnScopeChains(IdTypedef, TUScope); - Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); - Context.ObjCIdRedefinitionType = Context.getObjCIdType(); - } - // Create the built-in typedef for 'Class'. - if (Context.getObjCClassType().isNull()) { - QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0); - T = Context.getObjCObjectPointerType(T); - TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T); - TypedefDecl *ClassTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("Class"), ClassInfo); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); - Context.ObjCClassRedefinitionType = Context.getObjCClassType(); - } + if (PP.getLangOptions().ObjC1) { + // Synthesize "@class Protocol; + if (Context.getObjCProtoType().isNull()) { + ObjCInterfaceDecl *ProtocolDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Protocol"), + SourceLocation(), true); + Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); + PushOnScopeChains(ProtocolDecl, TUScope, false); + } + } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()), LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter), - CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0), + CurContext(0), OriginalLexicalContext(0), + PackContext(0), MSStructPragmaOn(false), VisContext(0), ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), - CompleteTranslationUnit(CompleteTranslationUnit), + ObjCShouldCallSuperDealloc(false), + ObjCShouldCallSuperFinalize(false), + TUKind(TUKind), NumSFINAEErrors(0), SuppressAccessChecking(false), AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), @@ -181,6 +137,40 @@ void Sema::Initialize() { if (ExternalSemaSource *ExternalSema = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) ExternalSema->InitializeSema(*this); + + // Initialize predefined 128-bit integer types, if needed. + if (PP.getTargetInfo().getPointerWidth(0) >= 64) { + // If either of the 128-bit integer types are unavailable to name lookup, + // define them now. + DeclarationName Int128 = &Context.Idents.get("__int128_t"); + if (IdentifierResolver::begin(Int128) == IdentifierResolver::end()) + PushOnScopeChains(Context.getInt128Decl(), TUScope); + + DeclarationName UInt128 = &Context.Idents.get("__uint128_t"); + if (IdentifierResolver::begin(UInt128) == IdentifierResolver::end()) + PushOnScopeChains(Context.getUInt128Decl(), TUScope); + } + + + // Initialize predefined Objective-C types: + if (PP.getLangOptions().ObjC1) { + // If 'SEL' does not yet refer to any declarations, make it refer to the + // predefined 'SEL'. + DeclarationName SEL = &Context.Idents.get("SEL"); + if (IdentifierResolver::begin(SEL) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCSelDecl(), TUScope); + + // If 'id' does not yet refer to any declarations, make it refer to the + // predefined 'id'. + DeclarationName Id = &Context.Idents.get("id"); + if (IdentifierResolver::begin(Id) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCIdDecl(), TUScope); + + // Create the built-in typedef for 'Class'. + DeclarationName Class = &Context.Idents.get("Class"); + if (IdentifierResolver::begin(Class) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCClassDecl(), TUScope); + } } Sema::~Sema() { @@ -210,7 +200,7 @@ Sema::~Sema() { /// make the relevant declaration unavailable instead of erroring, do /// so and return true. bool Sema::makeUnavailableInSystemHeader(SourceLocation loc, - llvm::StringRef msg) { + StringRef msg) { // If we're not in a function, it's an error. FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext); if (!fn) return false; @@ -287,7 +277,9 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { switch (ScalarTy->getScalarTypeKind()) { case Type::STK_Bool: return CK_NoOp; - case Type::STK_Pointer: return CK_PointerToBoolean; + case Type::STK_CPointer: return CK_PointerToBoolean; + case Type::STK_BlockPointer: return CK_PointerToBoolean; + case Type::STK_ObjCObjectPointer: return CK_PointerToBoolean; case Type::STK_MemberPointer: return CK_MemberPointerToBoolean; case Type::STK_Integral: return CK_IntegralToBoolean; case Type::STK_Floating: return CK_FloatingToBoolean; @@ -297,12 +289,6 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { return CK_Invalid; } -ExprValueKind Sema::CastCategory(Expr *E) { - Expr::Classification Classification = E->Classify(Context); - return Classification.isRValue() ? VK_RValue : - (Classification.isLValue() ? VK_LValue : VK_XValue); -} - /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->isUsed()) @@ -358,7 +344,7 @@ static void checkUndefinedInternals(Sema &S) { if (S.UndefinedInternals.empty()) return; // Collect all the still-undefined entities with internal linkage. - llvm::SmallVector<UndefinedInternal, 16> undefined; + SmallVector<UndefinedInternal, 16> undefined; for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end(); i != e; ++i) { @@ -389,7 +375,7 @@ static void checkUndefinedInternals(Sema &S) { // the iteration order through an llvm::DenseMap. llvm::array_pod_sort(undefined.begin(), undefined.end()); - for (llvm::SmallVectorImpl<UndefinedInternal>::iterator + for (SmallVectorImpl<UndefinedInternal>::iterator i = undefined.begin(), e = undefined.end(); i != e; ++i) { NamedDecl *decl = i->decl; S.Diag(decl->getLocation(), diag::warn_undefined_internal) @@ -398,24 +384,41 @@ static void checkUndefinedInternals(Sema &S) { } } +void Sema::LoadExternalWeakUndeclaredIdentifiers() { + if (!ExternalSource) + return; + + SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs; + ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs); + for (unsigned I = 0, N = WeakIDs.size(); I != N; ++I) { + llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator Pos + = WeakUndeclaredIdentifiers.find(WeakIDs[I].first); + if (Pos != WeakUndeclaredIdentifiers.end()) + continue; + + WeakUndeclaredIdentifiers.insert(WeakIDs[I]); + } +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { - // At PCH writing, implicit instantiations and VTable handling info are - // stored and performed when the PCH is included. - if (CompleteTranslationUnit) { + // Only complete translation units define vtables and perform implicit + // instantiations. + if (TUKind == TU_Complete) { // If any dynamic classes have their key function defined within // this translation unit, then those vtables are considered "used" and must // be emitted. - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { - assert(!DynamicClasses[I]->isDependentType() && + for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource), + E = DynamicClasses.end(); + I != E; ++I) { + assert(!(*I)->isDependentType() && "Should not see dependent types here!"); - if (const CXXMethodDecl *KeyFunction - = Context.getKeyFunction(DynamicClasses[I])) { + if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) { const FunctionDecl *Definition = 0; if (KeyFunction->hasBody(Definition)) - MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); + MarkVTableUsed(Definition->getLocation(), *I, true); } } @@ -438,13 +441,15 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, + true), UnusedFileScopedDecls.end(), std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), UnusedFileScopedDecls.end()); - if (!CompleteTranslationUnit) { + if (TUKind == TU_Prefix) { + // Translation unit prefixes don't need any of the checking below. TUScope = 0; return; } @@ -452,6 +457,7 @@ void Sema::ActOnEndOfTranslationUnit() { // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. + LoadExternalWeakUndeclaredIdentifiers(); for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = WeakUndeclaredIdentifiers.begin(), E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { @@ -461,6 +467,40 @@ void Sema::ActOnEndOfTranslationUnit() { << I->first; } + if (TUKind == TU_Module) { + // Mark any macros from system headers (in /usr/include) as exported, along + // with our own Clang headers. + // FIXME: This is a gross hack to deal with the fact that system headers + // are #include'd in many places within module headers, but are not + // themselves modularized. This doesn't actually work, but it lets us + // focus on other issues for the moment. + for (Preprocessor::macro_iterator M = PP.macro_begin(false), + MEnd = PP.macro_end(false); + M != MEnd; ++M) { + if (M->second && + !M->second->isExported() && + !M->second->isBuiltinMacro()) { + SourceLocation Loc = M->second->getDefinitionLoc(); + if (SourceMgr.isInSystemHeader(Loc)) { + const FileEntry *File + = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc)); + if (File && + ((StringRef(File->getName()).find("lib/clang") + != StringRef::npos) || + (StringRef(File->getName()).find("usr/include") + != StringRef::npos) || + (StringRef(File->getName()).find("usr/local/include") + != StringRef::npos))) + M->second->setExportLocation(Loc); + } + } + } + + // Modules don't need any of the checking below. + TUScope = 0; + return; + } + // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class @@ -473,8 +513,12 @@ void Sema::ActOnEndOfTranslationUnit() { // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; - for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) { - VarDecl *VD = TentativeDefinitions[i]->getActingDefinition(); + for (TentativeDefinitionsType::iterator + T = TentativeDefinitions.begin(ExternalSource), + TEnd = TentativeDefinitions.end(); + T != TEnd; ++T) + { + VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second @@ -510,16 +554,19 @@ void Sema::ActOnEndOfTranslationUnit() { if (LangOpts.CPlusPlus0x && Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, SourceLocation()) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) CheckDelegatingCtorCycles(); // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { // Output warning for unused file scoped decls. - for (llvm::SmallVectorImpl<const DeclaratorDecl*>::iterator - I = UnusedFileScopedDecls.begin(), + for (UnusedFileScopedDeclsType::iterator + I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { + if (ShouldRemoveFromUnused(this, *I)) + continue; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) @@ -631,7 +678,7 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { // Make a copy of this suppressed diagnostic and store it with the // template-deduction information; FlushCounts(); - DiagnosticInfo DiagInfo(&SemaRef.Diags); + Diagnostic DiagInfo(&SemaRef.Diags); if (*Info) (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), @@ -646,6 +693,9 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } } + // Set up the context's printing policy based on our current state. + SemaRef.Context.setPrintingPolicy(SemaRef.getPrintingPolicy()); + // Emit the diagnostic. if (!this->Emit()) return; @@ -677,20 +727,20 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } -/// \brief Looks through the macro-instantiation chain for the given -/// location, looking for a macro instantiation with the given name. +/// \brief Looks through the macro-expansion chain for the given +/// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that -/// instantiation loc. -bool Sema::findMacroSpelling(SourceLocation &locref, llvm::StringRef name) { +/// expansion loc. +bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) { SourceLocation loc = locref; if (!loc.isMacroID()) return false; // There's no good way right now to look at the intermediate - // instantiations, so just jump to the instantiation location. - loc = getSourceManager().getInstantiationLoc(loc); + // expansions, so just jump to the expansion location. + loc = getSourceManager().getExpansionLoc(loc); // If that's written with the name, stop here. - llvm::SmallVector<char, 16> buffer; + SmallVector<char, 16> buffer; if (getPreprocessor().getSpelling(loc, buffer) == name) { locref = loc; return true; @@ -754,7 +804,7 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP, if (WP && D) AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr); else { - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = Scope->PossiblyUnreachableDiags.begin(), e = Scope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -790,10 +840,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) { } void ExternalSemaSource::ReadKnownNamespaces( - llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) { + SmallVectorImpl<NamespaceDecl *> &Namespaces) { } -void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { +void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); if (Loc.isValid()) { @@ -820,27 +870,38 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { /// \param ZeroArgCallReturnTy - If the expression can be turned into a call /// with no arguments, this parameter is set to the type returned by such a /// call; otherwise, it is set to an empty QualType. -/// \param NonTemplateOverloads - If the expression is an overloaded function +/// \param OverloadSet - If the expression is an overloaded function /// name, this parameter is populated with the decls of the various overloads. bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, - UnresolvedSetImpl &NonTemplateOverloads) { + UnresolvedSetImpl &OverloadSet) { ZeroArgCallReturnTy = QualType(); - NonTemplateOverloads.clear(); - if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) { + OverloadSet.clear(); + + if (E.getType() == Context.OverloadTy) { + OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E)); + const OverloadExpr *Overloads = FR.Expression; + for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { - // Our overload set may include TemplateDecls, which we'll ignore for our - // present purpose. - if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { - NonTemplateOverloads.addDecl(*it); + OverloadSet.addDecl(*it); + + // Check whether the function is a non-template which takes no + // arguments. + if (const FunctionDecl *OverloadDecl + = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) { if (OverloadDecl->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = OverloadDecl->getResultType(); } } + + // Ignore overloads that are pointer-to-member constants. + if (FR.HasFormOfMemberPointer) + return false; + return true; } - if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) { + if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) { if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { if (Fun->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = Fun->getResultType(); @@ -887,8 +948,8 @@ bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, /// -fshow-overloads=best, this is the location to attach to the note about too /// many candidates. Typically this will be the location of the original /// ill-formed expression. -void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, - const SourceLocation FinalNoteLoc) { +static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, + const SourceLocation FinalNoteLoc) { int ShownOverloads = 0; int SuppressedOverloads = 0; for (UnresolvedSetImpl::iterator It = Overloads.begin(), @@ -896,15 +957,86 @@ void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, // FIXME: Magic number for max shown overloads stolen from // OverloadCandidateSet::NoteCandidates. if (ShownOverloads >= 4 && - Diags.getShowOverloads() == Diagnostic::Ovl_Best) { + S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) { ++SuppressedOverloads; continue; } - Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(), - diag::note_member_ref_possible_intended_overload); + + NamedDecl *Fn = (*It)->getUnderlyingDecl(); + S.Diag(Fn->getLocStart(), diag::note_possible_target_of_call); ++ShownOverloads; } + if (SuppressedOverloads) - Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) - << SuppressedOverloads; + S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) + << SuppressedOverloads; +} + +static void notePlausibleOverloads(Sema &S, SourceLocation Loc, + const UnresolvedSetImpl &Overloads, + bool (*IsPlausibleResult)(QualType)) { + if (!IsPlausibleResult) + return noteOverloads(S, Overloads, Loc); + + UnresolvedSet<2> PlausibleOverloads; + for (OverloadExpr::decls_iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + QualType OverloadResultTy = OverloadDecl->getResultType(); + if (IsPlausibleResult(OverloadResultTy)) + PlausibleOverloads.addDecl(It.getDecl()); + } + noteOverloads(S, PlausibleOverloads, Loc); +} + +/// Determine whether the given expression can be called by just +/// putting parentheses after it. Notably, expressions with unary +/// operators can't be because the unary operator will start parsing +/// outside the call. +static bool IsCallableWithAppend(Expr *E) { + E = E->IgnoreImplicit(); + return (!isa<CStyleCastExpr>(E) && + !isa<UnaryOperator>(E) && + !isa<BinaryOperator>(E) && + !isa<CXXOperatorCallExpr>(E)); +} + +bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, + bool ForceComplain, + bool (*IsPlausibleResult)(QualType)) { + SourceLocation Loc = E.get()->getExprLoc(); + SourceRange Range = E.get()->getSourceRange(); + + QualType ZeroArgCallTy; + UnresolvedSet<4> Overloads; + if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) && + !ZeroArgCallTy.isNull() && + (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) { + // At this point, we know E is potentially callable with 0 + // arguments and that it returns something of a reasonable type, + // so we can emit a fixit and carry on pretending that E was + // actually a CallExpr. + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(Range.getEnd()); + Diag(Loc, PD) + << /*zero-arg*/ 1 << Range + << (IsCallableWithAppend(E.get()) + ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") + : FixItHint()); + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + + // FIXME: Try this before emitting the fixit, and suppress diagnostics + // while doing so. + E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, + MultiExprArg(*this, 0, 0), + ParenInsertionLoc.getLocWithOffset(1)); + return true; + } + + if (!ForceComplain) return false; + + Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + E = ExprError(); + return true; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index a26737e..6cd9230 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -103,7 +103,11 @@ struct EffectiveContext { } else if (isa<FunctionDecl>(DC)) { FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); Functions.push_back(Function); - DC = Function->getDeclContext(); + + if (Function->getFriendObjectKind()) + DC = Function->getLexicalDeclContext(); + else + DC = Function->getDeclContext(); } else if (DC->isFileContext()) { break; } else { @@ -126,11 +130,11 @@ struct EffectiveContext { return Inner; } - typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; + typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; DeclContext *Inner; - llvm::SmallVector<FunctionDecl*, 4> Functions; - llvm::SmallVector<CXXRecordDecl*, 4> Records; + SmallVector<FunctionDecl*, 4> Functions; + SmallVector<CXXRecordDecl*, 4> Records; bool Dependent; }; @@ -146,10 +150,8 @@ struct AccessTarget : public AccessedEntity { MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, - QualType BaseObjectType, - bool IsUsingDecl = false) - : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType), - IsUsingDeclaration(IsUsingDecl) { + QualType BaseObjectType) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { initialize(); } @@ -218,7 +220,6 @@ private: DeclaringClass = DeclaringClass->getCanonicalDecl(); } - bool IsUsingDeclaration : 1; bool HasInstanceContext : 1; mutable bool CalculatedInstanceContext : 1; mutable const CXXRecordDecl *InstanceContext; @@ -260,7 +261,7 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, return AR_dependent; AccessResult OnFailure = AR_inaccessible; - llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack + SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack while (true) { for (CXXRecordDecl::base_class_const_iterator @@ -421,7 +422,7 @@ static AccessResult MatchesFriend(Sema &S, // Check whether the friend is the template of a class in the // context chain. - for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + for (SmallVectorImpl<CXXRecordDecl*>::const_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { CXXRecordDecl *Record = *I; @@ -472,7 +473,7 @@ static AccessResult MatchesFriend(Sema &S, FunctionDecl *Friend) { AccessResult OnFailure = AR_inaccessible; - for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + for (SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { if (Friend == *I) return AR_accessible; @@ -493,7 +494,7 @@ static AccessResult MatchesFriend(Sema &S, AccessResult OnFailure = AR_inaccessible; - for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + for (SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); @@ -584,7 +585,7 @@ struct ProtectedFriendContext { bool EverDependent; /// The path down to the current base class. - llvm::SmallVector<const CXXRecordDecl*, 20> CurPath; + SmallVector<const CXXRecordDecl*, 20> CurPath; ProtectedFriendContext(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *InstanceContext, @@ -1273,7 +1274,7 @@ static AccessResult CheckEffectiveAccess(Sema &S, AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); - if (S.getLangOptions().Microsoft && + if (S.getLangOptions().MicrosoftMode && IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) return AR_accessible; @@ -1554,8 +1555,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, Found.getAccess() == AS_public) return AR_accessible; - const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); - assert(RT && "found member operator but object expr not of record type"); + const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, @@ -1638,13 +1638,34 @@ void Sema::CheckLookupAccess(const LookupResult &R) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), - R.getBaseObjectType(), R.isUsingDeclaration()); + R.getBaseObjectType()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); } } } +/// Checks access to Decl from the given class. The check will take access +/// specifiers into account, but no member access expressions and such. +/// +/// \param Decl the declaration to check if it can be accessed +/// \param Class the class/context from which to start the search +/// \return true if the Decl is accessible from the Class, false otherwise. +bool Sema::IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *Class) { + if (!Class || !Decl->isCXXClassMember()) + return true; + + QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); + AccessTarget Entity(Context, AccessedEntity::Member, Class, + DeclAccessPair::make(Decl, Decl->getAccess()), + qType); + if (Entity.getAccess() == AS_public) + return true; + + EffectiveContext EC(CurContext); + return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; +} + void Sema::ActOnStartSuppressingAccessChecks() { assert(!SuppressAccessChecking && "Tried to start access check suppression when already started."); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 53dd297..77410db 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -189,7 +189,7 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, } void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, - ExprTy *alignment, SourceLocation PragmaLoc, + Expr *alignment, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { Expr *Alignment = static_cast<Expr *>(alignment); @@ -265,7 +265,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, break; default: - assert(0 && "Invalid #pragma pack kind."); + llvm_unreachable("Invalid #pragma pack kind."); } } @@ -300,6 +300,18 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context)); } +void Sema::AddCFAuditedAttribute(Decl *D) { + SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc(); + if (!Loc.isValid()) return; + + // Don't add a redundant or conflicting attribute. + if (D->hasAttr<CFAuditedTransferAttr>() || + D->hasAttr<CFUnknownTransferAttr>()) + return; + + D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context)); +} + typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack; enum { NoVisibility = (unsigned) -1 }; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index 5f8c9c6..360a040 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -137,8 +137,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - assert(false && "Dependent nested-name-specifier has no DeclContext"); - break; + llvm_unreachable("Dependent nested-name-specifier has no DeclContext"); case NestedNameSpecifier::Namespace: return NNS->getAsNamespace(); @@ -238,7 +237,7 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // until we see a definition, so awkwardly pull out this special // case. if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) { - if (!enumType->getDecl()->isDefinition()) { + if (!enumType->getDecl()->isCompleteDefinition()) { Diag(loc, diag::err_incomplete_nested_name_spec) << type << SS.getRange(); SS.SetInvalid(SS.getRange()); @@ -615,6 +614,31 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, LookupName(Found, S); } + // In Microsoft mode, if we are within a templated function and we can't + // resolve Identifier, then extend the SS with Identifier. This will have + // the effect of resolving Identifier during template instantiation. + // The goal is to be able to resolve a function call whose + // nested-name-specifier is located inside a dependent base class. + // Example: + // + // class C { + // public: + // static void foo2() { } + // }; + // template <class T> class A { public: typedef C D; }; + // + // template <class T> class B : public A<T> { + // public: + // void foo() { D::foo2(); } + // }; + if (getLangOptions().MicrosoftExt) { + DeclContext *DC = LookupCtx ? LookupCtx : CurContext; + if (DC->isDependentContext() && DC->isFunctionOrMethod()) { + SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + return false; + } + } + unsigned DiagID; if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index d053d5a..8bd9351 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp @@ -1,4 +1,4 @@ -//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===// +//===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,17 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for C++ named casts. +// This file implements semantic analysis for cast expressions, including +// 1) C-style casts like '(int) x' +// 2) C++ functional casts like 'int(x)' +// 3) C++ named casts like 'static_cast<int>(x)' // //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Initialization.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/Basic/PartialDiagnostic.h" @@ -39,29 +43,83 @@ enum CastType { CT_Functional ///< Type(expr) }; +namespace { + struct CastOperation { + CastOperation(Sema &S, QualType destType, ExprResult src) + : Self(S), SrcExpr(src), DestType(destType), + ResultType(destType.getNonLValueExprType(S.Context)), + ValueKind(Expr::getValueKindForType(destType)), + Kind(CK_Dependent) { + + if (const BuiltinType *placeholder = + src.get()->getType()->getAsPlaceholderType()) { + PlaceholderKind = placeholder->getKind(); + } else { + PlaceholderKind = (BuiltinType::Kind) 0; + } + } + + Sema &Self; + ExprResult SrcExpr; + QualType DestType; + QualType ResultType; + ExprValueKind ValueKind; + CastKind Kind; + BuiltinType::Kind PlaceholderKind; + CXXCastPath BasePath; + SourceRange OpRange; + SourceRange DestRange; + // Top-level semantics-checking routines. + void CheckConstCast(); + void CheckReinterpretCast(); + void CheckStaticCast(); + void CheckDynamicCast(); + void CheckCXXCStyleCast(bool FunctionalCast); + void CheckCStyleCast(); -static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange); -static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind); -static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - CastKind &Kind, - CXXCastPath &BasePath); -static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind, - CXXCastPath &BasePath); + // Internal convenience methods. + + /// Try to handle the given placeholder expression kind. Return + /// true if the source expression has the appropriate placeholder + /// kind. A placeholder can only be claimed once. + bool claimPlaceholder(BuiltinType::Kind K) { + if (PlaceholderKind != K) return false; + + PlaceholderKind = (BuiltinType::Kind) 0; + return true; + } + + bool isPlaceholder() const { + return PlaceholderKind != 0; + } + bool isPlaceholder(BuiltinType::Kind K) const { + return PlaceholderKind == K; + } + + void checkCastAlign() { + Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); + } + + void checkObjCARCConversion(Sema::CheckedConversionKind CCK) { + Expr *src = SrcExpr.get(); + Self.CheckObjCARCConversion(OpRange, DestType, src, CCK); + SrcExpr = src; + } + + /// Check for and handle non-overload placeholder expressions. + void checkNonOverloadPlaceholders() { + if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload)) + return; + + SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + PlaceholderKind = (BuiltinType::Kind) 0; + } + }; +} static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, bool CheckCVR, bool CheckObjCLifetime); @@ -162,70 +220,61 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, ExprResult Ex = Owned(E); QualType DestType = DestTInfo->getType(); - SourceRange OpRange(OpLoc, Parens.getEnd()); - SourceRange DestRange = AngleBrackets; - // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent(); - ExprValueKind VK = VK_RValue; - if (TypeDependent) - VK = Expr::getValueKindForType(DestType); + CastOperation Op(*this, DestType, E); + Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); + Op.DestRange = AngleBrackets; switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: if (!TypeDependent) { - CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange); - if (Ex.isInvalid()) + Op.CheckConstCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXConstCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Ex.take(), DestTInfo, OpLoc, + return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.SrcExpr.take(), DestTInfo, OpLoc, Parens.getEnd())); case tok::kw_dynamic_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange, - Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckDynamicCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXDynamicCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, DestTInfo, - OpLoc, Parens.getEnd())); + return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, + Op.SrcExpr.take(), &Op.BasePath, + DestTInfo, OpLoc, Parens.getEnd())); } case tok::kw_reinterpret_cast: { - CastKind Kind = CK_Dependent; if (!TypeDependent) { - CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind); - if (Ex.isInvalid()) + Op.CheckReinterpretCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXReinterpretCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), 0, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, + Op.SrcExpr.take(), 0, + DestTInfo, OpLoc, + Parens.getEnd())); } case tok::kw_static_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckStaticCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXStaticCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, DestTInfo, OpLoc, + Parens.getEnd())); } } @@ -410,7 +459,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); - llvm::SmallVector<Qualifiers, 8> cv1, cv2; + SmallVector<Qualifiers, 8> cv1, cv2; // Find the qualifiers. We only care about cvr-qualifiers for the // purpose of this check, because other qualifiers (address spaces, @@ -442,7 +491,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, QualType SrcConstruct = Self.Context.VoidTy; QualType DestConstruct = Self.Context.VoidTy; ASTContext &Context = Self.Context; - for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), + for (SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { SrcConstruct @@ -461,13 +510,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. -static void -CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind, - CXXCastPath &BasePath) { - QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType(); - DestType = Self.Context.getCanonicalType(DestType); +void CastOperation::CheckDynamicCast() { + QualType OrigSrcType = SrcExpr.get()->getType(); + QualType DestType = Self.Context.getCanonicalType(this->DestType); // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, // or "pointer to cv void". @@ -479,12 +524,9 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, DestPointee = DestPointer->getPointeeType(); } else if ((DestReference = DestType->getAs<ReferenceType>())) { DestPointee = DestReference->getPointeeType(); - VK = isa<LValueReferenceType>(DestReference) ? VK_LValue - : isa<RValueReferenceType>(DestReference) ? VK_XValue - : VK_RValue; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) - << OrigDestType << DestRange; + << this->DestType << DestRange; return; } @@ -519,7 +561,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else if (DestReference->isLValueReferenceType()) { if (!SrcExpr.get()->isLValue()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; } SrcPointee = SrcType; } else { @@ -547,7 +589,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; return; } @@ -595,11 +637,8 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// like this: /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); -void -CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, - const SourceRange &OpRange, const SourceRange &DestRange) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckConstCast() { + if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -617,12 +656,8 @@ CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code /// like this: /// char *bytes = reinterpret_cast\<char*\>(int_ptr); -void -CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckReinterpretCast() { + if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -647,10 +682,7 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); + checkObjCARCConversion(Sema::CCK_OtherCast); } } @@ -658,36 +690,34 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. -void -CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - CastKind &Kind, CXXCastPath &BasePath) { +void CastOperation::CheckStaticCast() { + if (isPlaceholder()) { + checkNonOverloadPlaceholders(); + if (SrcExpr.isInvalid()) + return; + } + // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { - SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { - ExprResult SingleFunctionExpression = - Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), + Kind = CK_ToVoid; + + if (claimPlaceholder(BuiltinType::Overload)) { + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr, false, // Decay Function to ptr true, // Complain OpRange, DestType, diag::err_bad_static_cast_overload); - if (SingleFunctionExpression.isUsable()) - { - SrcExpr = SingleFunctionExpression; - Kind = CK_ToVoid; - } + if (SrcExpr.isInvalid()) + return; } - else - Kind = CK_ToVoid; + + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); return; } - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue && !DestType->isRecordType()) { + if (ValueKind == VK_RValue && !DestType->isRecordType() && + !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -711,16 +741,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } } else if (tcr == TC_Success) { if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); - if (Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); - } + checkCastAlign(); + if (Self.getLangOptions().ObjCAutoRefCount) + checkObjCARCConversion(Sema::CCK_OtherCast); + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if @@ -815,11 +841,12 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // The same goes for reverse floating point promotion/conversion and // floating-integral conversions. Again, only floating->enum is relevant. if (DestType->isEnumeralType()) { - if (SrcType->isComplexType() || SrcType->isVectorType()) { - // Fall through - these cannot be converted. - } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { + if (SrcType->isIntegralOrEnumerationType()) { Kind = CK_IntegralCast; return TC_Success; + } else if (SrcType->isRealFloatingType()) { + Kind = CK_FloatingToIntegral; + return TC_Success; } } @@ -870,7 +897,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, else if (DestType->isObjCObjectPointerType()) { // allow both c-style cast and static_cast of objective-c pointers as // they are pervasive. - Kind = CK_AnyPointerToObjCPointerCast; + Kind = CK_CPointerToObjCPointerCast; return TC_Success; } else if (CStyle && DestType->isBlockPointerType()) { @@ -1373,7 +1400,7 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, diag::warn_undefined_reinterpret_cast; if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) == - Diagnostic::Ignored) { + DiagnosticsEngine::Ignored) { return; } @@ -1430,17 +1457,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Is the source an overloaded name? (i.e. &foo) // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... if (SrcType == Self.Context.OverloadTy) { - // ... unless foo<int> resolves to an lvalue unambiguously - ExprResult SingleFunctionExpr = - Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), + // ... unless foo<int> resolves to an lvalue unambiguously. + // TODO: what if this fails because of DiagnoseUseOfDecl or something + // like it? + ExprResult SingleFunctionExpr = SrcExpr; + if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( + SingleFunctionExpr, Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr - ); - if (SingleFunctionExpr.isUsable()) { + ) && SingleFunctionExpr.isUsable()) { SrcExpr = move(SingleFunctionExpr); SrcType = SrcExpr.get()->getType(); - } - else + } else { return TC_NotApplicable; + } } if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { @@ -1592,7 +1621,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // integral type size doesn't matter. if ((Self.Context.getTypeSize(SrcType) > Self.Context.getTypeSize(DestType)) && - !Self.getLangOptions().Microsoft) { + !Self.getLangOptions().MicrosoftExt) { msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } @@ -1629,16 +1658,28 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, (DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType())) return TC_NotApplicable; + if (IsLValueCast) { + Kind = CK_LValueBitCast; + } else if (DestType->isObjCObjectPointerType()) { + Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); + } else if (DestType->isBlockPointerType()) { + if (!SrcType->isBlockPointerType()) { + Kind = CK_AnyPointerToBlockPointerCast; + } else { + Kind = CK_BitCast; + } + } else { + Kind = CK_BitCast; + } + // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; return TC_Success; } // Not casting away constness, so the only remaining check is for compatible // pointer categories. - Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { @@ -1673,65 +1714,64 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Success; } -ExprResult -Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, - Expr *CastExpr, CastKind &Kind, - CXXCastPath &BasePath, - bool FunctionalStyle) { +void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) { + // Handle placeholders. + if (isPlaceholder()) { + // C-style casts can resolve __unknown_any types. + if (claimPlaceholder(BuiltinType::UnknownAny)) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + return; + } + + checkNonOverloadPlaceholders(); + if (SrcExpr.isInvalid()) + return; + } + + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. - // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - if (CastTy->isVoidType()) { + if (DestType->isVoidType()) { Kind = CK_ToVoid; - ExprResult CastExprRes = IgnoredValueConversions(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); - - if (CastExpr->getType() == Context.BoundMemberTy) - return CheckPlaceholderExpr(CastExpr); // will always fail - - if (CastExpr->getType() == Context.OverloadTy) { - ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization( - CastExpr, /* Decay Function to ptr */ false, - /* Complain */ true, R, CastTy, + if (claimPlaceholder(BuiltinType::Overload)) { + Self.ResolveAndFixSingleFunctionTemplateSpecialization( + SrcExpr, /* Decay Function to ptr */ false, + /* Complain */ true, DestRange, DestType, diag::err_bad_cstyle_cast_overload); - if (SingleFunctionExpr.isInvalid()) - return ExprError(); - CastExpr = SingleFunctionExpr.take(); + if (SrcExpr.isInvalid()) + return; } - assert(!CastExpr->getType()->isPlaceholderType()); + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; - return Owned(CastExpr); + return; } - // Make sure we determine the value kind before we bail out for - // dependent types. - VK = Expr::getValueKindForType(CastTy); - // If the type is dependent, we won't do any other semantic analysis now. - if (CastTy->isDependentType() || CastExpr->isTypeDependent()) { - Kind = CK_Dependent; - return Owned(CastExpr); + if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) { + assert(Kind == CK_Dependent); + return; } - if (VK == VK_RValue && !CastTy->isRecordType()) { - ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + if (ValueKind == VK_RValue && !DestType->isRecordType() && + !isPlaceholder(BuiltinType::Overload)) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; } // AltiVec vector initialization with a single literal. - if (const VectorType *vecTy = CastTy->getAs<VectorType>()) + if (const VectorType *vecTy = DestType->getAs<VectorType>()) if (vecTy->getVectorKind() == VectorType::AltiVecVector - && (CastExpr->getType()->isIntegerType() - || CastExpr->getType()->isFloatingType())) { + && (SrcExpr.get()->getType()->isIntegerType() + || SrcExpr.get()->getType()->isFloatingType())) { Kind = CK_VectorSplat; - return Owned(CastExpr); + return; } // C++ [expr.cast]p5: The conversions performed by @@ -1746,8 +1786,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... unsigned msg = diag::err_bad_cxx_cast_generic; - TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, - msg); + TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType, + /*CStyle*/true, msg); if (tcr == TC_Success) Kind = CK_NoOp; @@ -1756,47 +1796,274 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - ExprResult CastExprRes = Owned(CastExpr); - tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind, - BasePath); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, + msg, Kind, BasePath); + if (SrcExpr.isInvalid()) + return; + if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. - CastExprRes = Owned(CastExpr); - tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, - msg, Kind); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, + OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return; } } - if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success) - CheckObjCARCConversion(R, CastTy, CastExpr, CCK); + if (Self.getLangOptions().ObjCAutoRefCount && tcr == TC_Success) + checkObjCARCConversion(CCK); if (tcr != TC_Success && msg != 0) { - if (CastExpr->getType() == Context.OverloadTy) { + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, - CastTy, - /* Complain */ true, + FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), + DestType, + /*Complain*/ true, Found); assert(!Fn && "cast failed but able to resolve overload expression!!"); (void)Fn; } else { - diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), - R, CastExpr, CastTy); + diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), + OpRange, SrcExpr.get(), DestType); } + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - CheckCastAlign(CastExpr, CastTy, R); + // Clear out SrcExpr if there was a fatal error. if (tcr != TC_Success) + SrcExpr = ExprError(); +} + +/// Check the semantics of a C-style cast operation, in C. +void CastOperation::CheckCStyleCast() { + assert(!Self.getLangOptions().CPlusPlus); + + // Handle placeholders. + if (isPlaceholder()) { + // C-style casts can resolve __unknown_any types. + if (claimPlaceholder(BuiltinType::UnknownAny)) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + return; + } + + // We allow overloads in C, but we don't allow them to be resolved + // by anything except calls. + SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + } + + assert(!isPlaceholder()); + + // C99 6.5.4p2: the cast type needs to be void or scalar and the expression + // type needs to be scalar. + if (DestType->isVoidType()) { + // We don't necessarily do lvalue-to-rvalue conversions on this. + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + + // Cast to void allows any expr type. + Kind = CK_ToVoid; + return; + } + + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + QualType SrcType = SrcExpr.get()->getType(); + + if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + diag::err_typecheck_cast_to_incomplete)) { + SrcExpr = ExprError(); + return; + } + + if (!DestType->isScalarType() && !DestType->isVectorType()) { + const RecordType *DestRecordTy = DestType->getAs<RecordType>(); + + if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){ + // GCC struct/union extension: allow cast to self. + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar) + << DestType << SrcExpr.get()->getSourceRange(); + Kind = CK_NoOp; + return; + } + + // GCC's cast to union extension. + if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) { + RecordDecl *RD = DestRecordTy->getDecl(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(), FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) && + !Field->isUnnamedBitfield()) { + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) + << SrcExpr.get()->getSourceRange(); + break; + } + } + if (Field == FieldEnd) { + Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + Kind = CK_ToUnion; + return; + } + + // Reject any other conversions to non-scalar types. + Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar) + << DestType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + + // The type we're casting to is known to be a scalar or vector. + + // Require the operand to be a scalar or vector. + if (!SrcType->isScalarType() && !SrcType->isVectorType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::err_typecheck_expect_scalar_operand) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + + if (DestType->isExtVectorType()) { + SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.take(), Kind); + return; + } + + if (const VectorType *DestVecTy = DestType->getAs<VectorType>()) { + if (DestVecTy->getVectorKind() == VectorType::AltiVecVector && + (SrcType->isIntegerType() || SrcType->isFloatingType())) { + Kind = CK_VectorSplat; + } else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) { + SrcExpr = ExprError(); + } + return; + } + + if (SrcType->isVectorType()) { + if (Self.CheckVectorCast(OpRange, SrcType, DestType, Kind)) + SrcExpr = ExprError(); + return; + } + + // The source and target types are both scalars, i.e. + // - arithmetic types (fundamental, enum, and complex) + // - all kinds of pointers + // Note that member pointers were filtered out with C++, above. + + if (isa<ObjCSelectorExpr>(SrcExpr.get())) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_selector_expr); + SrcExpr = ExprError(); + return; + } + + // If either type is a pointer, the other type has to be either an + // integer or a pointer. + if (!DestType->isArithmeticType()) { + if (!SrcType->isIntegralType(Self.Context) && SrcType->isArithmeticType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::err_cast_pointer_from_non_pointer_int) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } else if (!SrcType->isArithmeticType()) { + if (!DestType->isIntegralType(Self.Context) && + DestType->isArithmeticType()) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_cast_pointer_to_non_pointer_int) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + + // ARC imposes extra restrictions on casts. + if (Self.getLangOptions().ObjCAutoRefCount) { + checkObjCARCConversion(Sema::CCK_CStyleCast); + if (SrcExpr.isInvalid()) + return; + + if (const PointerType *CastPtr = DestType->getAs<PointerType>()) { + if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) { + Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); + Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); + if (CastPtr->getPointeeType()->isObjCLifetimeType() && + ExprPtr->getPointeeType()->isObjCLifetimeType() && + !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_typecheck_incompatible_ownership) + << SrcType << DestType << Sema::AA_Casting + << SrcExpr.get()->getSourceRange(); + return; + } + } + } + else if (!Self.CheckObjCARCUnavailableWeakConversion(DestType, SrcType)) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_arc_convesion_of_weak_unavailable) + << 1 << SrcType << DestType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + + Kind = Self.PrepareScalarCast(SrcExpr, DestType); + if (SrcExpr.isInvalid()) + return; + + if (Kind == CK_BitCast) + checkCastAlign(); +} + +ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, + TypeSourceInfo *CastTypeInfo, + SourceLocation RPLoc, + Expr *CastExpr) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd()); + + if (getLangOptions().CPlusPlus) { + Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false); + } else { + Op.CheckCStyleCast(); + } + + if (Op.SrcExpr.isInvalid()) + return ExprError(); + + return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), &Op.BasePath, + CastTypeInfo, LPLoc, RPLoc)); +} + +ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, + SourceLocation LPLoc, + Expr *CastExpr, + SourceLocation RPLoc) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd()); + + Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true); + if (Op.SrcExpr.isInvalid()) return ExprError(); - return Owned(CastExpr); + return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, CastTypeInfo, + Op.DestRange.getBegin(), + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, RPLoc)); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index b032b8a..eaf7bfa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -12,8 +12,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Sema/Initialization.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Analysis/Analyses/FormatString.h" #include "clang/AST/ASTContext.h" @@ -87,6 +89,19 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { << call->getArg(1)->getSourceRange(); } +/// CheckBuiltinAnnotationString - Checks that string argument to the builtin +/// annotation is a non wide string literal. +static bool CheckBuiltinAnnotationString(Sema &S, Expr *Arg) { + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); + if (!Literal || !Literal->isAscii()) { + S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant) + << Arg->getSourceRange(); + return true; + } + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); @@ -183,12 +198,38 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_lock_release: case Builtin::BI__sync_swap: return SemaBuiltinAtomicOverloaded(move(TheCallResult)); + case Builtin::BI__atomic_load: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load); + case Builtin::BI__atomic_store: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store); + case Builtin::BI__atomic_exchange: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg); + case Builtin::BI__atomic_compare_exchange_strong: + return SemaAtomicOpsOverloaded(move(TheCallResult), + AtomicExpr::CmpXchgStrong); + case Builtin::BI__atomic_compare_exchange_weak: + return SemaAtomicOpsOverloaded(move(TheCallResult), + AtomicExpr::CmpXchgWeak); + case Builtin::BI__atomic_fetch_add: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add); + case Builtin::BI__atomic_fetch_sub: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub); + case Builtin::BI__atomic_fetch_and: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And); + case Builtin::BI__atomic_fetch_or: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or); + case Builtin::BI__atomic_fetch_xor: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor); + case Builtin::BI__builtin_annotation: + if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1))) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those // of the arch we are compiling for. if (BuiltinID >= Builtin::FirstTSBuiltin) { - switch (Context.Target.getTriple().getArch()) { + switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) @@ -319,7 +360,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } - // Memset/memcpy/memmove handling + // Builtin handling int CMF = -1; switch (FDecl->getBuiltinID()) { case Builtin::BI__builtin_memset: @@ -339,7 +380,40 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BImemmove: CMF = CMF_Memmove; break; + + case Builtin::BIstrlcpy: + case Builtin::BIstrlcat: + CheckStrlcpycatArguments(TheCall, FnInfo); + break; + case Builtin::BI__builtin_memcmp: + CMF = CMF_Memcmp; + break; + + case Builtin::BI__builtin_strncpy: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BIstrncpy: + CMF = CMF_Strncpy; + break; + + case Builtin::BI__builtin_strncmp: + CMF = CMF_Strncmp; + break; + + case Builtin::BI__builtin_strncasecmp: + CMF = CMF_Strncasecmp; + break; + + case Builtin::BI__builtin_strncat: + case Builtin::BIstrncat: + CMF = CMF_Strncat; + break; + + case Builtin::BI__builtin_strndup: + case Builtin::BIstrndup: + CMF = CMF_Strndup; + break; + default: if (FDecl->getLinkage() == ExternalLinkage && (!getLangOptions().CPlusPlus || FDecl->isExternC())) { @@ -349,12 +423,25 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { CMF = CMF_Memcpy; else if (FnInfo->isStr("memmove")) CMF = CMF_Memmove; + else if (FnInfo->isStr("memcmp")) + CMF = CMF_Memcmp; + else if (FnInfo->isStr("strncpy")) + CMF = CMF_Strncpy; + else if (FnInfo->isStr("strncmp")) + CMF = CMF_Strncmp; + else if (FnInfo->isStr("strncasecmp")) + CMF = CMF_Strncasecmp; + else if (FnInfo->isStr("strncat")) + CMF = CMF_Strncat; + else if (FnInfo->isStr("strndup")) + CMF = CMF_Strndup; } break; } + // Memset/memcpy/memmove handling if (CMF != -1) - CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo); + CheckMemaccessArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo); return false; } @@ -384,6 +471,170 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { return false; } +ExprResult +Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { + CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); + DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + + // All these operations take one of the following four forms: + // T __atomic_load(_Atomic(T)*, int) (loads) + // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub) + // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int) + // (cmpxchg) + // T __atomic_exchange(_Atomic(T)*, T, int) (everything else) + // where T is an appropriate type, and the int paremeterss are for orderings. + unsigned NumVals = 1; + unsigned NumOrders = 1; + if (Op == AtomicExpr::Load) { + NumVals = 0; + } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) { + NumVals = 2; + NumOrders = 2; + } + + if (TheCall->getNumArgs() < NumVals+NumOrders+1) { + Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) { + Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } + + // Inspect the first argument of the atomic operation. This should always be + // a pointer to an _Atomic type. + Expr *Ptr = TheCall->getArg(0); + Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get(); + const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); + if (!pointerType) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + QualType AtomTy = pointerType->getPointeeType(); + if (!AtomTy->isAtomicType()) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + QualType ValType = AtomTy->getAs<AtomicType>()->getValueType(); + + if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) && + !ValType->isIntegerType() && !ValType->isPointerType()) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + if (!ValType->isIntegerType() && + (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){ + Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + switch (ValType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + // okay + break; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Autoreleasing: + Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) + << ValType << Ptr->getSourceRange(); + return ExprError(); + } + + QualType ResultType = ValType; + if (Op == AtomicExpr::Store) + ResultType = Context.VoidTy; + else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) + ResultType = Context.BoolTy; + + // The first argument --- the pointer --- has a fixed type; we + // deduce the types of the rest of the arguments accordingly. Walk + // the remaining arguments, converting them to the deduced value type. + for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) { + ExprResult Arg = TheCall->getArg(i); + QualType Ty; + if (i < NumVals+1) { + // The second argument to a cmpxchg is a pointer to the data which will + // be exchanged. The second argument to a pointer add/subtract is the + // amount to add/subtract, which must be a ptrdiff_t. The third + // argument to a cmpxchg and the second argument in all other cases + // is the type of the value. + if (i == 1 && (Op == AtomicExpr::CmpXchgWeak || + Op == AtomicExpr::CmpXchgStrong)) + Ty = Context.getPointerType(ValType.getUnqualifiedType()); + else if (!ValType->isIntegerType() && + (Op == AtomicExpr::Add || Op == AtomicExpr::Sub)) + Ty = Context.getPointerDiffType(); + else + Ty = ValType; + } else { + // The order(s) are always converted to int. + Ty = Context.IntTy; + } + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, Ty, false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + } + + SmallVector<Expr*, 5> SubExprs; + SubExprs.push_back(Ptr); + if (Op == AtomicExpr::Load) { + SubExprs.push_back(TheCall->getArg(1)); // Order + } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) { + SubExprs.push_back(TheCall->getArg(2)); // Order + SubExprs.push_back(TheCall->getArg(1)); // Val1 + } else { + SubExprs.push_back(TheCall->getArg(3)); // Order + SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(TheCall->getArg(4)); // OrderFail + } + + return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), + SubExprs.data(), SubExprs.size(), + ResultType, Op, + TheCall->getRParenLoc())); +} + + +/// checkBuiltinArgument - Given a call to a builtin function, perform +/// normal type-checking on the given argument, updating the call in +/// place. This is useful when a builtin function requires custom +/// type-checking for some of its arguments but not necessarily all of +/// them. +/// +/// Returns true on error. +static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { + FunctionDecl *Fn = E->getDirectCallee(); + assert(Fn && "builtin call without direct callee!"); + + ParmVarDecl *Param = Fn->getParamDecl(ArgIndex); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, Param); + + ExprResult Arg = E->getArg(0); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + + E->setArg(ArgIndex, Arg.take()); + return false; +} + /// SemaBuiltinAtomicOverloaded - We have a call to a function like /// __sync_fetch_and_add, which is an overloaded function based on the pointer /// type of its first argument. The main ActOnCallExpr routines have already @@ -441,6 +692,9 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + // Strip any qualifiers off ValType. + ValType = ValType.getUnqualifiedType(); + // The majority of builtins return a value, but a few have special return // types, so allow them to override appropriately below. QualType ResultType = ValType; @@ -494,7 +748,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; switch (BuiltinID) { - default: assert(0 && "Unknown overloaded atomic builtin!"); + default: llvm_unreachable("Unknown overloaded atomic builtin!"); case Builtin::BI__sync_fetch_and_add: BuiltinIndex = 0; break; case Builtin::BI__sync_fetch_and_sub: BuiltinIndex = 1; break; case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break; @@ -559,11 +813,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(), - ValType, Arg.take(), Kind, VK, BasePath); + // Initialize the argument. + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + ValType, /*consume*/ false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return ExprError(); @@ -573,17 +826,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - Arg = ImpCastExprToType(Arg.take(), ValType, Kind, VK, &BasePath); - TheCall->setArg(i+1, Arg.get()); + TheCall->setArg(i+1, Arg.take()); } - // Switch the DeclRefExpr to refer to the new decl. - DRE->setDecl(NewBuiltinDecl); - DRE->setType(NewBuiltinDecl->getType()); + ASTContext& Context = this->getASTContext(); + + // Create a new DeclRefExpr to refer to the new decl. + DeclRefExpr* NewDRE = DeclRefExpr::Create( + Context, + DRE->getQualifierLoc(), + NewBuiltinDecl, + DRE->getLocation(), + NewBuiltinDecl->getType(), + DRE->getValueKind()); // Set the callee in the CallExpr. // FIXME: This leaks the original parens and implicit casts. - ExprResult PromotedCall = UsualUnaryConversions(DRE); + ExprResult PromotedCall = UsualUnaryConversions(NewDRE); if (PromotedCall.isInvalid()) return ExprError(); TheCall->setCallee(PromotedCall.take()); @@ -596,7 +855,6 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return move(TheCallResult); } - /// CheckObjCString - Checks that the argument to the builtin /// CFString constructor is correct /// Note: It might also make sense to do the UTF-16 conversion here (would @@ -605,16 +863,16 @@ bool Sema::CheckObjCString(Expr *Arg) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); - if (!Literal || Literal->isWide()) { + if (!Literal || !Literal->isAscii()) { Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant) << Arg->getSourceRange(); return true; } if (Literal->containsNonAsciiOrNull()) { - llvm::StringRef String = Literal->getString(); + StringRef String = Literal->getString(); unsigned NumBytes = String.size(); - llvm::SmallVector<UTF16, 128> ToBuf(NumBytes); + SmallVector<UTF16, 128> ToBuf(NumBytes); const UTF8 *FromPtr = (UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; @@ -649,6 +907,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, TheCall, 0)) + return true; + // Determine whether the current function is variadic or not. BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; @@ -844,7 +1106,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << TheCall->getArg(i)->getSourceRange()); } - llvm::SmallVector<Expr*, 32> exprs; + SmallVector<Expr*, 32> exprs; for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { exprs.push_back(TheCall->getArg(i)); @@ -1238,7 +1500,7 @@ getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1); // Advance the end SourceLocation by one due to half-open ranges. - End = End.getFileLocWithOffset(1); + End = End.getLocWithOffset(1); return CharSourceRange::getCharRange(Start, End); } @@ -1322,7 +1584,7 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, } S.Diag(Loc, diag::warn_format_invalid_conversion) - << llvm::StringRef(csStart, csLen) + << StringRef(csStart, csLen) << getSpecifierRange(startSpec, specifierLen); return keepGoing; @@ -1838,7 +2100,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, bool isPrintf) { // CHECK: is the format string a wide literal? - if (FExpr->isWide()) { + if (!FExpr->isAscii()) { Diag(FExpr->getLocStart(), diag::warn_format_string_is_wide_literal) << OrigFormatExpr->getSourceRange(); @@ -1846,12 +2108,13 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } // Str - The format string. NOTE: this is NOT null-terminated! - llvm::StringRef StrRef = FExpr->getString(); + StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); unsigned StrLen = StrRef.size(); + const unsigned numDataArgs = TheCall->getNumArgs() - firstDataArg; // CHECK: empty format string? - if (StrLen == 0) { + if (StrLen == 0 && numDataArgs > 0) { Diag(FExpr->getLocStart(), diag::warn_empty_format_string) << OrigFormatExpr->getSourceRange(); return; @@ -1859,9 +2122,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, if (isPrintf) { CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - TheCall->getNumArgs() - firstDataArg, - isa<ObjCStringLiteral>(OrigFormatExpr), Str, - HasVAListArg, TheCall, format_idx); + numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr), + Str, HasVAListArg, TheCall, format_idx); bool FormatExtensions = getLangOptions().FormatExtensions; if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, @@ -1870,9 +2132,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } else { CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - TheCall->getNumArgs() - firstDataArg, - isa<ObjCStringLiteral>(OrigFormatExpr), Str, - HasVAListArg, TheCall, format_idx); + numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr), + Str, HasVAListArg, TheCall, format_idx); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen)) H.DoneProcessing(); @@ -1916,19 +2177,22 @@ static QualType getSizeOfArgType(const Expr* E) { /// \brief Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified -/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls. +/// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' +/// function calls. /// /// \param Call The call expression to diagnose. -void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, - CheckedMemoryFunction CMF, - IdentifierInfo *FnName) { +void Sema::CheckMemaccessArguments(const CallExpr *Call, + CheckedMemoryFunction CMF, + IdentifierInfo *FnName) { // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - if (Call->getNumArgs() < 3) + unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3); + if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (CMF == CMF_Memset? 1 : 2); - const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts(); + unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2); + unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2); + const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); @@ -1962,6 +2226,8 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, llvm::FoldingSetNodeID DestID; Dest->Profile(DestID, Context, true); if (DestID == SizeOfArgID) { + // TODO: For strncpy() and friends, this could suggest sizeof(dst) + // over sizeof(src) as well. unsigned ActionIdx = 0; // Default is to suggest dereferencing. if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest)) if (UnaryOp->getOpcode() == UO_AddrOf) @@ -1969,9 +2235,10 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, if (Context.getTypeSize(PointeeTy) == Context.getCharWidth()) ActionIdx = 2; // If the pointee's size is sizeof(char), // suggest an explicit length. + unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx); DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest, PDiag(diag::warn_sizeof_pointer_expr_memaccess) - << FnName << ArgIdx << ActionIdx + << FnName << DestSrcSelect << ActionIdx << Dest->getSourceRange() << SizeOfArg->getSourceRange()); break; @@ -1993,24 +2260,27 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, } } - unsigned DiagID; - // Always complain about dynamic classes. if (isDynamicClassType(PointeeTy)) - DiagID = diag::warn_dyn_class_memaccess; + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy + // "overwritten" if we're warning about the destination for any call + // but memcmp; otherwise a verb appropriate to the call. + << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF) + << Call->getCallee()->getSourceRange()); else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset) - DiagID = diag::warn_arc_object_memaccess; + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_arc_object_memaccess) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); else continue; DiagRuntimeBehavior( Dest->getExprLoc(), Dest, - PDiag(DiagID) - << ArgIdx << FnName << PointeeTy - << Call->getCallee()->getSourceRange()); - - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, PDiag(diag::note_bad_memaccess_silence) << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); break; @@ -2018,10 +2288,107 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, } } +// A little helper routine: ignore addition and subtraction of integer literals. +// This intentionally does not ignore all integer constant expressions because +// we don't want to remove sizeof(). +static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { + Ex = Ex->IgnoreParenCasts(); + + for (;;) { + const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); + if (!BO || !BO->isAdditiveOp()) + break; + + const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); + const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); + + if (isa<IntegerLiteral>(RHS)) + Ex = LHS; + else if (isa<IntegerLiteral>(LHS)) + Ex = RHS; + else + break; + } + + return Ex; +} + +// Warn if the user has made the 'size' argument to strlcpy or strlcat +// be the size of the source, instead of the destination. +void Sema::CheckStrlcpycatArguments(const CallExpr *Call, + IdentifierInfo *FnName) { + + // Don't crash if the user has the wrong number of arguments + if (Call->getNumArgs() != 3) + return; + + const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context); + const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context); + const Expr *CompareWithSrc = NULL; + + // Look for 'strlcpy(dst, x, sizeof(x))' + if (const Expr *Ex = getSizeOfExprArg(SizeArg)) + CompareWithSrc = Ex; + else { + // Look for 'strlcpy(dst, x, strlen(x))' + if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) { + if (SizeCall->isBuiltinCall(Context) == Builtin::BIstrlen + && SizeCall->getNumArgs() == 1) + CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context); + } + } + + if (!CompareWithSrc) + return; + + // Determine if the argument to sizeof/strlen is equal to the source + // argument. In principle there's all kinds of things you could do + // here, for instance creating an == expression and evaluating it with + // EvaluateAsBooleanCondition, but this uses a more direct technique: + const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg); + if (!SrcArgDRE) + return; + + const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc); + if (!CompareWithSrcDRE || + SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) + return; + + const Expr *OriginalSizeArg = Call->getArg(2); + Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size) + << OriginalSizeArg->getSourceRange() << FnName; + + // Output a FIXIT hint if the destination is an array (rather than a + // pointer to an array). This could be enhanced to handle some + // pointers if we know the actual size, like if DstArg is 'array+2' + // we could say 'sizeof(array)-2'. + const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts(); + QualType DstArgTy = DstArg->getType(); + + // Only handle constant-sized or VLAs, but not flexible members. + if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) { + // Only issue the FIXIT for arrays of size > 1. + if (CAT->getSize().getSExtValue() <= 1) + return; + } else if (!DstArgTy->isVariableArrayType()) { + return; + } + + llvm::SmallString<128> sizeString; + llvm::raw_svector_ostream OS(sizeString); + OS << "sizeof("; + DstArg->printPretty(OS, Context, 0, getPrintingPolicy()); + OS << ")"; + + Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) + << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), + OS.str()); +} + //===--- CHECK: Return Address of Stack Variable --------------------------===// -static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); -static Expr *EvalAddr(Expr* E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); +static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars); +static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -2030,7 +2397,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { Expr *stackE = 0; - llvm::SmallVector<DeclRefExpr *, 8> refVars; + SmallVector<DeclRefExpr *, 8> refVars; // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. @@ -2112,7 +2479,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { +static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) { if (E->isTypeDependent()) return NULL; @@ -2257,7 +2624,7 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { +static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) { do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead @@ -2374,11 +2741,11 @@ do { /// Check for comparisons of floating point operands using != and ==. /// Issue a warning if these are no self-comparisons, as they are not likely /// to do what the programmer intended. -void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { +void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { bool EmitWarning = true; - Expr* LeftExprSansParen = lex->IgnoreParenImpCasts(); - Expr* RightExprSansParen = rex->IgnoreParenImpCasts(); + Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts(); + Expr* RightExprSansParen = RHS->IgnoreParenImpCasts(); // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. @@ -2417,8 +2784,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { // Emit the diagnostic. if (EmitWarning) - Diag(loc, diag::warn_floatingpoint_eq) - << lex->getSourceRange() << rex->getSourceRange(); + Diag(Loc, diag::warn_floatingpoint_eq) + << LHS->getSourceRange() << RHS->getSourceRange(); } //===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// @@ -2462,7 +2829,7 @@ struct IntRange { // For enum types, use the known bit width of the enumerators. if (const EnumType *ET = dyn_cast<EnumType>(T)) { EnumDecl *Enum = ET->getDecl(); - if (!Enum->isDefinition()) + if (!Enum->isCompleteDefinition()) return IntRange(C.getIntWidth(QualType(T, 0)), false); unsigned NumPositive = Enum->getNumPositiveBits(); @@ -2490,7 +2857,7 @@ struct IntRange { if (const ComplexType *CT = dyn_cast<ComplexType>(T)) T = CT->getElementType().getTypePtr(); if (const EnumType *ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr(); const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -2767,14 +3134,9 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { IntRange::forValueOfType(C, E->getType()); } - FieldDecl *BitField = E->getBitField(); - if (BitField) { - llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); - unsigned BitWidth = BitWidthAP.getZExtValue(); - - return IntRange(BitWidth, + if (FieldDecl *BitField = E->getBitField()) + return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); - } return IntRange::forValueOfType(C, E->getType()); } @@ -2883,10 +3245,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// -/// \param lex the left-hand expression -/// \param rex the right-hand expression -/// \param OpLoc the location of the joining operator -/// \param BinOpc binary opcode or 0 +/// \param E the binary operator to check for warnings void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -2903,20 +3262,20 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { || E->isValueDependent() || E->isIntegerConstantExpr(S.Context)) return AnalyzeImpConvsInComparison(S, E); - Expr *lex = E->getLHS()->IgnoreParenImpCasts(); - Expr *rex = E->getRHS()->IgnoreParenImpCasts(); + Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); + Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; - if (lex->getType()->hasSignedIntegerRepresentation()) { - assert(!rex->getType()->hasSignedIntegerRepresentation() && + if (LHS->getType()->hasSignedIntegerRepresentation()) { + assert(!RHS->getType()->hasSignedIntegerRepresentation() && "unsigned comparison between two signed integer expressions?"); - signedOperand = lex; - unsignedOperand = rex; - } else if (rex->getType()->hasSignedIntegerRepresentation()) { - signedOperand = rex; - unsignedOperand = lex; + signedOperand = LHS; + unsignedOperand = RHS; + } else if (RHS->getType()->hasSignedIntegerRepresentation()) { + signedOperand = RHS; + unsignedOperand = LHS; } else { CheckTrivialUnsignedComparison(S, E); return AnalyzeImpConvsInComparison(S, E); @@ -2927,8 +3286,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. - AnalyzeImplicitConversions(S, lex, E->getOperatorLoc()); - AnalyzeImplicitConversions(S, rex, E->getOperatorLoc()); + AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); + AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); // If the signed range is non-negative, -Wsign-compare won't fire, // but we should still check for comparisons which are always true @@ -2953,8 +3312,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { } S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange(); } /// Analyzes an attempt to assign the given value to a bitfield. @@ -2979,16 +3338,14 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, Expr *OriginalInit = Init->IgnoreParenImpCasts(); - llvm::APSInt Width(32); Expr::EvalResult InitValue; - if (!Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) || - !OriginalInit->Evaluate(InitValue, S.Context) || + if (!OriginalInit->Evaluate(InitValue, S.Context) || !InitValue.Val.isInt()) return false; const llvm::APSInt &Value = InitValue.Val.getInt(); unsigned OriginalWidth = Value.getBitWidth(); - unsigned FieldWidth = Width.getZExtValue(); + unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); if (OriginalWidth <= FieldWidth) return false; @@ -3049,34 +3406,22 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag); } -/// Diagnose an implicit cast from a literal expression. Also attemps to supply -/// fixit hints when the cast wouldn't lose information to simply write the -/// expression with the expected type. +/// Diagnose an implicit cast from a literal expression. Does not warn when the +/// cast wouldn't lose information. void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, SourceLocation CContext) { - // Emit the primary warning first, then try to emit a fixit hint note if - // reasonable. - S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) - << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext); - - const llvm::APFloat &Value = FL->getValue(); - - // Don't attempt to fix PPC double double literals. - if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble) - return; - - // Try to convert this exactly to an integer. + // Try to convert the literal exactly to an integer. If we can, don't warn. bool isExact = false; + const llvm::APFloat &Value = FL->getValue(); llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, &isExact) - != llvm::APFloat::opOK || !isExact) + == llvm::APFloat::opOK && isExact) return; - std::string LiteralValue = IntegerValue.toString(10); - S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer) - << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue); + S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) + << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext); } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -3102,17 +3447,24 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Source == Target) return; if (Target->isDependentType()) return; - // If the conversion context location is invalid don't complain. - // We also don't want to emit a warning if the issue occurs from the - // instantiation of a system macro. The problem is that 'getSpellingLoc()' - // is slow, so we delay this check as long as possible. Once we detect - // we are in that scenario, we just return. + // If the conversion context location is invalid don't complain. We also + // don't want to emit a warning if the issue occurs from the expansion of + // a system macro. The problem is that 'getSpellingLoc()' is slow, so we + // delay this check as long as possible. Once we detect we are in that + // scenario, we just return. if (CC.isInvalid()) return; - // Never diagnose implicit casts to bool. - if (Target->isSpecificBuiltinType(BuiltinType::Bool)) - return; + // Diagnose implicit casts to bool. + if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { + if (isa<StringLiteral>(E)) + // Warn on string literal to bool. Checks for string literals in logical + // expressions, for instances, assert(0 && "error here"), is prevented + // by a check in AnalyzeImplicitConversions(). + return DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_string_literal_to_bool); + return; // Other casts to bool are not checked. + } // Strip vector types. if (isa<VectorType>(Source)) { @@ -3180,6 +3532,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; Expr *InnerE = E->IgnoreParenImpCasts(); + // We also want to warn on, e.g., "int i = -1.234" + if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) + if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) + InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); + if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { DiagnoseFloatingLiteralImpCast(S, FL, T, CC); } else { @@ -3314,29 +3671,16 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { CC)) return; - // ...and -Wsign-compare isn't... - if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional, CC)) - return; - // ...then check whether it would have warned about either of the // candidates for a signedness conversion to the condition type. - if (E->getType() != T) { - Suspicious = false; - CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + if (E->getType() == T) return; + + Suspicious = false; + CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + E->getType(), CC, &Suspicious); + if (!Suspicious) + CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); - if (!Suspicious) - CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), - E->getType(), CC, &Suspicious); - if (!Suspicious) - return; - } - - // If so, emit a diagnostic under -Wsign-compare. - Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts(); - Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts(); - S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); } /// AnalyzeImplicitConversions - Find and report any interesting @@ -3346,6 +3690,9 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); + if (E->isTypeDependent() || E->isValueDependent()) + return; + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -3389,8 +3736,16 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { // Now just recurse over the expression's children. CC = E->getExprLoc(); - for (Stmt::child_range I = E->children(); I; ++I) - AnalyzeImplicitConversions(S, cast<Expr>(*I), CC); + BinaryOperator *BO = dyn_cast<BinaryOperator>(E); + bool IsLogicalOperator = BO && BO->isLogicalOp(); + for (Stmt::child_range I = E->children(); I; ++I) { + Expr *ChildExpr = cast<Expr>(*I); + if (IsLogicalOperator && + isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts())) + // Ignore checking string literals that are in logical operators. + continue; + AnalyzeImplicitConversions(S, ChildExpr, CC); + } } } // end anonymous namespace @@ -3411,6 +3766,11 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { if (E->isTypeDependent() || E->isValueDependent()) return; + // Check for array bounds violations in cases where the check isn't triggered + // elsewhere for other Expr types (like BinaryOperators), e.g. when an + // ArraySubscriptExpr is on the RHS of a variable initialization. + CheckArrayAccess(E); + // This is not the right CC for (e.g.) a variable initialization. AnalyzeImplicitConversions(*this, E, CC); } @@ -3477,7 +3837,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { // cast; don't do it if we're ignoring -Wcast_align (as is the default). if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align, TRange.getBegin()) - == Diagnostic::Ignored) + == DiagnosticsEngine::Ignored) return; // Ignore dependent types. @@ -3515,63 +3875,164 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -static void CheckArrayAccess_Check(Sema &S, - const clang::ArraySubscriptExpr *E) { - const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts(); +static const Type* getElementType(const Expr *BaseExpr) { + const Type* EltType = BaseExpr->getType().getTypePtr(); + if (EltType->isAnyPointerType()) + return EltType->getPointeeType().getTypePtr(); + else if (EltType->isArrayType()) + return EltType->getBaseElementTypeUnsafe(); + return EltType; +} + +/// \brief Check whether this array fits the idiom of a size-one tail padded +/// array member of a struct. +/// +/// We avoid emitting out-of-bounds access warnings for such arrays as they are +/// commonly used to emulate flexible arrays in C89 code. +static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size, + const NamedDecl *ND) { + if (Size != 1 || !ND) return false; + + const FieldDecl *FD = dyn_cast<FieldDecl>(ND); + if (!FD) return false; + + // Don't consider sizes resulting from macro expansions or template argument + // substitution to form C89 tail-padded arrays. + ConstantArrayTypeLoc TL = + cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc()); + const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr()); + if (!SizeExpr || SizeExpr->getExprLoc().isMacroID()) + return false; + + const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext()); + if (!RD || !RD->isStruct()) + return false; + + // See if this is the last field decl in the record. + const Decl *D = FD; + while ((D = D->getNextDeclInContext())) + if (isa<FieldDecl>(D)) + return false; + return true; +} + +void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, + bool isSubscript, bool AllowOnePastEnd) { + const Type* EffectiveType = getElementType(BaseExpr); + BaseExpr = BaseExpr->IgnoreParenCasts(); + IndexExpr = IndexExpr->IgnoreParenCasts(); + const ConstantArrayType *ArrayTy = - S.Context.getAsConstantArrayType(BaseExpr->getType()); + Context.getAsConstantArrayType(BaseExpr->getType()); if (!ArrayTy) return; - const Expr *IndexExpr = E->getIdx(); if (IndexExpr->isValueDependent()) return; llvm::APSInt index; - if (!IndexExpr->isIntegerConstantExpr(index, S.Context)) + if (!IndexExpr->isIntegerConstantExpr(index, Context)) return; + const NamedDecl *ND = NULL; + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(DRE->getDecl()); + if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); if (!size.isStrictlyPositive()) return; + + const Type* BaseType = getElementType(BaseExpr); + if (BaseType != EffectiveType) { + // Make sure we're comparing apples to apples when comparing index to size + uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); + uint64_t array_typesize = Context.getTypeSize(BaseType); + // Handle ptrarith_typesize being zero, such as when casting to void* + if (!ptrarith_typesize) ptrarith_typesize = 1; + if (ptrarith_typesize != array_typesize) { + // There's a cast to a different size type involved + uint64_t ratio = array_typesize / ptrarith_typesize; + // TODO: Be smarter about handling cases where array_typesize is not a + // multiple of ptrarith_typesize + if (ptrarith_typesize * ratio == array_typesize) + size *= llvm::APInt(size.getBitWidth(), ratio); + } + } + if (size.getBitWidth() > index.getBitWidth()) index = index.sext(size.getBitWidth()); else if (size.getBitWidth() < index.getBitWidth()) size = size.sext(index.getBitWidth()); - if (index.slt(size)) + // For array subscripting the index must be less than size, but for pointer + // arithmetic also allow the index (offset) to be equal to size since + // computing the next address after the end of the array is legal and + // commonly done e.g. in C++ iterators and range-based for loops. + if (AllowOnePastEnd ? index.sle(size) : index.slt(size)) + return; + + // Also don't warn for arrays of size 1 which are members of some + // structure. These are often used to approximate flexible arrays in C89 + // code. + if (IsTailPaddedMemberArray(*this, size, ND)) return; - S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - S.PDiag(diag::warn_array_index_exceeds_bounds) - << index.toString(10, true) - << size.toString(10, true) - << IndexExpr->getSourceRange()); + unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds; + if (isSubscript) + DiagID = diag::warn_array_index_exceeds_bounds; + + DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, + PDiag(DiagID) << index.toString(10, true) + << size.toString(10, true) + << (unsigned)size.getLimitedValue(~0U) + << IndexExpr->getSourceRange()); } else { - S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - S.PDiag(diag::warn_array_index_precedes_bounds) - << index.toString(10, true) - << IndexExpr->getSourceRange()); + unsigned DiagID = diag::warn_array_index_precedes_bounds; + if (!isSubscript) { + DiagID = diag::warn_ptr_arith_precedes_bounds; + if (index.isNegative()) index = -index; + } + + DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, + PDiag(DiagID) << index.toString(10, true) + << IndexExpr->getSourceRange()); } - const NamedDecl *ND = NULL; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); - if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); if (ND) - S.DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, - S.PDiag(diag::note_array_index_out_of_bounds) - << ND->getDeclName()); + DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, + PDiag(diag::note_array_index_out_of_bounds) + << ND->getDeclName()); } void Sema::CheckArrayAccess(const Expr *expr) { - while (true) { - expr = expr->IgnoreParens(); + int AllowOnePastEnd = 0; + while (expr) { + expr = expr->IgnoreParenImpCasts(); switch (expr->getStmtClass()) { - case Stmt::ArraySubscriptExprClass: - CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr)); + case Stmt::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); + CheckArrayAccess(ASE->getBase(), ASE->getIdx(), true, + AllowOnePastEnd > 0); return; + } + case Stmt::UnaryOperatorClass: { + // Only unwrap the * and & unary operators + const UnaryOperator *UO = cast<UnaryOperator>(expr); + expr = UO->getSubExpr(); + switch (UO->getOpcode()) { + case UO_AddrOf: + AllowOnePastEnd++; + break; + case UO_Deref: + AllowOnePastEnd--; + break; + default: + return; + } + break; + } case Stmt::ConditionalOperatorClass: { const ConditionalOperator *cond = cast<ConditionalOperator>(expr); if (const Expr *lhs = cond->getLHS()) @@ -3625,7 +4086,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) { case CK_BitCast: case CK_LValueBitCast: case CK_LValueToRValue: - case CK_ObjCReclaimReturnedObject: + case CK_ARCReclaimReturnedObject: e = cast->getSubExpr(); continue; @@ -3634,10 +4095,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) { const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty(); if (pre->isImplicitProperty()) return false; ObjCPropertyDecl *property = pre->getExplicitProperty(); - if (!(property->getPropertyAttributes() & - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_strong)) && + if (!property->isRetaining() && !(property->getPropertyIvarDecl() && property->getPropertyIvarDecl()->getType() .getObjCLifetime() == Qualifiers::OCL_Strong)) @@ -3758,7 +4216,7 @@ static void diagnoseRetainCycle(Sema &S, Expr *capturer, static bool isSetterLikeSelector(Selector sel) { if (sel.isUnarySelector()) return false; - llvm::StringRef str = sel.getNameForSlot(0); + StringRef str = sel.getNameForSlot(0); while (!str.empty() && str.front() == '_') str = str.substr(1); if (str.startswith("set") || str.startswith("add")) str = str.substr(3); @@ -3810,7 +4268,7 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc, return false; // strip off any implicit cast added to get to the one arc-specific while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { - if (cast->getCastKind() == CK_ObjCConsumeObject) { + if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_assign) << (LT == Qualifiers::OCL_ExplicitNone) << RHS->getSourceRange(); @@ -3841,7 +4299,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, unsigned Attributes = PD->getPropertyAttributes(); if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { - if (cast->getCastKind() == CK_ObjCConsumeObject) { + if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_property_assign) << RHS->getSourceRange(); return; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index b555c8a..405d626 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -61,7 +61,7 @@ namespace { /// a single (declaration, index) mapping (the common case) but /// can also store a list of (declaration, index) mappings. class ShadowMapEntry { - typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector; + typedef SmallVector<DeclIndexPair, 4> DeclIndexPairVector; /// \brief Contains either the solitary NamedDecl * or a vector /// of (declaration, index) pairs. @@ -434,7 +434,7 @@ static NestedNameSpecifier * getRequiredQualification(ASTContext &Context, DeclContext *CurContext, DeclContext *TargetContext) { - llvm::SmallVector<DeclContext *, 4> TargetParents; + SmallVector<DeclContext *, 4> TargetParents; for (DeclContext *CommonAncestor = TargetContext; CommonAncestor && !CommonAncestor->Encloses(CurContext); @@ -990,9 +990,6 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { else if (SemaRef.getLangOptions().ObjC1) { if (isa<ObjCIvarDecl>(ND)) return true; - if (isa<ObjCPropertyDecl>(ND) && - SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) - return true; } return ND->getIdentifierNamespace() & IDNS; @@ -1011,9 +1008,6 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const { else if (SemaRef.getLangOptions().ObjC1) { if (isa<ObjCIvarDecl>(ND)) return true; - if (isa<ObjCPropertyDecl>(ND) && - SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) - return true; } return ND->getIdentifierNamespace() & IDNS; @@ -1192,8 +1186,16 @@ namespace { CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) : Results(Results), CurContext(CurContext) { } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { - Results.AddResult(ND, CurContext, Hiding, InBaseClass); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) { + bool Accessible = true; + if (Ctx) { + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) + Accessible = Results.getSema().IsSimplyAccessible(ND, Class); + // FIXME: ObjC access checks are missing. + } + ResultBuilder::Result Result(ND, 0, false, Accessible); + Results.AddResult(Result, CurContext, Hiding, InBaseClass); } }; } @@ -1846,6 +1848,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("operator")); } +/// \brief Retrieve a printing policy suitable for code completion. +static PrintingPolicy getCompletionPrintingPolicy(Sema &S) { + PrintingPolicy Policy = S.getPrintingPolicy(); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + return Policy; +} + /// \brief Retrieve the string representation of the given type as a string /// that has the appropriate lifetime for code completion. /// @@ -1853,15 +1863,12 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, /// common type names. static const char *GetCompletionTypeString(QualType T, ASTContext &Context, + const PrintingPolicy &Policy, CodeCompletionAllocator &Allocator) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - if (!T.getLocalQualifiers()) { // Built-in type names are constant strings. if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) - return BT->getName(Context.getLangOptions()); + return BT->getName(Policy); // Anonymous tag types are constant strings. if (const TagType *TagT = dyn_cast<TagType>(T)) @@ -1885,6 +1892,7 @@ static const char *GetCompletionTypeString(QualType T, /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, + const PrintingPolicy &Policy, NamedDecl *ND, CodeCompletionBuilder &Result) { if (!ND) @@ -1915,7 +1923,7 @@ static void AddResultTypeChunk(ASTContext &Context, if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; - Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, + Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, Policy, Result.getAllocator())); } @@ -1933,13 +1941,32 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod, } } +static void appendWithSpace(std::string &Result, StringRef Text) { + if (!Result.empty()) + Result += ' '; + Result += Text.str(); +} +static std::string formatObjCParamQualifiers(unsigned ObjCQuals) { + std::string Result; + if (ObjCQuals & Decl::OBJC_TQ_In) + appendWithSpace(Result, "in"); + else if (ObjCQuals & Decl::OBJC_TQ_Inout) + appendWithSpace(Result, "inout"); + else if (ObjCQuals & Decl::OBJC_TQ_Out) + appendWithSpace(Result, "out"); + if (ObjCQuals & Decl::OBJC_TQ_Bycopy) + appendWithSpace(Result, "bycopy"); + else if (ObjCQuals & Decl::OBJC_TQ_Byref) + appendWithSpace(Result, "byref"); + if (ObjCQuals & Decl::OBJC_TQ_Oneway) + appendWithSpace(Result, "oneway"); + return Result; +} + static std::string FormatFunctionParameter(ASTContext &Context, + const PrintingPolicy &Policy, ParmVarDecl *Param, bool SuppressName = false) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -1953,8 +1980,8 @@ static std::string FormatFunctionParameter(ASTContext &Context, Param->getType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { - Result = "(" + Result; - Result += ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) + + Result + ")"; if (Param->getIdentifier() && !SuppressName) Result += Param->getIdentifier()->getName(); } @@ -2003,8 +2030,8 @@ static std::string FormatFunctionParameter(ASTContext &Context, Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { - Result = "(" + Result; - Result += ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) + + Result + ")"; if (Param->getIdentifier()) Result += Param->getIdentifier()->getName(); } @@ -2030,7 +2057,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { if (I) Result += ", "; - Result += FormatFunctionParameter(Context, Block->getArg(I)); + Result += FormatFunctionParameter(Context, Policy, Block->getArg(I)); if (I == N - 1 && BlockProto->getTypePtr()->isVariadic()) Result += ", ..."; @@ -2046,6 +2073,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(ASTContext &Context, + const PrintingPolicy &Policy, FunctionDecl *Function, CodeCompletionBuilder &Result, unsigned Start = 0, @@ -2062,7 +2090,7 @@ static void AddFunctionParameterChunks(ASTContext &Context, CodeCompletionBuilder Opt(Result.getAllocator()); if (!FirstParameter) Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - AddFunctionParameterChunks(Context, Function, Opt, P, true); + AddFunctionParameterChunks(Context, Policy, Function, Opt, P, true); Result.AddOptionalChunk(Opt.TakeString()); break; } @@ -2075,7 +2103,8 @@ static void AddFunctionParameterChunks(ASTContext &Context, InOptional = false; // Format the placeholder string. - std::string PlaceholderStr = FormatFunctionParameter(Context, Param); + std::string PlaceholderStr = FormatFunctionParameter(Context, Policy, + Param); if (Function->isVariadic() && P == N - 1) PlaceholderStr += ", ..."; @@ -2097,14 +2126,12 @@ static void AddFunctionParameterChunks(ASTContext &Context, /// \brief Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks(ASTContext &Context, + const PrintingPolicy &Policy, TemplateDecl *Template, CodeCompletionBuilder &Result, unsigned MaxParameters = 0, unsigned Start = 0, bool InDefaultArg = false) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - typedef CodeCompletionString::Chunk Chunk; bool FirstParameter = true; @@ -2155,7 +2182,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, CodeCompletionBuilder Opt(Result.getAllocator()); if (!FirstParameter) Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - AddTemplateParameterChunks(Context, Template, Opt, MaxParameters, + AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters, P - Params->begin(), true); Result.AddOptionalChunk(Opt.TakeString()); break; @@ -2180,14 +2207,15 @@ static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, NestedNameSpecifier *Qualifier, bool QualifierIsInformative, - ASTContext &Context) { + ASTContext &Context, + const PrintingPolicy &Policy) { if (!Qualifier) return; std::string PrintedNNS; { llvm::raw_string_ostream OS(PrintedNNS); - Qualifier->print(OS, Context.PrintingPolicy); + Qualifier->print(OS, Policy); } if (QualifierIsInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS)); @@ -2233,8 +2261,8 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, } /// \brief Add the name of the given declaration -static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND, - CodeCompletionBuilder &Result) { +static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, + NamedDecl *ND, CodeCompletionBuilder &Result) { typedef CodeCompletionString::Chunk Chunk; DeclarationName Name = ND->getDeclName(); @@ -2299,7 +2327,7 @@ static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND, Result.getAllocator().CopyString(Record->getNameAsString())); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(Context, Template, Result); + AddTemplateParameterChunks(Context, Policy, Template, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } break; @@ -2319,10 +2347,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, typedef CodeCompletionString::Chunk Chunk; CodeCompletionBuilder Result(Allocator, Priority, Availability); - PrintingPolicy Policy(S.Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - + PrintingPolicy Policy = getCompletionPrintingPolicy(S); if (Kind == RK_Pattern) { Pattern->Priority = Priority; Pattern->Availability = Availability; @@ -2346,19 +2371,24 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // Format a function-like macro with placeholders for the arguments. Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); - A != AEnd; ++A) { + bool CombineVariadicArgument = false; + MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); + if (MI->isVariadic() && AEnd - A > 1) { + AEnd -= 2; + CombineVariadicArgument = true; + } + for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) { if (A != MI->arg_begin()) Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - if (!MI->isVariadic() || A != AEnd - 1) { + if (!MI->isVariadic() || A + 1 != AEnd) { // Non-variadic argument. Result.AddPlaceholderChunk( Result.getAllocator().CopyString((*A)->getName())); continue; } - // Variadic argument; cope with the different between GNU and C99 + // Variadic argument; cope with the difference between GNU and C99 // variadic macros, providing a single placeholder for the rest of the // arguments. if ((*A)->isStr("__VA_ARGS__")) @@ -2369,6 +2399,18 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); } } + + if (CombineVariadicArgument) { + // Handle the next-to-last argument, combining it with the variadic + // argument. + std::string LastArg = (*A)->getName(); + ++A; + if ((*A)->isStr("__VA_ARGS__")) + LastArg += ", ..."; + else + LastArg += ", " + (*A)->getName().str() + "..."; + Result.AddPlaceholderChunk(Result.getAllocator().CopyString(LastArg)); + } Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result.TakeString(); } @@ -2382,15 +2424,21 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, Result.AddTextChunk("::"); return Result.TakeString(); } + + for (Decl::attr_iterator i = ND->attr_begin(); i != ND->attr_end(); ++i) { + if (AnnotateAttr *Attr = dyn_cast_or_null<AnnotateAttr>(*i)) { + Result.AddAnnotation(Result.getAllocator().CopyString(Attr->getAnnotation())); + } + } - AddResultTypeChunk(S.Context, ND, Result); + AddResultTypeChunk(S.Context, Policy, ND, Result); if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); - AddTypedNameChunk(S.Context, ND, Result); + S.Context, Policy); + AddTypedNameChunk(S.Context, Policy, ND, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - AddFunctionParameterChunks(S.Context, Function, Result); + AddFunctionParameterChunks(S.Context, Policy, Function, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); @@ -2398,13 +2446,13 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - AddTypedNameChunk(S.Context, Function, Result); + AddTypedNameChunk(S.Context, Policy, Function, Result); // Figure out which template parameters are deduced (or have default // arguments). - llvm::SmallVector<bool, 16> Deduced; + SmallVector<bool, 16> Deduced; S.MarkDeducedTemplateParameters(FunTmpl, Deduced); unsigned LastDeducibleArgument; for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; @@ -2437,14 +2485,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(S.Context, FunTmpl, Result, + AddTemplateParameterChunks(S.Context, Policy, FunTmpl, Result, LastDeducibleArgument); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } // Add the function parameters Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - AddFunctionParameterChunks(S.Context, Function, Result); + AddFunctionParameterChunks(S.Context, Policy, Function, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); @@ -2452,11 +2500,11 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Template->getNameAsString())); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(S.Context, Template, Result); + AddTemplateParameterChunks(S.Context, Policy, Template, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); return Result.TakeString(); } @@ -2490,7 +2538,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (Idx > StartParameter) Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) - Keyword += II->getName().str(); + Keyword += II->getName(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword)); @@ -2505,13 +2553,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, std::string Arg; if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) - Arg = FormatFunctionParameter(S.Context, *P, true); + Arg = FormatFunctionParameter(S.Context, Policy, *P, true); else { (*P)->getType().getAsStringInternal(Arg, Policy); - Arg = "(" + Arg + ")"; + Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier()) + + Arg + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) - Arg += II->getName().str(); + Arg += II->getName(); } if (Method->isVariadic() && (P + 1) == PEnd) @@ -2543,7 +2592,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (Qualifier) AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); @@ -2556,14 +2605,12 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Sema &S, CodeCompletionAllocator &Allocator) const { typedef CodeCompletionString::Chunk Chunk; - PrintingPolicy Policy(S.Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; + PrintingPolicy Policy = getCompletionPrintingPolicy(S); // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available); FunctionDecl *FDecl = getFunction(); - AddResultTypeChunk(S.Context, FDecl, Result); + AddResultTypeChunk(S.Context, Policy, FDecl, Result); const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(getFunctionType()); if (!FDecl && !Proto) { @@ -2571,7 +2618,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // highlighted ellipsis. const FunctionType *FT = getFunctionType(); Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(), - S.Context, + S.Context, Policy, Result.getAllocator())); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); @@ -2624,7 +2671,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( return Result.TakeString(); } -unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName, +unsigned clang::getMacroUsagePriority(StringRef MacroName, const LangOptions &LangOpts, bool PreferredTypeIsPointer) { unsigned Priority = CCP_Macro; @@ -2689,6 +2736,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case Decl::TemplateTemplateParm:return CXCursor_TemplateTemplateParameter; case Decl::FunctionTemplate: return CXCursor_FunctionTemplate; case Decl::ClassTemplate: return CXCursor_ClassTemplate; + case Decl::AccessSpec: return CXCursor_CXXAccessSpecifier; case Decl::ClassTemplatePartialSpecialization: return CXCursor_ClassTemplatePartialSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; @@ -2850,6 +2898,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, return; } + PrintingPolicy Policy = getCompletionPrintingPolicy(S); for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), MEnd = Method->end_overridden_methods(); M != MEnd; ++M) { @@ -2866,7 +2915,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, if (NNS) { std::string Str; llvm::raw_string_ostream OS(Str); - NNS->print(OS, S.Context.PrintingPolicy); + NNS->print(OS, Policy); Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str())); } } else if (!InContext->Equals(Overridden->getDeclContext())) @@ -3059,7 +3108,7 @@ struct Sema::CodeCompleteExpressionData { QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; - llvm::SmallVector<Decl *, 4> IgnoreDecls; + SmallVector<Decl *, 4> IgnoreDecls; }; /// \brief Perform code-completion in an expression context when we know what @@ -3146,6 +3195,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, // Add nullary methods if (AllowNullaryMethods) { ASTContext &Context = Container->getASTContext(); + PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), MEnd = Container->meth_end(); M != MEnd; ++M) { @@ -3153,7 +3203,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) if (AddedProperties.insert(Name)) { CodeCompletionBuilder Builder(Results.getAllocator()); - AddResultTypeChunk(Context, *M, Builder); + AddResultTypeChunk(Context, Policy, *M, Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Name->getName())); @@ -3224,7 +3274,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, } } -void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, +void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE, SourceLocation OpLoc, bool IsArrow) { if (!BaseE || !CodeCompleter) @@ -3366,8 +3416,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { break; default: - assert(false && "Unknown type specifier kind in CodeCompleteTag"); - return; + llvm_unreachable("Unknown type specifier kind in CodeCompleteTag"); } ResultBuilder Results(*this, CodeCompleter->getAllocator(), ContextKind); @@ -3408,10 +3457,11 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { void Sema::CodeCompleteCase(Scope *S) { if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; - + SwitchStmt *Switch = getCurFunction()->SwitchStack.back(); - if (!Switch->getCond()->getType()->isEnumeralType()) { - CodeCompleteExpressionData Data(Switch->getCond()->getType()); + QualType type = Switch->getCond()->IgnoreImplicit()->getType(); + if (!type->isEnumeralType()) { + CodeCompleteExpressionData Data(type); Data.IntegralConstantExpression = true; CodeCompleteExpression(S, Data); return; @@ -3419,7 +3469,7 @@ void Sema::CodeCompleteCase(Scope *S) { // Code-complete the cases of a switch statement over an enumeration type // by providing the list of - EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl(); + EnumDecl *Enum = type->castAs<EnumType>()->getDecl(); // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion @@ -3527,8 +3577,8 @@ static bool anyNullArguments(Expr **Args, unsigned NumArgs) { return false; } -void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, - ExprTy **ArgsIn, unsigned NumArgs) { +void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, + Expr **ArgsIn, unsigned NumArgs) { if (!CodeCompleter) return; @@ -3556,7 +3606,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: What if we're calling a member function? typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; - llvm::SmallVector<ResultCandidate, 8> Results; + SmallVector<ResultCandidate, 8> Results; Expr *NakedFn = Fn->IgnoreParenCasts(); if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) @@ -3662,7 +3712,62 @@ void Sema::CodeCompleteReturn(Scope *S) { CodeCompleteExpression(S, ResultType); } -void Sema::CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) { +void Sema::CodeCompleteAfterIf(Scope *S) { + typedef CodeCompletionResult Result; + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + mapCodeCompletionContext(*this, PCC_Statement)); + Results.setFilter(&ResultBuilder::IsOrdinaryName); + Results.EnterNewScope(); + + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); + + AddOrdinaryNameResults(PCC_Statement, S, *this, Results); + + // "else" block + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("else"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Builder.TakeString()); + + // "else if" block + Builder.AddTypedTextChunk("else"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("if"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + if (getLangOptions().CPlusPlus) + Builder.AddPlaceholderChunk("condition"); + else + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Builder.TakeString()); + + Results.ExitScope(); + + if (S->getFnParent()) + AddPrettyFunctionResults(PP.getLangOptions(), Results); + + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, Results); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(),Results.size()); +} + +void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) { if (LHS) CodeCompleteExpression(S, static_cast<Expr *>(LHS)->getType()); else @@ -3706,7 +3811,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Name, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -3848,10 +3953,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) { void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, CXXCtorInitializer** Initializers, unsigned NumInitializers) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); CXXConstructorDecl *Constructor = static_cast<CXXConstructorDecl *>(ConstructorD); if (!Constructor) @@ -4045,15 +4147,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { Results.AddResult(Result(Builder.TakeString())); } -void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, - bool InInterface) { +void Sema::CodeCompleteObjCAtDirective(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - if (ObjCImpDecl) + if (isa<ObjCImplDecl>(CurContext)) AddObjCImplementationResults(getLangOptions(), Results, false); - else if (InInterface) + else if (CurContext->isObjCContainer()) AddObjCInterfaceResults(getLangOptions(), Results, false); else AddObjCTopLevelResults(Results, false); @@ -4425,14 +4526,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container, } -void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) { +void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { typedef CodeCompletionResult Result; // Try to find the interface where getters might live. - ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(ClassDecl); + ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null<ObjCCategoryDecl>(ClassDecl)) + = dyn_cast_or_null<ObjCCategoryDecl>(CurContext)) Class = Category->getClassInterface(); if (!Class) @@ -4453,15 +4554,15 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) { Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl) { +void Sema::CodeCompleteObjCPropertySetter(Scope *S) { typedef CodeCompletionResult Result; // Try to find the interface where setters might live. ObjCInterfaceDecl *Class - = dyn_cast_or_null<ObjCInterfaceDecl>(ObjCImplDecl); + = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null<ObjCCategoryDecl>(ObjCImplDecl)) + = dyn_cast_or_null<ObjCCategoryDecl>(CurContext)) Class = Category->getClassInterface(); if (!Class) @@ -4694,7 +4795,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, CodeCompletionBuilder Builder(Results.getAllocator()); // Give this completion a return type. - AddResultTypeChunk(S.Context, SuperMethod, Builder); + AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + Builder); // If we need the "super" keyword, add it (plus some spacing). if (NeedSuperKeyword) { @@ -4955,8 +5057,13 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, unsigned NumSelIdents, bool AtArgumentExpression, bool IsSuper) { + + QualType T = this->GetTypeFromParser(Receiver); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCClassMessage); + CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, + T, SelIdents, NumSelIdents)); + AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, AtArgumentExpression, IsSuper, Results); @@ -4967,7 +5074,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, // our preferred type, improving completion results. if (AtArgumentExpression) { QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, - NumSelIdents); + NumSelIdents); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); else @@ -4976,11 +5083,11 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCClassMessage, + Results.getCompletionContext(), Results.data(), Results.size()); } -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, +void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents, bool AtArgumentExpression, @@ -5019,7 +5126,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // Build the set of methods we can see. ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCInstanceMessage); + CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage, + ReceiverType, SelIdents, NumSelIdents)); + Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send @@ -5132,7 +5241,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCInstanceMessage, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -5196,7 +5305,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, } } - Accumulator += Sel.getNameForSlot(I).str(); + Accumulator += Sel.getNameForSlot(I); Accumulator += ':'; } Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Accumulator)); @@ -5303,12 +5412,11 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, // Record any forward-declared interfaces we find. if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) { - for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end(); - C != CEnd; ++C) - if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && - (!OnlyUnimplemented || !C->getInterface()->getImplementation())) - Results.AddResult(Result(C->getInterface(), 0), CurContext, - 0, false); + ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl(); + if ((!OnlyForwardDeclarations || IDecl->isForwardDecl()) && + (!OnlyUnimplemented || !IDecl->getImplementation())) + Results.AddResult(Result(IDecl, 0), CurContext, + 0, false); } } } @@ -5318,21 +5426,23 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // Add all classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, true, - false, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCSuperclass); + CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. @@ -5341,14 +5451,16 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, if (CurClass && isa<ObjCInterfaceDecl>(CurClass)) Results.Ignore(CurClass); - // Add all classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, - false, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCSuperclass, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } @@ -5357,14 +5469,16 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // Add all unimplemented classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, - true, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all unimplemented classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + true, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } @@ -5442,14 +5556,14 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { +void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl); + = dyn_cast_or_null<ObjCContainerDecl>(CurContext); if (!Container || (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) @@ -5482,15 +5596,14 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { } void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, - IdentifierInfo *PropertyName, - Decl *ObjCImpDecl) { + IdentifierInfo *PropertyName) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl); + = dyn_cast_or_null<ObjCContainerDecl>(CurContext); if (!Container || (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) @@ -5523,7 +5636,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, bool SawSimilarlyNamedIvar = false; std::string NameWithPrefix; NameWithPrefix += '_'; - NameWithPrefix += PropertyName->getName().str(); + NameWithPrefix += PropertyName->getName(); std::string NameWithSuffix = PropertyName->getName().str(); NameWithSuffix += '_'; for(; Class; Class = Class->getSuperClass()) { @@ -5557,8 +5670,9 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available); + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context, - Allocator)); + Policy, Allocator)); Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix)); Results.AddResult(Result(Builder.TakeString(), Priority, CXCursor_ObjCIvarDecl)); @@ -5658,9 +5772,10 @@ static void FindImplementableMethods(ASTContext &Context, /// completion string. static void AddObjCPassingTypeChunk(QualType Type, ASTContext &Context, + const PrintingPolicy &Policy, CodeCompletionBuilder &Builder) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); - Builder.AddTextChunk(GetCompletionTypeString(Type, Context, + Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy, Builder.getAllocator())); Builder.AddChunk(CodeCompletionString::CK_RightParen); } @@ -5668,7 +5783,7 @@ static void AddObjCPassingTypeChunk(QualType Type, /// \brief Determine whether the given class is or inherits from a class by /// the given name. static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, - llvm::StringRef Name) { + StringRef Name) { if (!Class) return false; @@ -5690,7 +5805,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (!PropName || PropName->getLength() == 0) return; - + PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); + // Builder that will create each code completion. typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); @@ -5703,10 +5819,10 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // on demand. struct KeyHolder { CodeCompletionAllocator &Allocator; - llvm::StringRef Key; + StringRef Key; const char *CopiedKey; - KeyHolder(CodeCompletionAllocator &Allocator, llvm::StringRef Key) + KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key) : Allocator(Allocator), Key(Key), CopiedKey(0) { } operator const char *() { @@ -5733,7 +5849,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, KnownSelectors.insert(Selectors.getNullarySelector(PropName)) && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder); Builder.AddTypedTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, @@ -5748,7 +5864,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() && (Property->getType()->isIntegerType() || Property->getType()->isBooleanType())))) { - std::string SelectorName = (llvm::Twine("is") + UpperKey).str(); + std::string SelectorName = (Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5767,7 +5883,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add the normal mutator. if (IsInstanceMethod && ReturnTypeMatchesVoid && !Property->getSetterMethodDecl()) { - std::string SelectorName = (llvm::Twine("set") + UpperKey).str(); + std::string SelectorName = (Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5779,7 +5895,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName())); Builder.AddTypedTextChunk(":"); - AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder); Builder.AddTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); @@ -5818,7 +5934,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(NSUInteger)countOf<key> if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isIntegerType())) { - std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str(); + std::string SelectorName = (Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5841,7 +5957,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName - = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str(); + = (Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5868,7 +5984,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSArray"))) { std::string SelectorName - = (llvm::Twine(Property->getName()) + "AtIndexes").str(); + = (Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5889,7 +6005,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("get") + UpperKey).str(); + std::string SelectorName = (Twine("get") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("range") @@ -5923,7 +6039,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("in") + UpperKey + "AtIndex").str(); + std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get("insertObject"), &Context.Idents.get(SelectorName) @@ -5955,7 +6071,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("insert") + UpperKey).str(); + std::string SelectorName = (Twine("insert") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("atIndexes") @@ -5987,7 +6103,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); + = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6009,7 +6125,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("remove") + UpperKey + "AtIndexes").str(); + = (Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6031,7 +6147,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); + = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("withObject") @@ -6063,8 +6179,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName1 - = (llvm::Twine("replace") + UpperKey + "AtIndexes").str(); - std::string SelectorName2 = (llvm::Twine("with") + UpperKey).str(); + = (Twine("replace") + UpperKey + "AtIndexes").str(); + std::string SelectorName2 = (Twine("with") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName1), &Context.Idents.get(SelectorName2) @@ -6101,7 +6217,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSEnumerator"))) { - std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str(); + std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6119,7 +6235,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (type *)memberOfKey:(type *)object if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { - std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str(); + std::string SelectorName = (Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6136,6 +6252,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk(" *"); } else { Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, + Policy, Builder.getAllocator())); } Builder.AddChunk(CodeCompletionString::CK_RightParen); @@ -6149,7 +6266,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str(); + = (Twine("add") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6171,7 +6288,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("add") + UpperKey).str(); + std::string SelectorName = (Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6193,7 +6310,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str(); + = (Twine("remove") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6215,7 +6332,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("remove") + UpperKey).str(); + std::string SelectorName = (Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6236,7 +6353,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str(); + std::string SelectorName = (Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6264,7 +6381,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSSet"))) { std::string SelectorName - = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str(); + = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6285,7 +6402,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->isIntegerType() || ReturnType->isBooleanType())) { std::string SelectorName - = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); + = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6303,12 +6420,15 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, void Sema::CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, - ParsedType ReturnTy, - Decl *IDecl) { + ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); - + Decl *IDecl = 0; + if (CurContext->isObjCContainer()) { + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + IDecl = cast<Decl>(OCD); + } // Determine where we should start searching for methods. ObjCContainerDecl *SearchDecl = 0; bool IsInImplementation = false; @@ -6346,9 +6466,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { @@ -6358,7 +6476,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Method->getResultType(), Context, Builder); + AddObjCPassingTypeChunk(Method->getResultType(), Context, Policy, + Builder); Selector Sel = Method->getSelector(); @@ -6382,7 +6501,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, break; // Add the parameter type. - AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Builder); + AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Policy, + Builder); if (IdentifierInfo *Id = (*P)->getIdentifier()) Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); @@ -6425,7 +6545,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of // the properties in this class and its categories. if (Context.getLangOptions().ObjC2) { - llvm::SmallVector<ObjCContainerDecl *, 4> Containers; + SmallVector<ObjCContainerDecl *, 4> Containers; Containers.push_back(SearchDecl); VisitedSelectorSet KnownSelectors; @@ -6748,9 +6868,8 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, // FIXME: In the future, we could provide "overload" results, much like we // do for function calls. - CodeCompleteOrdinaryName(S, - S->getFnParent()? Sema::PCC_RecoveryInFunction - : Sema::PCC_Namespace); + // Now just ignore this. There will be another code-completion callback + // for the expanded tokens. } void Sema::CodeCompleteNaturalLanguage() { @@ -6760,7 +6879,7 @@ void Sema::CodeCompleteNaturalLanguage() { } void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, - llvm::SmallVectorImpl<CodeCompletionResult> &Results) { + SmallVectorImpl<CodeCompletionResult> &Results) { ResultBuilder Builder(*this, Allocator, CodeCompletionContext::CCC_Recovery); if (!CodeCompleter || CodeCompleter->includeGlobals()) { CodeCompletionDeclConsumer Consumer(Builder, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index 9d91a48..8d993ef 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -33,11 +33,13 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/ModuleLoader.h" #include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> @@ -69,7 +71,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, - bool WantNontrivialTypeSourceInfo) { + bool WantNontrivialTypeSourceInfo, + IdentifierInfo **CorrectedII) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; if (ObjectTypePtr) { @@ -144,6 +147,51 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: + if (CorrectedII) { + TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), + Kind, S, SS, 0, false, + Sema::CTC_Type); + IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); + TemplateTy Template; + bool MemberOfUnknownSpecialization; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(NewII, NameLoc); + NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); + CXXScopeSpec NewSS, *NewSSPtr = SS; + if (SS && NNS) { + NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); + NewSSPtr = &NewSS; + } + if (Correction && (NNS || NewII != &II) && + // Ignore a correction to a template type as the to-be-corrected + // identifier is not a template (typo correction for template names + // is handled elsewhere). + !(getLangOptions().CPlusPlus && NewSSPtr && + isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(), + false, Template, MemberOfUnknownSpecialization))) { + ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, + isClassName, HasTrailingDot, ObjectTypePtr, + WantNontrivialTypeSourceInfo); + if (Ty) { + std::string CorrectedStr(Correction.getAsString(getLangOptions())); + std::string CorrectedQuotedStr( + Correction.getQuoted(getLangOptions())); + Diag(NameLoc, diag::err_unknown_typename_suggest) + << Result.getLookupName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(SourceRange(NameLoc), + CorrectedStr); + if (NamedDecl *FirstDecl = Correction.getCorrectionDecl()) + Diag(FirstDecl->getLocation(), diag::note_previous_decl) + << CorrectedQuotedStr; + + if (SS && NNS) + SS->MakeTrivial(Context, NNS, SourceRange(NameLoc)); + *CorrectedII = NewII; + return Ty; + } + } + } + // If typo correction failed or was not performed, fall through case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); @@ -269,7 +317,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { /// A<T>::TYPE a; // no typename required because A<T> is a base class. /// }; /// @endcode -bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) { +bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { const Type *Ty = SS->getScopeRep()->getAsType(); @@ -278,8 +326,9 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) { BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType())) return true; + return S->isFunctionPrototypeScope(); } - return false; + return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, @@ -361,7 +410,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; - if (getLangOptions().Microsoft && isMicrosoftMissingTypename(SS)) + if (getLangOptions().MicrosoftMode && isMicrosoftMissingTypename(SS, S)) DiagID = diag::warn_typename_missing; Diag(SS->getRange().getBegin(), DiagID) @@ -419,24 +468,6 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, ExprResult E = LookupInObjCMethod(Result, S, Name, true); if (E.get() || E.isInvalid()) return E; - - // Synthesize ivars lazily. - if (getLangOptions().ObjCDefaultSynthProperties && - getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) { - if (const ObjCPropertyDecl *Property = - canSynthesizeProvisionalIvar(Name)) { - Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name; - Diag(Property->getLocation(), diag::note_property_declare); - } - - // FIXME: This is strange. Shouldn't we just take the ivar returned - // from SynthesizeProvisionalIvar and continue with that? - E = LookupInObjCMethod(Result, S, Name, true); - if (E.get() || E.isInvalid()) - return E; - } - } } bool SecondTry = false; @@ -737,11 +768,6 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC; } - // ObjCMethodDecls are parsed (for some reason) outside the context - // of the class. - if (isa<ObjCMethodDecl>(DC)) - return DC->getLexicalParent()->getLexicalParent(); - return DC->getLexicalParent(); } @@ -804,6 +830,29 @@ void Sema::ExitDeclaratorContext(Scope *S) { // disappear. } + +void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FunctionTemplateDecl *TFD = dyn_cast_or_null<FunctionTemplateDecl>(D)) { + // We assume that the caller has already called + // ActOnReenterTemplateScope + FD = TFD->getTemplatedDecl(); + } + if (!FD) + return; + + PushDeclContext(S, FD); + for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) { + ParmVarDecl *Param = FD->getParamDecl(P); + // If the parameter has an identifier, then add it to the scope + if (Param->getIdentifier()) { + S->AddDecl(Param); + IdResolver.AddDecl(Param); + } + } +} + + /// \brief Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// @@ -843,7 +892,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Out-of-line definitions shouldn't be pushed into scope in C++. // Out-of-line variable and function definitions shouldn't even in C. if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) && - D->isOutOfLine()) + D->isOutOfLine() && + !D->getDeclContext()->getRedeclContext()->Equals( + D->getLexicalDeclContext()->getRedeclContext())) return; // Template instantiations should also not be pushed into scope. @@ -1086,12 +1137,28 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, + FixItHint &Hint) { + if (isa<LabelDecl>(D)) { + SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(), + tok::colon, Ctx.getSourceManager(), Ctx.getLangOptions(), true); + if (AfterColon.isInvalid()) + return; + Hint = FixItHint::CreateRemoval(CharSourceRange:: + getCharRange(D->getLocStart(), AfterColon)); + } + return; +} + /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { + FixItHint Hint; if (!ShouldDiagnoseUnusedDecl(D)) return; + GenerateFixForUnusedDecl(D, Context, Hint); + unsigned DiagID; if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) DiagID = diag::warn_unused_exception_param; @@ -1100,7 +1167,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { else DiagID = diag::warn_unused_variable; - Diag(D->getLocation(), DiagID) << D->getDeclName(); + Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint; } static void CheckPoppedLabel(LabelDecl *L, Sema &S) { @@ -1246,7 +1313,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, << R; if (Context.BuiltinInfo.getHeaderName(BID) && Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) Diag(Loc, diag::note_please_include_header) << Context.BuiltinInfo.getHeaderName(BID) << Context.BuiltinInfo.GetName(BID); @@ -1263,7 +1330,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // Create Decl objects for each parameter, adding them to the // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { ParmVarDecl *parm = ParmVarDecl::Create(Context, New, SourceLocation(), @@ -1273,7 +1340,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, parm->setScopeInfo(0, i); Params.push_back(parm); } - New->setParams(Params.data(), Params.size()); + New->setParams(Params); } AddKnownFunctionAttributes(New); @@ -1308,29 +1375,24 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { case 2: if (!TypeID->isStr("id")) break; - Context.ObjCIdRedefinitionType = New->getUnderlyingType(); + Context.setObjCIdRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'id', ignoring the current definition. New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); return; case 5: if (!TypeID->isStr("Class")) break; - Context.ObjCClassRedefinitionType = New->getUnderlyingType(); + Context.setObjCClassRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'Class', ignoring the current definition. New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) break; - Context.ObjCSelRedefinitionType = New->getUnderlyingType(); + Context.setObjCSelRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'SEL', ignoring the current definition. New->setTypeForDecl(Context.getObjCSelType().getTypePtr()); return; - case 8: - if (!TypeID->isStr("Protocol")) - break; - Context.setObjCProtoType(New->getUnderlyingType()); - return; } // Fall through - the typedef name was not a builtin type. } @@ -1382,7 +1444,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old)) New->setPreviousDeclaration(Typedef); - if (getLangOptions().Microsoft) + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + + if (getLangOptions().MicrosoftExt) return; if (getLangOptions().CPlusPlus) { @@ -1443,8 +1511,14 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { static bool DeclHasAttr(const Decl *D, const Attr *A) { const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A); + const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A); for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) if ((*i)->getKind() == A->getKind()) { + if (Ann) { + if (Ann->getAnnotation() == cast<AnnotateAttr>(*i)->getAnnotation()) + return true; + continue; + } // FIXME: Don't hardcode this check if (OA && isa<OwnershipAttr>(*i)) return OA->getOwnKind() == cast<OwnershipAttr>(*i)->getOwnKind(); @@ -1456,7 +1530,7 @@ DeclHasAttr(const Decl *D, const Attr *A) { /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl, - ASTContext &C) { + ASTContext &C, bool mergeDeprecation = true) { if (!oldDecl->hasAttrs()) return; @@ -1469,6 +1543,13 @@ static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl, for (specific_attr_iterator<InheritableAttr> i = oldDecl->specific_attr_begin<InheritableAttr>(), e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) { + // Ignore deprecated/unavailable/availability attributes if requested. + if (!mergeDeprecation && + (isa<DeprecatedAttr>(*i) || + isa<UnavailableAttr>(*i) || + isa<AvailabilityAttr>(*i))) + continue; + if (!DeclHasAttr(newDecl, *i)) { InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C)); newAttr->setInherited(true); @@ -1535,6 +1616,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { return Sema::CXXDestructor; } else if (MD->isCopyAssignmentOperator()) { return Sema::CXXCopyAssignment; + } else if (MD->isMoveAssignmentOperator()) { + return Sema::CXXMoveAssignment; } return Sema::CXXInvalid; @@ -1605,7 +1688,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->getStorageClass() == SC_Static && Old->getStorageClass() != SC_Static && !canRedefineFunction(Old, getLangOptions())) { - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { Diag(New->getLocation(), diag::warn_static_non_static) << New; Diag(Old->getLocation(), PrevDiag); } else { @@ -1669,6 +1752,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { RequiresAdjustment = true; } + // Merge ns_returns_retained attribute. + if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) { + if (NewTypeInfo.getProducesResult()) { + Diag(New->getLocation(), diag::err_returns_retained_mismatch); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; + } + + NewTypeInfo = NewTypeInfo.withProducesResult(true); + RequiresAdjustment = true; + } + if (RequiresAdjustment) { NewType = Context.adjustFunctionType(NewType, NewTypeInfo); New->setType(QualType(NewType, 0)); @@ -1706,9 +1801,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); + // MSVC allows explicit template specialization at class scope: + // 2 CXMethodDecls referring to the same function will be injected. + // We don't want a redeclartion error. + bool IsClassScopeExplicitSpecialization = + OldMethod->isFunctionTemplateSpecialization() && + NewMethod->isFunctionTemplateSpecialization(); bool isFriend = NewMethod->getFriendObjectKind(); - if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) { + if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() && + !IsClassScopeExplicitSpecialization) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. @@ -1790,7 +1892,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); - llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), + SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), @@ -1799,7 +1901,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->setHasInheritedPrototype(); // Synthesize a parameter for each argument type. - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (FunctionProtoType::arg_type_iterator ParamType = OldProto->arg_type_begin(), ParamEnd = OldProto->arg_type_end(); @@ -1815,7 +1917,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Params.push_back(Param); } - New->setParams(Params.data(), Params.size()); + New->setParams(Params); } return MergeCompatibleFunctionDecls(New, Old); @@ -1836,8 +1938,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Old->hasPrototype() && !New->hasPrototype() && New->getType()->getAs<FunctionProtoType>() && Old->getNumParams() == New->getNumParams()) { - llvm::SmallVector<QualType, 16> ArgTypes; - llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings; + SmallVector<QualType, 16> ArgTypes; + SmallVector<GNUCompatibleParamWarning, 16> Warnings; const FunctionProtoType *OldProto = Old->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *NewProto @@ -1933,6 +2035,12 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { if (Old->isPure()) New->setPure(); + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) @@ -1949,15 +2057,20 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, const ObjCMethodDecl *oldMethod) { + // We don't want to merge unavailable and deprecated attributes + // except from interface to implementation. + bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext()); + // Merge the attributes. - mergeDeclAttributes(newMethod, oldMethod, Context); + mergeDeclAttributes(newMethod, oldMethod, Context, mergeDeprecation); // Merge attributes from the parameters. - for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(), + ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(); + for (ObjCMethodDecl::param_iterator ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, Context); - + CheckObjCMethodOverride(newMethod, oldMethod, true); } @@ -2111,6 +2224,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -2193,6 +2312,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Tag = dyn_cast<TagDecl>(TagD); } + if (Tag) + Tag->setFreeStanding(); + if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." @@ -2202,6 +2324,20 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << DS.getSourceRange(); } + if (DS.isConstexprSpecified()) { + // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations + // and definitions of functions and variables. + if (Tag) + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) + << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : + DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + else + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); + // Don't emit warnings after this error. + return TagD; + } + if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. @@ -2217,7 +2353,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); - if (!Record->getDeclName() && Record->isDefinition() && + if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || Record->getDeclContext()->isRecord()) @@ -2230,7 +2366,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } // Check for Microsoft C extension: anonymous struct. - if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus && + if (getLangOptions().MicrosoftExt && !getLangOptions().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Handle 2 kinds of anonymous struct: @@ -2238,7 +2374,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); - if ((Record && Record->getDeclName() && !Record->isDefinition()) || + if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || (DS.getTypeSpecType() == DeclSpec::TST_typename && DS.getRepAsType().get()->isStructureType())) { Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct) @@ -2305,6 +2441,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; + if (DS.isModulePrivateSpecified() && + Tag && Tag->getDeclContext()->isFunctionOrMethod()) + Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) + << Tag->getTagKind() + << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); + // FIXME: Warn on useless attributes return TagD; @@ -2379,7 +2521,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, AccessSpecifier AS, - llvm::SmallVector<NamedDecl*, 2> &Chaining, + SmallVector<NamedDecl*, 2> &Chaining, bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl @@ -2511,8 +2653,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; // Recover by adding 'static'. - DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), - PrevSpec, DiagID, getLangOptions()); + DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(), + PrevSpec, DiagID); } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an @@ -2524,8 +2666,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; // Recover by removing the storage specifier. - DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec, DiagID, getLangOptions()); + DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(), + PrevSpec, DiagID); } // Ignore const/volatile/restrict qualifiers. @@ -2582,7 +2724,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { // Visual C++ allows type definition in anonymous struct or union. - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); else { @@ -2606,7 +2748,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DK = diag::err_anonymous_record_with_static; // Visual C++ allows type definition in anonymous struct or union. - if (getLangOptions().Microsoft && + if (getLangOptions().MicrosoftExt && DK == diag::err_anonymous_record_with_type) Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); @@ -2665,6 +2807,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, SC, SCAsWritten); + + // Default-initialize the implicit variable. This initialization will be + // trivial in almost all cases, except if a union member has an in-class + // initializer: + // union { int n = 0; }; + ActOnUninitializedDecl(Anon, /*TypeMayContainAuto=*/false); } Anon->setImplicit(); @@ -2676,7 +2824,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - llvm::SmallVector<NamedDecl*, 2> Chain; + SmallVector<NamedDecl*, 2> Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, @@ -2740,7 +2888,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct into the current // context and into the identifier resolver chain for name lookup // purposes. - llvm::SmallVector<NamedDecl*, 2> Chain; + SmallVector<NamedDecl*, 2> Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext, @@ -2855,26 +3003,51 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { } // switch (Name.getKind()) - assert(false && "Unknown name kind"); - return DeclarationNameInfo(); + llvm_unreachable("Unknown name kind"); +} + +static QualType getCoreType(QualType Ty) { + do { + if (Ty->isPointerType() || Ty->isReferenceType()) + Ty = Ty->getPointeeType(); + else if (Ty->isArrayType()) + Ty = Ty->castAsArrayTypeUnsafe()->getElementType(); + else + return Ty.withoutLocalFastQualifiers(); + } while (true); } -/// isNearlyMatchingFunction - Determine whether the C++ functions -/// Declaration and Definition are "nearly" matching. This heuristic -/// is used to improve diagnostics in the case where an out-of-line -/// function definition doesn't match any declaration within -/// the class or namespace. -static bool isNearlyMatchingFunction(ASTContext &Context, +/// hasSimilarParameters - Determine whether the C++ functions Declaration +/// and Definition have "nearly" matching parameters. This heuristic is +/// used to improve diagnostics in the case where an out-of-line function +/// definition doesn't match any declaration within the class or namespace. +/// Also sets Params to the list of indices to the parameters that differ +/// between the declaration and the definition. If hasSimilarParameters +/// returns true and Params is empty, then all of the parameters match. +static bool hasSimilarParameters(ASTContext &Context, FunctionDecl *Declaration, - FunctionDecl *Definition) { + FunctionDecl *Definition, + llvm::SmallVectorImpl<unsigned> &Params) { + Params.clear(); if (Declaration->param_size() != Definition->param_size()) return false; for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); - if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(), - DefParamTy.getNonReferenceType())) + // The parameter types are identical + if (Context.hasSameType(DefParamTy, DeclParamTy)) + continue; + + QualType DeclParamBaseTy = getCoreType(DeclParamTy); + QualType DefParamBaseTy = getCoreType(DefParamTy); + const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier(); + const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier(); + + if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) || + (DeclTyName && DeclTyName == DefTyName)) + Params.push_back(Idx); + else // The two parameters aren't even close return false; } @@ -2900,7 +3073,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_decltype: - case DeclSpec::TST_underlyingType: { + case DeclSpec::TST_underlyingType: + case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); @@ -2955,8 +3129,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, } Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { - return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), - /*IsFunctionDefinition=*/false); + D.setFunctionDefinition(false); + return HandleDeclarator(S, D, MultiTemplateParamsArg(*this)); } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: @@ -2980,8 +3154,7 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, } Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition) { + MultiTemplateParamsArg TemplateParamLists) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -3180,22 +3353,21 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) Previous.clear(); - bool Redeclaration = false; + bool AddToScope = true; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return 0; } - New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, + New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, move(TemplateParamLists), - IsFunctionDefinition, Redeclaration); + AddToScope); } else { - New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, - move(TemplateParamLists), - Redeclaration); + New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, + move(TemplateParamLists)); } if (New == 0) @@ -3203,7 +3375,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. - if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl())) + if (New->getDeclName() && AddToScope && + !(D.isRedeclaration() && New->isInvalidDecl())) PushOnScopeChains(New, S); return New; @@ -3321,6 +3494,23 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, } } +llvm::DenseMap<DeclarationName, NamedDecl *>::iterator +Sema::findLocallyScopedExternalDecl(DeclarationName Name) { + if (ExternalSource) { + // Load locally-scoped external decls from the external source. + SmallVector<NamedDecl *, 4> Decls; + ExternalSource->ReadLocallyScopedExternalDecls(Decls); + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(Decls[I]->getDeclName()); + if (Pos == LocallyScopedExternalDecls.end()) + LocallyScopedExternalDecls[Decls[I]->getDeclName()] = Decls[I]; + } + } + + return LocallyScopedExternalDecls.find(Name); +} + /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { @@ -3341,8 +3531,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, bool &Redeclaration) { + TypeSourceInfo *TInfo, LookupResult &Previous) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) @@ -3362,6 +3551,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 1; if (D.getName().Kind != UnqualifiedId::IK_Identifier) { Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) @@ -3369,7 +3561,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, return 0; } - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo); if (!NewTD) return 0; // Handle attributes prior to checking for duplicates in MergeVarDecl @@ -3377,7 +3569,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckTypedefForVariablyModifiedType(S, NewTD); - return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); + bool Redeclaration = D.isRedeclaration(); + NamedDecl *ND = ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); + D.setRedeclaration(Redeclaration); + return ND; } void @@ -3557,10 +3752,9 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { NamedDecl* Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool &Redeclaration) { + TypeSourceInfo *TInfo, LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists) { + QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); // Check that there are no default arguments (C++ only). @@ -3585,7 +3779,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) - << Name.getAsString(); + << Name; return 0; } @@ -3606,6 +3800,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + if (getLangOptions().OpenCL) { + // Set up the special work-group-local storage class for variables in the + // OpenCL __local address space. + if (R.getAddressSpace() == LangAS::opencl_local) + SC = SC_OpenCLWorkGroupLocal; + } + bool isExplicitSpecialization = false; VarDecl *NewVD; if (!getLangOptions().CPlusPlus) { @@ -3695,20 +3896,67 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.size(), TemplateParamLists.release()); } + + if (D.getDeclSpec().isConstexprSpecified()) { + // FIXME: once we know whether there's an initializer, apply this to + // static data members too. + if (!NewVD->isStaticDataMember() && + !NewVD->isThisDeclarationADefinition()) { + // 'constexpr' is redundant and ill-formed on a non-defining declaration + // of a variable. Suggest replacing it with 'const' if appropriate. + SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc(); + SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc); + // If the declarator is complex, we need to move the keyword to the + // innermost chunk as we switch it from 'constexpr' to 'const'. + int Kind = DeclaratorChunk::Paren; + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + Kind = D.getTypeObject(I).Kind; + if (Kind != DeclaratorChunk::Paren) + break; + } + if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) || + Kind == DeclaratorChunk::Reference) + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateRemoval(ConstexprRange); + else if (Kind == DeclaratorChunk::Paren) + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateReplacement(ConstexprRange, "const"); + else + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateRemoval(ConstexprRange) + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const "); + } else { + NewVD->setConstexpr(true); + } + } } + // Set the lexical context. If the declarator has a C++ scope specifier, the + // lexical context will be different from the semantic context. + NewVD->setLexicalDeclContext(CurContext); + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); - else if (!Context.Target.isTLSSupported()) + else if (!Context.getTargetInfo().isTLSSupported()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); else NewVD->setThreadSpecified(true); } - // Set the lexical context. If the declarator has a C++ scope specifier, the - // lexical context will be different from the semantic context. - NewVD->setLexicalDeclContext(CurContext); + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (isExplicitSpecialization) + Diag(NewVD->getLocation(), diag::err_module_private_specialization) + << 2 + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else if (NewVD->hasLocalStorage()) + Diag(NewVD->getLocation(), diag::err_module_private_local) + << 0 << NewVD->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else + NewVD->setModulePrivate(); + } // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -3722,7 +3970,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - llvm::StringRef Label = SE->getString(); + StringRef Label = SE->getString(); if (S->getFnParent() != 0) { switch (SC) { case SC_None: @@ -3730,12 +3978,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; break; case SC_Register: - if (!Context.Target.isValidGCCRegisterName(Label)) + if (!Context.getTargetInfo().isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; break; case SC_Static: case SC_Extern: case SC_PrivateExtern: + case SC_OpenCLWorkGroupLocal: break; } } @@ -3754,9 +4003,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); - if (!getLangOptions().CPlusPlus) - CheckVariableDeclaration(NewVD, Previous, Redeclaration); - else { + if (!getLangOptions().CPlusPlus) { + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + } else { // Merge the decl with the existing one if appropriate. if (!Previous.empty()) { if (Previous.isSingleResult() && @@ -3777,7 +4026,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setInvalidDecl(); } - CheckVariableDeclaration(NewVD, Previous, Redeclaration); + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); // This is an explicit specialization of a static data member. Check it. if (isExplicitSpecialization && !NewVD->isInvalidDecl() && @@ -3825,7 +4074,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) == - Diagnostic::Ignored) + DiagnosticsEngine::Ignored) return; // Don't diagnose declarations at file scope. @@ -3899,7 +4148,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) == - Diagnostic::Ignored) + DiagnosticsEngine::Ignored) return; LookupResult R(*this, D->getDeclName(), D->getLocation(), @@ -3918,18 +4167,21 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { /// that have been instantiated from a template. /// /// Sets NewVD->isInvalidDecl() if an error was encountered. -void Sema::CheckVariableDeclaration(VarDecl *NewVD, - LookupResult &Previous, - bool &Redeclaration) { +/// +/// Returns true if the variable declaration is a redeclaration. +bool Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) - return; + return false; QualType T = NewVD->getType(); if (T->isObjCObjectType()) { - Diag(NewVD->getLocation(), diag::err_statically_allocated_object); - return NewVD->setInvalidDecl(); + Diag(NewVD->getLocation(), diag::err_statically_allocated_object) + << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); + T = Context.getObjCObjectPointerType(T); + NewVD->setType(T); } // Emit an error if an address space was applied to decl with local storage. @@ -3938,12 +4190,13 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // ISO/IEC TR 18037 S5.1.2 if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr<BlocksAttr>()) { - if (getLangOptions().getGCMode() != LangOptions::NonGC) + if (getLangOptions().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); else Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); @@ -3977,7 +4230,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, else Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (FixedTy.isNull()) { @@ -3985,7 +4239,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); @@ -3997,7 +4252,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // an extern "C" variable, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(NewVD->getDeclName()); + = findLocallyScopedExternalDecl(NewVD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } @@ -4005,17 +4260,20 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if (T->isVoidType() && !NewVD->hasExternalStorage()) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (isVM && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } // Function pointers and references cannot have qualified function type, only @@ -4032,13 +4290,15 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) { Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer) << PtrOrRef; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (!Previous.empty()) { - Redeclaration = true; MergeVarDecl(NewVD, Previous); + return true; } + return false; } /// \brief Data used with FindOverriddenMethod @@ -4108,233 +4368,397 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { return AddedAny; } -static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { - LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(), +namespace { + // Struct for holding all of the extra arguments needed by + // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator. + struct ActOnFDArgs { + Scope *S; + Declarator &D; + MultiTemplateParamsArg TemplateParamLists; + bool AddToScope; + }; +} + +/// \brief Generate diagnostics for an invalid function redeclaration. +/// +/// This routine handles generating the diagnostic messages for an invalid +/// function redeclaration, including finding possible similar declarations +/// or performing typo correction if there are no previous declarations with +/// the same name. +/// +/// Returns a NamedDecl iff typo correction was performed and substituting in +/// the new declaration name does not cause new errors. +static NamedDecl* DiagnoseInvalidRedeclaration( + Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD, + ActOnFDArgs &ExtraArgs) { + NamedDecl *Result = NULL; + DeclarationName Name = NewFD->getDeclName(); + DeclContext *NewDC = NewFD->getDeclContext(); + LookupResult Prev(SemaRef, Name, NewFD->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - S.LookupQualifiedName(Prev, NewFD->getDeclContext()); + llvm::SmallVector<unsigned, 1> MismatchedParams; + llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches; + TypoCorrection Correction; + bool isFriendDecl = (SemaRef.getLangOptions().CPlusPlus && + ExtraArgs.D.getDeclSpec().isFriendSpecified()); + unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend + : diag::err_member_def_does_not_match; + + NewFD->setInvalidDecl(); + SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - if (isa<FunctionDecl>(*Func) && - isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD)) - S.Diag((*Func)->getLocation(), diag::note_member_def_close_match); + if (!Prev.empty()) { + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func); + if (FD && + hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { + // Add 1 to the index so that 0 can mean the mismatch didn't + // involve a parameter + unsigned ParamNum = + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; + NearMatches.push_back(std::make_pair(FD, ParamNum)); + } + } + // If the qualified name lookup yielded nothing, try typo correction + } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(), + Prev.getLookupKind(), 0, 0, NewDC)) && + Correction.getCorrection() != Name) { + // Trap errors. + Sema::SFINAETrap Trap(SemaRef); + + // Set up everything for the call to ActOnFunctionDeclarator + ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), + ExtraArgs.D.getIdentifierLoc()); + Previous.clear(); + Previous.setLookupName(Correction.getCorrection()); + for (TypoCorrection::decl_iterator CDecl = Correction.begin(), + CDeclEnd = Correction.end(); + CDecl != CDeclEnd; ++CDecl) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl); + if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD, + MismatchedParams)) { + Previous.addDecl(FD); + } + } + bool wasRedeclaration = ExtraArgs.D.isRedeclaration(); + // TODO: Refactor ActOnFunctionDeclarator so that we can call only the + // pieces need to verify the typo-corrected C++ declaraction and hopefully + // eliminate the need for the parameter pack ExtraArgs. + Result = SemaRef.ActOnFunctionDeclarator(ExtraArgs.S, ExtraArgs.D, + NewFD->getDeclContext(), + NewFD->getTypeSourceInfo(), + Previous, + ExtraArgs.TemplateParamLists, + ExtraArgs.AddToScope); + if (Trap.hasErrorOccurred()) { + // Pretend the typo correction never occurred + ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(), + ExtraArgs.D.getIdentifierLoc()); + ExtraArgs.D.setRedeclaration(wasRedeclaration); + Previous.clear(); + Previous.setLookupName(Name); + Result = NULL; + } else { + for (LookupResult::iterator Func = Previous.begin(), + FuncEnd = Previous.end(); + Func != FuncEnd; ++Func) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) + NearMatches.push_back(std::make_pair(FD, 0)); + } + } + if (NearMatches.empty()) { + // Ignore the correction if it didn't yield any close FunctionDecl matches + Correction = TypoCorrection(); + } else { + DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest + : diag::err_member_def_does_not_match_suggest; + } } -} -NamedDecl* -Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition, bool &Redeclaration) { - assert(R.getTypePtr()->isFunctionType()); + if (Correction) + SemaRef.Diag(NewFD->getLocation(), DiagMsg) + << Name << NewDC << Correction.getQuoted(SemaRef.getLangOptions()) + << FixItHint::CreateReplacement( + NewFD->getLocation(), + Correction.getAsString(SemaRef.getLangOptions())); + else + SemaRef.Diag(NewFD->getLocation(), DiagMsg) + << Name << NewDC << NewFD->getLocation(); + + bool NewFDisConst = false; + if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) + NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const; + + for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator + NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); + NearMatch != NearMatchEnd; ++NearMatch) { + FunctionDecl *FD = NearMatch->first; + bool FDisConst = false; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + FDisConst = MD->getTypeQualifiers() & Qualifiers::Const; + + if (unsigned Idx = NearMatch->second) { + ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); + SemaRef.Diag(FDParam->getTypeSpecStartLoc(), + diag::note_member_def_close_param_match) + << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType(); + } else if (Correction) { + SemaRef.Diag(FD->getLocation(), diag::note_previous_decl) + << Correction.getQuoted(SemaRef.getLangOptions()); + } else if (FDisConst != NewFDisConst) { + SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match) + << NewFDisConst << FD->getSourceRange().getEnd(); + } else + SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match); + } + return Result; +} - // TODO: consider using NameInfo for diagnostic. - DeclarationNameInfo NameInfo = GetNameForDeclarator(D); - DeclarationName Name = NameInfo.getName(); - FunctionDecl::StorageClass SC = SC_None; +static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); + default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_typecheck_sclass_func); + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_typecheck_sclass_func); D.setInvalidType(); break; - case DeclSpec::SCS_unspecified: SC = SC_None; break; - case DeclSpec::SCS_extern: SC = SC_Extern; break; + case DeclSpec::SCS_unspecified: break; + case DeclSpec::SCS_extern: return SC_Extern; case DeclSpec::SCS_static: { - if (CurContext->getRedeclContext()->isFunctionOrMethod()) { + if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_block_func); - SC = SC_None; + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_block_func); + break; } else - SC = SC_Static; - break; + return SC_Static; } - case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break; + case DeclSpec::SCS_private_extern: return SC_PrivateExtern; } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + // No explicit storage class has already been returned + return SC_None; +} - // Do not allow returning a objc interface by-value. - if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { - Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs<FunctionType>()->getResultType(); - D.setInvalidType(); - } - - FunctionDecl *NewFD; +static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, + DeclContext *DC, QualType &R, + TypeSourceInfo *TInfo, + FunctionDecl::StorageClass SC, + bool &IsVirtualOkay) { + DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + + FunctionDecl *NewFD = 0; bool isInline = D.getDeclSpec().isInlineSpecified(); - bool isFriend = false; DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); FunctionDecl::StorageClass SCAsWritten = StorageClassSpecToFunctionDeclStorageClass(SCSpec); - FunctionTemplateDecl *FunctionTemplate = 0; - bool isExplicitSpecialization = false; - bool isFunctionTemplateSpecialization = false; - if (!getLangOptions().CPlusPlus) { + if (!SemaRef.getLangOptions().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other reference // to a type name (which eventually refers to a function type). bool HasPrototype = - (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || - (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); + + NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); if (D.isInvalidType()) NewFD->setInvalidDecl(); - + // Set the lexical context. - NewFD->setLexicalDeclContext(CurContext); - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - /*ExplicitInstantiationOrSpecialization=*/false); - } else { - isFriend = D.getDeclSpec().isFriendSpecified(); - bool isVirtual = D.getDeclSpec().isVirtualSpecified(); - bool isExplicit = D.getDeclSpec().isExplicitSpecified(); - bool isVirtualOkay = false; - - // Check that the return type is not an abstract class type. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!DC->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), - R->getAs<FunctionType>()->getResultType(), - diag::err_abstract_type_in_decl, - AbstractReturnType)) - D.setInvalidType(); + NewFD->setLexicalDeclContext(SemaRef.CurContext); - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { - // This is a C++ constructor declaration. - assert(DC->isRecord() && - "Constructors can only be declared in a member context"); - - R = CheckConstructorDeclarator(D, R, SC); - - // Create the new declaration - CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( - Context, - cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isExplicit, isInline, - /*isImplicitlyDeclared=*/false); - - NewFD = NewCD; - } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - // This is a C++ destructor declaration. - if (DC->isRecord()) { - R = CheckDestructorDeclarator(D, R, SC); - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - - CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record, - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, - /*isImplicitlyDeclared=*/false); - NewFD = NewDD; - isVirtualOkay = true; - - // If the class is complete, then we now create the implicit exception - // specification. If the class is incomplete or dependent, we can't do - // it yet. - if (getLangOptions().CPlusPlus0x && !Record->isDependentType() && - Record->getDefinition() && !Record->isBeingDefined() && - R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { - AdjustDestructorExceptionSpec(Record, NewDD); - } + return NewFD; + } - } else { - Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - - // Create a FunctionDecl to satisfy the function definition parsing - // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - D.getIdentifierLoc(), Name, R, TInfo, - SC, SCAsWritten, isInline, - /*hasPrototype=*/true); - D.setInvalidType(); - } - } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - if (!DC->isRecord()) { - Diag(D.getIdentifierLoc(), - diag::err_conv_function_not_member); - return 0; - } + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); + + // Check that the return type is not an abstract class type. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + SemaRef.RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs<FunctionType>()->getResultType(), + diag::err_abstract_type_in_decl, + SemaRef.AbstractReturnType)) + D.setInvalidType(); - CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = SemaRef.CheckConstructorDeclarator(D, R, SC); + return CXXConstructorDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isExplicit, isInline, + /*isImplicitlyDeclared=*/false, + isConstexpr); + + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = SemaRef.CheckDestructorDeclarator(D, R, SC); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( + SemaRef.Context, Record, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, isExplicit, - SourceLocation()); - - isVirtualOkay = true; - } else if (DC->isRecord()) { - // If the of the function is the same as the name of the record, then this - // must be an invalid constructor that has a return type. - // (The parser checks for a return type and makes the declarator a - // constructor if it has no return type). - // must have an invalid constructor that has a return type - if (Name.getAsIdentifierInfo() && - Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ - Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) - << SourceRange(D.getIdentifierLoc()); - return 0; + NameInfo, R, TInfo, isInline, + /*isImplicitlyDeclared=*/false); + + // If the class is complete, then we now create the implicit exception + // specification. If the class is incomplete or dependent, we can't do + // it yet. + if (SemaRef.getLangOptions().CPlusPlus0x && !Record->isDependentType() && + Record->getDefinition() && !Record->isBeingDefined() && + R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { + SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); } - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - // This is a C++ method declaration. - CXXMethodDecl *NewMD = CXXMethodDecl::Create( - Context, cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); - NewFD = NewMD; - - isVirtualOkay = !isStatic; + IsVirtualOkay = true; + return NewDD; + } else { - // Determine whether the function was written with a - // prototype. This true when: - // - we're in C++ (where every function has a prototype), - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, SC, SCAsWritten, isInline, - true/*HasPrototype*/); + SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); + D.setInvalidType(); + + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), Name, R, TInfo, + SC, SCAsWritten, isInline, + /*hasPrototype=*/true, isConstexpr); + } + + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + if (!DC->isRecord()) { + SemaRef.Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } + + SemaRef.CheckConversionDeclarator(D, R, SC); + IsVirtualOkay = true; + return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isInline, isExplicit, + isConstexpr, SourceLocation()); + + } else if (DC->isRecord()) { + // If the name of the function is the same as the name of the record, + // then this must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a + // constructor if it has no return type). + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + return 0; + } + + bool isStatic = SC == SC_Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + + IsVirtualOkay = !isStatic; + + // This is a C++ method declaration. + return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, + TInfo, isStatic, SCAsWritten, isInline, + isConstexpr, SourceLocation()); + + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + true/*HasPrototype*/, isConstexpr); + } +} + +NamedDecl* +Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, + TypeSourceInfo *TInfo, LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope) { + QualType R = TInfo->getType(); + + assert(R.getTypePtr()->isFunctionType()); + + // TODO: consider using NameInfo for diagnostic. + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + // Do not allow returning a objc interface by-value. + if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { + Diag(D.getIdentifierLoc(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 + << R->getAs<FunctionType>()->getResultType() + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); + + QualType T = R->getAs<FunctionType>()->getResultType(); + T = Context.getObjCObjectPointerType(T); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + R = Context.getFunctionType(T, FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); } + else if (isa<FunctionNoProtoType>(R)) + R = Context.getFunctionNoProtoType(T); + } + + bool isFriend = false; + FunctionTemplateDecl *FunctionTemplate = 0; + bool isExplicitSpecialization = false; + bool isFunctionTemplateSpecialization = false; + bool isDependentClassScopeExplicitSpecialization = false; + bool isVirtualOkay = false; - if (isFriend && !isInline && IsFunctionDefinition) { + FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, + isVirtualOkay); + if (!NewFD) return 0; + + if (getLangOptions().CPlusPlus) { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); + isFriend = D.getDeclSpec().isFriendSpecified(); + if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. @@ -4377,6 +4801,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(NewFD->getLocation(), diag::err_destructor_template); return 0; } + + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (DC->isDependentContext()) { + ContextRAII SavedContext(*this, DC); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), @@ -4437,7 +4871,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } - + // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a @@ -4474,7 +4908,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } } - + // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; see 12.3.1 @@ -4495,10 +4929,32 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - isExplicitSpecialization || - isFunctionTemplateSpecialization); + if (isConstexpr) { + // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors + // are implicitly inline. + NewFD->setImplicitlyInline(); + + // C++0x [dcl.constexpr]p3: functions declared constexpr are required to + // be either constructors or to return a literal type. Therefore, + // destructors cannot be declared constexpr. + if (isa<CXXDestructorDecl>(NewFD)) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor); + } + + // If __module_private__ was specified, mark the function accordingly. + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (isFunctionTemplateSpecialization) { + SourceLocation ModulePrivateLoc + = D.getDeclSpec().getModulePrivateSpecLoc(); + Diag(ModulePrivateLoc, diag::err_module_private_specialization) + << 0 + << FixItHint::CreateRemoval(ModulePrivateLoc); + } else { + NewFD->setModulePrivate(); + if (FunctionTemplate) + FunctionTemplate->setModulePrivate(); + } + } if (isFriend) { // For now, claim that the objects have no previous declaration. @@ -4510,7 +4966,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setAccess(AS_public); } - if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) { + if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && + D.isFunctionDefinition()) { // A method is implicitly inline if it's defined in its class // definition. NewFD->setImplicitlyInline(); @@ -4530,6 +4987,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } } + + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), + isExplicitSpecialization || + isFunctionTemplateSpecialization); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { @@ -4541,7 +5003,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; if (D.isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); @@ -4603,8 +5065,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && "Should not need args for typedef of non-prototype fn"); } + // Finally, we know we have the right number of parameters, install them. - NewFD->setParams(Params.data(), Params.size()); + NewFD->setParams(Params); // Process the non-inheritable attributes on this declaration. ProcessDeclAttributes(S, NewFD, D, @@ -4613,9 +5076,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!getLangOptions().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplicitSpecialization=false; - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration); - assert((NewFD->isInvalidDecl() || !Redeclaration || + if (!NewFD->isInvalidDecl()) { + if (NewFD->getResultType()->isVariablyModifiedType()) { + // Functions returning a variably modified type violate C99 6.7.5.2p2 + // because all functions have linkage. + Diag(NewFD->getLocation(), diag::err_vm_func_decl); + NewFD->setInvalidDecl(); + } else { + if (NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isExplicitSpecialization)); + } + } + assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); } else { @@ -4676,8 +5150,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // that either the specialized function type or the specialized // template is dependent, and therefore matching will fail. In // this case, don't check the specialization yet. + bool InstantiationDependent = false; if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + (NewFD->getType()->isDependentType() || DC->isDependentContext() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs.getArgumentArray(), TemplateArgs.size(), + InstantiationDependent))) { assert(HasExplicitTemplateArgs && "friend function specialization without template args"); if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, @@ -4686,10 +5164,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } else if (isFunctionTemplateSpecialization) { if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { - Diag(NewFD->getLocation(), diag::err_function_specialization_in_class) + isDependentClassScopeExplicitSpecialization = true; + Diag(NewFD->getLocation(), getLangOptions().MicrosoftExt ? + diag::ext_function_specialization_in_class : + diag::err_function_specialization_in_class) << NewFD->getDeclName(); - NewFD->setInvalidDecl(); - return 0; } else if (CheckFunctionTemplateSpecialization(NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) @@ -4719,18 +5198,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Perform semantic checking on the function declaration. - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration); + if (!isDependentClassScopeExplicitSpecialization) { + if (NewFD->isInvalidDecl()) { + // If this is a class member, mark the class invalid immediately. + // This avoids some consistency errors later. + if (CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(NewFD)) + methodDecl->getParent()->setInvalidDecl(); + } else { + if (NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isExplicitSpecialization)); + } + } - assert((NewFD->isInvalidDecl() || !Redeclaration || + assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() && + !CheckConstexprFunctionDecl(NewFD, CCK_Declaration)) + NewFD->setInvalidDecl(); + NamedDecl *PrincipalDecl = (FunctionTemplate ? cast<NamedDecl>(FunctionTemplate) : NewFD); - if (isFriend && Redeclaration) { + if (isFriend && D.isRedeclaration()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDeclaration()->getAccess(); @@ -4752,7 +5246,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), PrevTemplate? PrevTemplate->getTemplateParameters() : 0, D.getDeclSpec().isFriendSpecified() - ? (IsFunctionDefinition + ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition : TPC_FriendFunctionTemplate) : (D.getCXXScopeSpec().isSet() && @@ -4764,7 +5258,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewFD->isInvalidDecl()) { // Ignore all the rest of this. - } else if (!Redeclaration) { + } else if (!D.isRedeclaration()) { + struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, + AddToScope }; // Fake up an access specifier if it's supposed to be a class member. if (isa<CXXRecordDecl>(NewFD->getDeclContext())) NewFD->setAccess(AS_public); @@ -4784,38 +5280,43 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, (TemplateParamLists.size() || D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { - // ignore these - } else { - // The user tried to provide an out-of-line definition for a - // function that is a member of a class or namespace, but there - // was no such member function declared (C++ [class.mfct]p2, - // C++ [namespace.memdef]p2). For example: - // - // class X { - // void f() const; - // }; - // - // void X::f() { } // ill-formed - // - // Complain about this problem, and attempt to suggest close - // matches (e.g., those that differ only in cv-qualifiers and - // whether the parameter types are references). - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << Name << DC << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - - DiagnoseInvalidRedeclaration(*this, NewFD); - } + // ignore these + } else { + // The user tried to provide an out-of-line definition for a + // function that is a member of a class or namespace, but there + // was no such member function declared (C++ [class.mfct]p2, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // matches (e.g., those that differ only in cv-qualifiers and + // whether the parameter types are references). + + if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous, + NewFD, + ExtraArgs)) { + AddToScope = ExtraArgs.AddToScope; + return Result; + } + } // Unqualified local friend declarations are required to resolve // to something. - } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { - Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend); - NewFD->setInvalidDecl(); - DiagnoseInvalidRedeclaration(*this, NewFD); + } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { + if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous, + NewFD, + ExtraArgs)) { + AddToScope = ExtraArgs.AddToScope; + return Result; } + } - } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && + } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { // An out-of-line member function declaration must also be a @@ -4839,7 +5340,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging - if (Redeclaration && Previous.isSingleResult()) { + if (D.isRedeclaration() && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl()); if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { @@ -4871,6 +5372,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewFD); + // If there's a #pragma clang arc_cf_code_audited in scope, consider + // marking the function. + AddCFAuditedAttribute(NewFD); + // If this is a locally-scoped extern C function, update the // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC() @@ -4901,6 +5406,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Context.setcudaConfigureCallDecl(NewFD); } } + + // Here we have an function template explicit specialization at class scope. + // The actually specialization will be postponed to template instatiation + // time via the ClassScopeFunctionSpecializationDecl node. + if (isDependentClassScopeExplicitSpecialization) { + ClassScopeFunctionSpecializationDecl *NewSpec = + ClassScopeFunctionSpecializationDecl::Create( + Context, CurContext, SourceLocation(), + cast<CXXMethodDecl>(NewFD)); + CurContext->addDecl(NewSpec); + AddToScope = false; + } return NewFD; } @@ -4919,29 +5436,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, +/// +/// Returns true if the function declaration is a redeclaration. +bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, - bool IsExplicitSpecialization, - bool &Redeclaration) { - // If NewFD is already known erroneous, don't do any of this checking. - if (NewFD->isInvalidDecl()) { - // If this is a class member, mark the class invalid immediately. - // This avoids some consistency errors later. - if (isa<CXXMethodDecl>(NewFD)) - cast<CXXMethodDecl>(NewFD)->getParent()->setInvalidDecl(); - - return; - } - - if (NewFD->getResultType()->isVariablyModifiedType()) { - // Functions returning a variably modified type violate C99 6.7.5.2p2 - // because all functions have linkage. - Diag(NewFD->getLocation(), diag::err_vm_func_decl); - return NewFD->setInvalidDecl(); - } - - if (NewFD->isMain()) - CheckMain(NewFD); + bool IsExplicitSpecialization) { + assert(!NewFD->getResultType()->isVariablyModifiedType() + && "Variably modified return types are not handled here"); // Check for a previous declaration of this name. if (Previous.empty() && NewFD->isExternC()) { @@ -4949,11 +5450,13 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // an extern "C" function, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(NewFD->getDeclName()); + = findLocallyScopedExternalDecl(NewFD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } + bool Redeclaration = false; + // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. if (!Previous.empty()) { @@ -5003,8 +5506,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. - if (MergeFunctionDecl(NewFD, OldDecl)) - return NewFD->setInvalidDecl(); + if (MergeFunctionDecl(NewFD, OldDecl)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } Previous.clear(); Previous.addDecl(OldDecl); @@ -5028,6 +5533,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); } + + if (OldTemplateDecl->isModulePrivate()) + NewTemplateDecl->setModulePrivate(); + } else { if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions NewFD->setAccess(OldDecl->getAccess()); @@ -5054,7 +5563,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Context.getCanonicalType(ClassType)); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); - return NewFD->setInvalidDecl(); + NewFD->setInvalidDecl(); + return Redeclaration; } } } else if (CXXConversionDecl *Conversion @@ -5086,13 +5596,17 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && - CheckOverloadedOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); + CheckOverloadedOperatorDeclaration(NewFD)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } // Extra checking for C++0x literal operators (C++0x [over.literal]). if (NewFD->getLiteralIdentifier() && - CheckLiteralOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); + CheckLiteralOperatorDeclaration(NewFD)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done @@ -5112,24 +5626,22 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + return Redeclaration; } -void Sema::CheckMain(FunctionDecl* FD) { +void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // C++ [basic.start.main]p3: A program that declares main to be inline // or static is ill-formed. // C99 6.7.4p4: In a hosted environment, the inline function specifier // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. - bool isInline = FD->isInlineSpecified(); - bool isStatic = FD->getStorageClass() == SC_Static; - if (isInline || isStatic) { - unsigned diagID = diag::warn_unusual_main_decl; - if (isInline || getLangOptions().CPlusPlus) - diagID = diag::err_unusual_main_decl; - - int which = isStatic + (isInline << 1) - 1; - Diag(FD->getLocation(), diagID) << which; - } + if (FD->getStorageClass() == SC_Static) + Diag(DS.getStorageClassSpecLoc(), getLangOptions().CPlusPlus + ? diag::err_static_main : diag::warn_static_main) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + if (FD->isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_main) + << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); @@ -5152,7 +5664,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // Darwin passes an undocumented fourth argument of type char**. If // other platforms start sprouting these, the logic below will start // getting shifty. - if (nparams == 4 && Context.Target.getTriple().isOSDarwin()) + if (nparams == 4 && Context.getTargetInfo().getTriple().isOSDarwin()) HasExtraParameters = false; if (HasExtraParameters) { @@ -5231,41 +5743,89 @@ namespace { : public EvaluatedExprVisitor<SelfReferenceChecker> { Sema &S; Decl *OrigDecl; + bool isRecordType; + bool isPODType; public: typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), - S(S), OrigDecl(OrigDecl) { } + S(S), OrigDecl(OrigDecl) { + isPODType = false; + isRecordType = false; + if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) { + isPODType = VD->getType().isPODType(S.Context); + isRecordType = VD->getType()->isRecordType(); + } + } void VisitExpr(Expr *E) { if (isa<ObjCMessageExpr>(*E)) return; + if (isRecordType) { + Expr *expr = E; + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + ValueDecl *VD = ME->getMemberDecl(); + if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return; + expr = ME->getBase(); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) { + HandleDeclRefExpr(DRE); + return; + } + } Inherited::VisitExpr(E); } + void VisitMemberExpr(MemberExpr *E) { + if (E->getType()->canDecayToPointerType()) return; + if (isa<FieldDecl>(E->getMemberDecl())) + if (DeclRefExpr *DRE + = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) { + HandleDeclRefExpr(DRE); + return; + } + Inherited::VisitMemberExpr(E); + } + void VisitImplicitCastExpr(ImplicitCastExpr *E) { - CheckForSelfReference(E); + if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) || + (isRecordType && E->getCastKind() == CK_NoOp)) { + Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr)) + SubExpr = ME->getBase()->IgnoreParenImpCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + HandleDeclRefExpr(DRE); + return; + } + } Inherited::VisitImplicitCastExpr(E); } - void CheckForSelfReference(ImplicitCastExpr *E) { - if (E->getCastKind() != CK_LValueToRValue) return; - Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr); - if (!DRE) return; - Decl* ReferenceDecl = DRE->getDecl(); + void VisitUnaryOperator(UnaryOperator *E) { + // For POD record types, addresses of its own members are well-defined. + if (isRecordType && isPODType) return; + Inherited::VisitUnaryOperator(E); + } + + void HandleDeclRefExpr(DeclRefExpr *DRE) { + Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, Sema::NotForRedeclaration); - S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr, + S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() + << Result.getLookupName() << OrigDecl->getLocation() - << SubExpr->getSourceRange()); + << DRE->getSourceRange()); } }; } +/// CheckSelfReference - Warns if OrigDecl is used in expression E. +void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { + SelfReferenceChecker(*this, OrigDecl).VisitExpr(E); +} + /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -5281,10 +5841,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Variables declared within a function/method body are handled // by a dataflow analysis. if (!vd->hasLocalStorage() && !vd->isStaticLocal()) - SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + CheckSelfReference(RealDecl, Init); } else { - SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + CheckSelfReference(RealDecl, Init); } if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { @@ -5392,6 +5952,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } } + // OpenCL 1.1 6.5.2: "Variables allocated in the __local address space inside + // a kernel function cannot be initialized." + if (VDecl->getStorageClass() == SC_OpenCLWorkGroupLocal) { + Diag(VDecl->getLocation(), diag::err_local_cant_init); + VDecl->setInvalidDecl(); + return; + } + // Capture the variable that is being initialized and the style of // initialization. InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); @@ -5456,11 +6024,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // A member-declarator can contain a constant-initializer only // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. + // + // C++0x [class.static.data]p3: + // If a non-volatile const static data member is of integral or + // enumeration type, its declaration in the class definition can + // specify a brace-or-equal-initializer in which every initalizer-clause + // that is an assignment-expression is a constant expression. A static + // data member of literal type can be declared in the class definition + // with the constexpr specifier; if so, its declaration shall specify a + // brace-or-equal-initializer in which every initializer-clause that is + // an assignment-expression is a constant expression. QualType T = VDecl->getType(); // Do nothing on dependent types. if (T->isDependentType()) { + // Allow any 'static constexpr' members, whether or not they are of literal + // type. We separately check that the initializer is a constant expression, + // which implicitly requires the member to be of literal type. + } else if (VDecl->isConstexpr()) { + // Require constness. } else if (!T.isConstQualified()) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) @@ -5471,7 +6054,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } else if (T->isIntegralOrEnumerationType()) { // Check whether the expression is a constant expression. SourceLocation Loc; - if (Init->isValueDependent()) + if (getLangOptions().CPlusPlus0x && T.isVolatileQualified()) + // In C++0x, a non-constexpr const static data member with an + // in-class initializer cannot be volatile. + Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile); + else if (Init->isValueDependent()) ; // Nothing to check. else if (Init->isIntegerConstantExpr(Context, &Loc)) ; // Ok, it's an ICE! @@ -5488,31 +6075,33 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); } - // We allow floating-point constants as an extension in C++03, and - // C++0x has far more complicated rules that we don't really - // implement fully. - } else { - bool Allowed = false; - if (getLangOptions().CPlusPlus0x) { - Allowed = T->isLiteralType(); - } else if (T->isFloatingType()) { // also permits complex, which is ok - Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) - << T << Init->getSourceRange(); - Allowed = true; - } - - if (!Allowed) { - Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) - << T << Init->getSourceRange(); - VDecl->setInvalidDecl(); - - // TODO: there are probably expressions that pass here that shouldn't. - } else if (!Init->isValueDependent() && - !Init->isConstantInitializer(Context, false)) { + // We allow floating-point constants as an extension. + } else if (T->isFloatingType()) { // also permits complex, which is ok + Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) + << T << Init->getSourceRange(); + if (getLangOptions().CPlusPlus0x) + Diag(VDecl->getLocation(), + diag::note_in_class_initializer_float_type_constexpr) + << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); + + if (!Init->isValueDependent() && + !Init->isConstantInitializer(Context, false)) { Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } + + // Suggest adding 'constexpr' in C++0x for literal types. + } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) + << T << Init->getSourceRange() + << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); + VDecl->setConstexpr(true); + + } else { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) + << T << Init->getSourceRange(); + VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { if (VDecl->getStorageClassAsWritten() == SC_Extern && @@ -5547,33 +6136,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setType(DclT); Init->setType(DclT); } - - - // If this variable is a local declaration with record type, make sure it - // doesn't have a flexible member initialization. We only support this as a - // global/static definition. - if (VDecl->hasLocalStorage()) - if (const RecordType *RT = VDecl->getType()->getAs<RecordType>()) - if (RT->getDecl()->hasFlexibleArrayMember()) { - // Check whether the initializer tries to initialize the flexible - // array member itself to anything other than an empty initializer list. - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - unsigned Index = std::distance(RT->getDecl()->field_begin(), - RT->getDecl()->field_end()) - 1; - if (Index < ILE->getNumInits() && - !(isa<InitListExpr>(ILE->getInit(Index)) && - cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) { - Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable); - VDecl->setInvalidDecl(); - } - } - } // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); if (!VDecl->isInvalidDecl()) checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + + if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() && + !VDecl->getType()->isDependentType() && + !Init->isTypeDependent() && !Init->isValueDependent() && + !Init->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) { + // FIXME: Improve this diagnostic to explain why the initializer is not + // a constant expression. + Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init) + << VDecl << Init->getSourceRange(); + } Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. @@ -5639,6 +6218,21 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } + // C++0x [dcl.constexpr]p9: An object or reference declared constexpr must + // have an initializer. + // C++0x [class.static.data]p3: A static data member can be declared with + // the constexpr specifier; if so, its declaration shall specify + // a brace-or-equal-initializer. + // + // A static data member's definition may inherit an initializer from an + // in-class declaration. + if (Var->isConstexpr() && !Var->getAnyInitializer()) { + Diag(Var->getLocation(), diag::err_constexpr_var_requires_init) + << Var->getDeclName(); + Var->setInvalidDecl(); + return; + } + switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) @@ -5829,10 +6423,11 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) { case SC_Register: Error = 4; break; + case SC_OpenCLWorkGroupLocal: + llvm_unreachable("Unexpected storage class"); } - // FIXME: constexpr isn't allowed here. - //if (DS.isConstexprSpecified()) - // Error = 5; + if (VD->isConstexpr()) + Error = 5; if (Error != -1) { Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) << VD->getDeclName() << Error; @@ -5916,7 +6511,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { - llvm::SmallVector<Decl*, 8> Decls; + SmallVector<Decl*, 8> Decls; if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); @@ -5996,6 +6591,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 0; DiagnoseFunctionSpecifiers(D); @@ -6074,6 +6672,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ProcessDeclAttributes(S, New, D); + if (D.getDeclSpec().isModulePrivateSpecified()) + Diag(New->getLocation(), diag::err_module_private_local) + << 1 << New->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + if (New->hasAttr<BlocksAttr>()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } @@ -6157,8 +6761,9 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // - otherwise, it's an error if (T->isArrayType()) { if (!T.isConstQualified()) { - Diag(NameLoc, diag::err_arc_array_param_no_ownership) - << TSInfo->getTypeLoc().getSourceRange(); + DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType( + NameLoc, diag::err_arc_array_param_no_ownership, T, false)); } lifetime = Qualifiers::OCL_ExplicitNone; } else { @@ -6185,8 +6790,10 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // passed by reference. if (T->isObjCObjectType()) { Diag(NameLoc, - diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; - New->setInvalidDecl(); + diag::err_object_cannot_be_passed_returned_by_value) << 1 << T + << FixItHint::CreateInsertion(NameLoc, "*"); + T = Context.getObjCObjectPointerType(T); + New->setType(T); } // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage @@ -6241,9 +6848,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); + D.setFunctionDefinition(true); Decl *DP = HandleDeclarator(ParentScope, D, - MultiTemplateParamsArg(*this), - /*IsFunctionDefinition=*/true); + MultiTemplateParamsArg(*this)); return ActOnStartOfFunctionDef(FnBodyScope, DP); } @@ -6379,7 +6986,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // dllimport attribute cannot be directly applied to definition. // Microsoft accepts dllimport for functions defined within class scope. if (!DA->isInherited() && - !(LangOpts.Microsoft && FD->getLexicalDeclContext()->isRecord())) { + !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) << "dllimport"; @@ -6389,7 +6996,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Visual C++ appears to not think this is an issue, so only issue // a warning when Microsoft extensions are disabled. - if (!LangOpts.Microsoft) { + if (!LangOpts.MicrosoftExt) { // If a symbol previously declared dllimport is later defined, the // attribute is ignored in subsequent references, and a warning is // emitted. @@ -6417,7 +7024,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { /// FIXME: Employ a smarter algorithm that accounts for multiple return /// statements and the lifetimes of the NRVO candidates. We should be able to /// find a maximal set of NRVO variables. -static void ComputeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { +void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { ReturnStmt **Returns = Scope->Returns.data(); const VarDecl *NRVOCandidate = 0; @@ -6466,7 +7073,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // MSVC permits the use of pure specifier (=0) on function definition, // defined at class scope, warn about this non standard construct. - if (getLangOptions().Microsoft && FD->isPure()) + if (getLangOptions().MicrosoftExt && FD->isPure()) Diag(FD->getLocation(), diag::warn_pure_function_definition); if (!FD->isInvalidDecl()) { @@ -6478,7 +7085,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - ComputeNRVO(Body, getCurFunction()); + computeNRVO(Body, getCurFunction()); } assert(FD == getCurFunctionDecl() && "Function parsing confused"); @@ -6491,11 +7098,27 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), MD->getResultType(), MD); + + if (Body) + computeNRVO(Body, getCurFunction()); + } + if (ObjCShouldCallSuperDealloc) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); + ObjCShouldCallSuperDealloc = false; + } + if (ObjCShouldCallSuperFinalize) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize); + ObjCShouldCallSuperFinalize = false; } } else { return 0; } + assert(!ObjCShouldCallSuperDealloc && "This should only be set for " + "ObjC methods, which should have been handled in the block above."); + assert(!ObjCShouldCallSuperFinalize && "This should only be set for " + "ObjC methods, which should have been handled in the block above."); + // Verify and clean out per-function state. if (Body) { // C++ constructors that have function-try-blocks can't have return @@ -6504,8 +7127,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); - // Verify that that gotos and switch cases don't jump into scopes illegally. - // Verify that that gotos and switch cases don't jump into scopes illegally. + // Verify that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !dcl->isInvalidDecl() && !hasAnyUnrecoverableErrorsInThisFunction()) @@ -6532,6 +7154,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, ActivePolicy = &WP; } + if (FD && FD->isConstexpr() && !FD->isInvalidDecl() && + !CheckConstexprFunctionBody(FD, Body)) + FD->setInvalidDecl(); + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); } @@ -6552,6 +7178,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, return dcl; } + +/// When we finish delayed parsing of an attribute, we must attach it to the +/// relevant Decl. +void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, + ParsedAttributes &Attrs) { + ProcessDeclAttributeList(S, D, Attrs.getList()); +} + + /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, @@ -6561,7 +7196,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(&II); + = findLocallyScopedExternalDecl(&II); if (Pos != LocallyScopedExternalDecls.end()) { Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; Diag(Pos->second->getLocation(), diag::note_previous_declaration); @@ -6651,6 +7286,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } + if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && + !FD->getAttr<ReturnsTwiceAttr>()) + FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>()) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>()) @@ -6712,6 +7350,16 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (CurContext->isFunctionOrMethod()) + Diag(NewTD->getLocation(), diag::err_module_private_local) + << 2 << NewTD->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else + NewTD->setModulePrivate(); + } + // C++ [dcl.typedef]p8: // If the typedef declaration defines an unnamed class (or // enum), the first typedef-name declared by the declaration @@ -6853,6 +7501,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, bool ScopedEnum, bool ScopedEnumUsesClassTag, @@ -6892,6 +7541,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, TemplateParams, AS, + ModulePrivateLoc, TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); return Result.get(); @@ -6934,7 +7584,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); - } else if (getLangOptions().Microsoft) + } else if (getLangOptions().MicrosoftExt) // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); } @@ -7233,7 +7883,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || - getLangOptions().Microsoft)) || TUK == TUK_Friend) + getLangOptions().MicrosoftExt)) || TUK == TUK_Friend) return PrevTagDecl; // Diagnose attempts to redefine a tag. @@ -7385,7 +8035,7 @@ CreateNewDecl: Diag(Def->getLocation(), diag::note_previous_definition); } else { unsigned DiagID = diag::ext_forward_ref_enum; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::ext_ms_forward_ref_enum; else if (getLangOptions().CPlusPlus) DiagID = diag::err_forward_ref_enum; @@ -7454,6 +8104,23 @@ CreateNewDecl: AddMsStructLayoutForRecord(RD); } + if (PrevDecl && PrevDecl->isModulePrivate()) + New->setModulePrivate(); + else if (ModulePrivateLoc.isValid()) { + if (isExplicitSpecialization) + Diag(New->getLocation(), diag::err_module_private_specialization) + << 2 + << FixItHint::CreateRemoval(ModulePrivateLoc); + else if (PrevDecl && !PrevDecl->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, PrevDecl, ModulePrivateLoc); + // __module_private__ does not apply to local classes. However, we only + // diagnose this as an error when the declaration specifiers are + // freestanding. Here, we just ignore the __module_private__. + // foobar + else if (!SearchDC->isFunctionOrMethod()) + New->setModulePrivate(); + } + // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) @@ -7480,7 +8147,7 @@ CreateNewDecl: // the tag name visible. if (TUK == TUK_Friend) New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() || - getLangOptions().Microsoft); + getLangOptions().MicrosoftExt); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) @@ -7530,6 +8197,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { PushDeclContext(S, Tag); } +Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { + assert(isa<ObjCContainerDecl>(IDecl) && + "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); + DeclContext *OCD = cast<DeclContext>(IDecl); + assert(getContainingDC(OCD) == CurContext && + "The next DeclContext should be lexically contained in the current one."); + CurContext = OCD; + return IDecl; +} + void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation FinalLoc, SourceLocation LBraceLoc) { @@ -7581,6 +8258,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, Consumer.HandleTagDeclDefinition(Tag); } +void Sema::ActOnObjCContainerFinishDefinition() { + // Exit this scope of this interface definition. + PopDeclContext(); +} + +void Sema::ActOnObjCTemporaryExitContainerContext() { + OriginalLexicalContext = CurContext; + ActOnObjCContainerFinishDefinition(); +} + +void Sema::ActOnObjCReenterContainerContext() { + ActOnObjCContainerStartDefinition(cast<Decl>(OriginalLexicalContext)); + OriginalLexicalContext = 0; +} + void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD); @@ -7669,7 +8361,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { + Declarator &D, Expr *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD), DeclStart, D, static_cast<Expr*>(BitfieldWidth), /*HasInit=*/false, AS_public); @@ -7703,6 +8395,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 2; // Check to see if this name was declared as a member previously LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); @@ -7735,6 +8430,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); + if (D.getDeclSpec().isModulePrivateSpecified()) + NewFD->setModulePrivate(); + if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -7968,8 +8666,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } } - assert(0 && "found no user-declared constructors"); - return; + llvm_unreachable("found no user-declared constructors"); } break; @@ -8054,7 +8751,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXDestructor: hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break; default: - assert(0 && "unexpected special member"); return; + llvm_unreachable("unexpected special member"); } // Check for nontrivial bases (and recurse). @@ -8102,7 +8799,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } } - assert(0 && "found no explanation for non-trivial member"); + llvm_unreachable("found no explanation for non-trivial member"); } /// TranslateIvarVisibility - Translate visibility from a token ID to an @@ -8110,7 +8807,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { static ObjCIvarDecl::AccessControl TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { switch (ivarVisibility) { - default: assert(0 && "Unknown visitibility kind"); + default: llvm_unreachable("Unknown visitibility kind"); case tok::objc_private: return ObjCIvarDecl::Private; case tok::objc_public: return ObjCIvarDecl::Public; case tok::objc_protected: return ObjCIvarDecl::Protected; @@ -8122,8 +8819,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { /// in order to create an IvarDecl object for it. Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, - Decl *IntfDecl, - Declarator &D, ExprTy *BitfieldWidth, + Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind Visibility) { IdentifierInfo *II = D.getIdentifier(); @@ -8165,7 +8861,7 @@ Decl *Sema::ActOnIvar(Scope *S, Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. - ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(IntfDecl); + ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(CurContext); ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { @@ -8213,6 +8909,9 @@ Decl *Sema::ActOnIvar(Scope *S, if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID)) NewID->setInvalidDecl(); + if (D.getDeclSpec().isModulePrivateSpecified()) + NewID->setModulePrivate(); + if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. @@ -8227,23 +8926,19 @@ Decl *Sema::ActOnIvar(Scope *S, /// class and class extensions. For every class @interface and class /// extension @interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. -void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, - llvm::SmallVectorImpl<Decl *> &AllIvarDecls) { +void Sema::ActOnLastBitfield(SourceLocation DeclLoc, + SmallVectorImpl<Decl *> &AllIvarDecls) { if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty()) return; Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl); - if (!Ivar->isBitField()) - return; - uint64_t BitFieldSize = - Ivar->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); - if (BitFieldSize == 0) + if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) return; - ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl); + ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext); if (!ID) { - if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CurContext)) { if (!CD->IsClassExtension()) return; } @@ -8252,13 +8947,14 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, return; } // All conditions are met. Add a new bitfield to the tail end of ivars. - llvm::APInt Zero(Context.getTypeSize(Context.CharTy), 0); - Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc); + llvm::APInt Zero(Context.getTypeSize(Context.IntTy), 0); + Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc); - Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl), + Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext), DeclLoc, DeclLoc, 0, Context.CharTy, - Context.CreateTypeSourceInfo(Context.CharTy), + Context.getTrivialTypeSourceInfo(Context.CharTy, + DeclLoc), ObjCIvarDecl::Private, BW, true); AllIvarDecls.push_back(Ivar); @@ -8266,27 +8962,25 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, void Sema::ActOnFields(Scope* S, SourceLocation RecLoc, Decl *EnclosingDecl, - Decl **Fields, unsigned NumFields, + llvm::ArrayRef<Decl *> Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { assert(EnclosingDecl && "missing record or interface decl"); // If the decl this is being inserted into is invalid, then it may be a // redeclaration or some other bogus case. Don't try to add fields to it. - if (EnclosingDecl->isInvalidDecl()) { - // FIXME: Deallocate fields? + if (EnclosingDecl->isInvalidDecl()) return; - } - // Verify that all the fields are okay. unsigned NumNamedMembers = 0; - llvm::SmallVector<FieldDecl*, 32> RecFields; + SmallVector<FieldDecl*, 32> RecFields; RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); bool ARCErrReported = false; - for (unsigned i = 0; i != NumFields; ++i) { - FieldDecl *FD = cast<FieldDecl>(Fields[i]); + for (llvm::ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end(); + i != end; ++i) { + FieldDecl *FD = cast<FieldDecl>(*i); // Get the type for the field. const Type *FDTy = FD->getType().getTypePtr(); @@ -8321,25 +9015,26 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } else if (FDTy->isIncompleteArrayType() && Record && - ((i == NumFields - 1 && !Record->isUnion()) || - ((getLangOptions().Microsoft || getLangOptions().CPlusPlus) && - (i == NumFields - 1 || Record->isUnion())))) { + ((i + 1 == Fields.end() && !Record->isUnion()) || + ((getLangOptions().MicrosoftExt || + getLangOptions().CPlusPlus) && + (i + 1 == Fields.end() || Record->isUnion())))) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. // It will accept flexible array in union and also // as the sole element of a struct/class. - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_ms) << FD->getDeclName(); - else if (NumFields == 1) + else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms) << FD->getDeclName() << Record->getTagKind(); } else if (getLangOptions().CPlusPlus) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu) << FD->getDeclName(); - else if (NumFields == 1) + else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu) << FD->getDeclName() << Record->getTagKind(); } else if (NumNamedMembers < 1) { @@ -8376,7 +9071,7 @@ void Sema::ActOnFields(Scope* S, // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. - if (i != NumFields-1) + if (i + 1 != Fields.end()) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { @@ -8393,10 +9088,10 @@ void Sema::ActOnFields(Scope* S, Record->setHasObjectMember(true); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object - Diag(FD->getLocation(), diag::err_statically_allocated_object); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; + Diag(FD->getLocation(), diag::err_statically_allocated_object) + << FixItHint::CreateInsertion(FD->getLocation(), "*"); + QualType T = Context.getObjCObjectPointerType(FD->getType()); + FD->setType(T); } else if (!getLangOptions().CPlusPlus) { if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) { @@ -8421,7 +9116,7 @@ void Sema::ActOnFields(Scope* S, } } else if (getLangOptions().ObjC1 && - getLangOptions().getGCMode() != LangOptions::NonGC && + getLangOptions().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { if (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong()) @@ -8650,7 +9345,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, SourceLocation IdLoc, IdentifierInfo *Id, Expr *Val) { - unsigned IntWidth = Context.Target.getIntWidth(); + unsigned IntWidth = Context.getTargetInfo().getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; @@ -8691,7 +9386,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // ... if the initializing value of an enumerator cannot be // represented by the underlying type, the program is ill-formed. if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } else @@ -8806,7 +9501,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attr, - SourceLocation EqualLoc, ExprTy *val) { + SourceLocation EqualLoc, Expr *val) { EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null<EnumConstantDecl>(lastEnumConst); @@ -8894,9 +9589,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. - unsigned IntWidth = Context.Target.getIntWidth(); - unsigned CharWidth = Context.Target.getCharWidth(); - unsigned ShortWidth = Context.Target.getShortWidth(); + unsigned IntWidth = Context.getTargetInfo().getIntWidth(); + unsigned CharWidth = Context.getTargetInfo().getCharWidth(); + unsigned ShortWidth = Context.getTargetInfo().getShortWidth(); // Verify that all the values are okay, compute the size of the values, and // reverse the list. @@ -8969,12 +9664,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.IntTy; BestWidth = IntWidth; } else { - BestWidth = Context.Target.getLongWidth(); + BestWidth = Context.getTargetInfo().getLongWidth(); if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; } else { - BestWidth = Context.Target.getLongLongWidth(); + BestWidth = Context.getTargetInfo().getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) Diag(Enum->getLocation(), diag::warn_enum_too_large); @@ -9001,13 +9696,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) ? Context.UnsignedIntTy : Context.IntTy; } else if (NumPositiveBits <= - (BestWidth = Context.Target.getLongWidth())) { + (BestWidth = Context.getTargetInfo().getLongWidth())) { BestType = Context.UnsignedLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) ? Context.UnsignedLongTy : Context.LongTy; } else { - BestWidth = Context.Target.getLongLongWidth(); + BestWidth = Context.getTargetInfo().getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; @@ -9094,6 +9789,33 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, return New; } +DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc, + IdentifierInfo &ModuleName, + SourceLocation ModuleNameLoc) { + ModuleKey Module = PP.getModuleLoader().loadModule(ImportLoc, + ModuleName, ModuleNameLoc); + if (!Module) + return true; + + // FIXME: Actually create a declaration to describe the module import. + (void)Module; + return DeclResult((Decl *)0); +} + +void +Sema::diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old, + SourceLocation ModulePrivateKeyword) { + assert(!Old->isModulePrivate() && "Old is module-private!"); + + Diag(New->getLocation(), diag::err_module_private_follows_public) + << New->getDeclName() << SourceRange(ModulePrivateKeyword); + Diag(Old->getLocation(), diag::note_previous_declaration) + << Old->getDeclName(); + + // Drop the __module_private__ from the new declaration, since it's invalid. + New->setModulePrivate(false); +} + void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { @@ -9126,3 +9848,16 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, std::pair<IdentifierInfo*,WeakInfo>(AliasName, W)); } } + +Decl *Sema::getObjCDeclContext() const { + return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); +} + +AvailabilityResult Sema::getCurContextAvailability() const { + const Decl *D = cast<Decl>(getCurLexicalContext()); + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + D = CatD->getClassInterface(); + + return D->getAvailability(); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 61b7b3e..69baf79 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -15,19 +15,21 @@ #include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace sema; /// These constants match the enumerated choices of /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. -enum { +enum AttributeDeclKind { ExpectedFunction, ExpectedUnion, ExpectedVariableOrFunction, @@ -42,7 +44,8 @@ enum { ExpectedClassMember, ExpectedVariable, ExpectedMethod, - ExpectedVariableFunctionOrLabel + ExpectedVariableFunctionOrLabel, + ExpectedFieldOrGlobalVar }; //===----------------------------------------------------------------------===// @@ -194,6 +197,8 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } +/// \brief Check if the attribute has exactly as many args as Num. May +/// output an error. static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, unsigned int Num) { if (Attr.getNumArgs() != Num) { @@ -204,6 +209,140 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, return true; } + +/// \brief Check if the attribute has at least as many args as Num. May +/// output an error. +static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, + unsigned int Num) { + if (Attr.getNumArgs() < Num) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num; + return false; + } + + return true; +} + +/// +/// \brief Check if passed in Decl is a field or potentially shared global var +/// \return true if the Decl is a field or potentially shared global variable +/// +static bool mayBeSharedVariable(const Decl *D) { + if (isa<FieldDecl>(D)) + return true; + if (const VarDecl *vd = dyn_cast<VarDecl>(D)) + return (vd->hasGlobalStorage() && !(vd->isThreadSpecified())); + + return false; +} + +/// \brief Check if the passed-in expression is of type int or bool. +static bool isIntOrBool(Expr *Exp) { + QualType QT = Exp->getType(); + return QT->isBooleanType() || QT->isIntegerType(); +} + +/// +/// \brief Check if passed in Decl is a pointer type. +/// Note that this function may produce an error message. +/// \return true if the Decl is a pointer type; false otherwise +/// +static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) { + if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) { + QualType QT = vd->getType(); + if (QT->isAnyPointerType()) + return true; + S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type) + << Attr.getName()->getName() << QT; + } else { + S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl) + << Attr.getName(); + } + return false; +} + +/// \brief Checks that the passed in QualType either is of RecordType or points +/// to RecordType. Returns the relevant RecordType, null if it does not exit. +static const RecordType *getRecordType(QualType QT) { + if (const RecordType *RT = QT->getAs<RecordType>()) + return RT; + + // Now check if we point to record type. + if (const PointerType *PT = QT->getAs<PointerType>()) + return PT->getPointeeType()->getAs<RecordType>(); + + return 0; +} + +/// \brief Thread Safety Analysis: Checks that the passed in RecordType +/// resolves to a lockable object. May flag an error. +static bool checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, + const RecordType *RT) { + // Flag error if could not get record type for this argument. + if (!RT) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class) + << Attr.getName(); + return false; + } + // Flag error if the type is not lockable. + if (!RT->getDecl()->getAttr<LockableAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable) + << Attr.getName(); + return false; + } + return true; +} + +/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting +/// from Sidx, resolve to a lockable object. May flag an error. +/// \param Sidx The attribute argument index to start checking with. +/// \param ParamIdxOk Whether an argument can be indexing into a function +/// parameter list. +static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, + const AttributeList &Attr, + SmallVectorImpl<Expr*> &Args, + int Sidx = 0, + bool ParamIdxOk = false) { + for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { + Expr *ArgExp = Attr.getArg(Idx); + + if (ArgExp->isTypeDependent()) { + // FIXME -- need to processs this again on template instantiation + Args.push_back(ArgExp); + continue; + } + + QualType ArgTy = ArgExp->getType(); + + // First see if we can just cast to record type, or point to record type. + const RecordType *RT = getRecordType(ArgTy); + + // Now check if we index into a record type function param. + if(!RT && ParamIdxOk) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp); + if(FD && IL) { + unsigned int NumParams = FD->getNumParams(); + llvm::APInt ArgValue = IL->getValue(); + uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); + uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; + if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) + << Attr.getName() << Idx + 1 << NumParams; + return false; + } + ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); + RT = getRecordType(ArgTy); + } + } + + if (!checkForLockableRecord(S, D, Attr, RT)) + return false; + + Args.push_back(ArgExp); + } + return true; +} + //===----------------------------------------------------------------------===// // Attribute Implementations //===----------------------------------------------------------------------===// @@ -212,6 +351,324 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, // least add some helper functions to check most argument patterns (# // and types of args). +static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool pointer = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + if (pointer && !checkIsPointer(S, D, Attr)) + return; + + if (pointer) + D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context)); + else + D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context)); +} + +static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool pointer = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + + Expr *Arg = Attr.getArg(0); + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + if (pointer && !checkIsPointer(S, D, Attr)) + return; + + if (Arg->isTypeDependent()) + // FIXME: handle attributes with dependent types + return; + + // check that the argument is lockable object + if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType()))) + return; + + if (pointer) + D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), + S.Context, Arg)); + else + D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg)); +} + + +static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool scoped = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + // FIXME: Lockable structs for C code. + if (!isa<CXXRecordDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedClass; + return; + } + + if (scoped) + D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context)); + else + D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context)); +} + +static void handleNoThreadSafetyAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getRange(), + S.Context)); +} + +static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool before) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // D must be either a member field or global (potentially shared) variable. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD || !mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + // Check that this attribute only applies to lockable types + QualType QT = VD->getType(); + if (!QT->isDependentType()) { + const RecordType *RT = getRecordType(QT); + if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable) + << Attr.getName(); + return; + } + } + + SmallVector<Expr*, 1> Args; + // check that all arguments are lockable objects + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (before) + D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context, + StartArg, Size)); + else + D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + +static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + // check that the attribute is applied to a function + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(), + S.Context, StartArg, + Size)); + else + D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(), + S.Context, StartArg, + Size)); +} + +static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (!isIntOrBool(Attr.getArg(0))) { + S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool) + << Attr.getName(); + return; + } + + SmallVector<Expr*, 2> Args; + // check that all arguments are lockable objects + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1)) + return; + + unsigned Size = Args.size(); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(), + S.Context, + Attr.getArg(0), + StartArg, Size)); + else + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(), + S.Context, + Attr.getArg(0), + StartArg, Size)); +} + +static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(), + S.Context, StartArg, + Size)); + else + D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(), + S.Context, StartArg, + Size)); +} + +static void handleUnlockFunAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + +static void handleLockReturnedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + Expr *Arg = Attr.getArg(0); + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (Arg->isTypeDependent()) + return; + + // check that the argument is lockable object + if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType()))) + return; + + D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg)); +} + +static void handleLocksExcludedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + + static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D); @@ -261,7 +718,7 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); + TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. @@ -270,14 +727,14 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << Attr.getName() << FD->getType(); else - FD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); + FD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context)); + TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -290,26 +747,48 @@ static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) { // The IBAction attributes only apply to instance methods. if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->isInstanceMethod()) { - D->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context)); return; } S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName(); } +static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { + // The IBOutlet/IBOutletCollection attributes only apply to instance + // variables or properties of Objective-C classes. The outlet must also + // have an object reference type. + if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) { + if (!VD->getType()->getAs<ObjCObjectPointerType>()) { + S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type) + << Attr.getName() << VD->getType() << 0; + return false; + } + } + else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + if (!PD->getType()->getAs<ObjCObjectPointerType>()) { + S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type) + << Attr.getName() << PD->getType() << 1; + return false; + } + } + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + return false; + } + + return true; +} + static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (!checkAttributeNumArgs(S, Attr, 0)) return; - - // The IBOutlet attributes only apply to instance variables of - // Objective-C classes. - if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) { - D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context)); + + if (!checkIBOutletCommon(S, D, Attr)) return; - } - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + D->addAttr(::new (S.Context) IBOutletAttr(Attr.getRange(), S.Context)); } static void handleIBOutletCollection(Sema &S, Decl *D, @@ -321,25 +800,9 @@ static void handleIBOutletCollection(Sema &S, Decl *D, return; } - // The IBOutletCollection attributes only apply to instance variables of - // Objective-C classes. - if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + if (!checkIBOutletCommon(S, D, Attr)) return; - } - if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) - if (!VD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) - << VD->getType() << 0; - return; - } - if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - if (!PD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) - << PD->getType() << 1; - return; - } - + IdentifierInfo *II = Attr.getParameterName(); if (!II) II = &S.Context.Idents.get("id"); @@ -360,8 +823,8 @@ static void handleIBOutletCollection(Sema &S, Decl *D, S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; return; } - D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context, - QT)); + D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getRange(),S.Context, + QT, Attr.getParameterLoc())); } static void possibleTransparentUnionPointerType(QualType &T) { @@ -394,7 +857,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; // The nonnull attribute only applies to pointers. - llvm::SmallVector<unsigned, 10> NonNullArgs; + SmallVector<unsigned, 10> NonNullArgs; for (AttributeList::arg_iterator I=Attr.arg_begin(), E=Attr.arg_end(); I!=E; ++I) { @@ -466,7 +929,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned* start = &NonNullArgs[0]; unsigned size = NonNullArgs.size(); llvm::array_pod_sort(start, start + size); - D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start, + D->addAttr(::new (S.Context) NonNullAttr(Attr.getRange(), S.Context, start, size)); } @@ -526,13 +989,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { bool HasImplicitThisParam = isInstanceMethod(D); unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; - llvm::StringRef Module = AL.getParameterName()->getName(); + StringRef Module = AL.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. if (Module.startswith("__") && Module.endswith("__")) Module = Module.substr(2, Module.size() - 4); - llvm::SmallVector<unsigned, 10> OwnershipArgs; + SmallVector<unsigned, 10> OwnershipArgs; for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E; ++I) { @@ -712,18 +1175,18 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "weakref" << 1; return; } // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str->getString())); } - D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WeakRefAttr(Attr.getRange(), S.Context)); } static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -737,20 +1200,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "alias" << 1; return; } - if (S.Context.Target.getTriple().isOSDarwin()) { + if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); return; } // FIXME: check if target symbol exists in current file - D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str->getString())); } @@ -765,7 +1228,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context)); } static void handleAlwaysInlineAttr(Sema &S, Decl *D, @@ -782,7 +1245,7 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context)); } static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -795,7 +1258,7 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { QualType RetTy = FD->getResultType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { - D->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context)); return; } } @@ -808,13 +1271,13 @@ static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 0)) return; - D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MayAliasAttr(Attr.getRange(), S.Context)); } static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { assert(!Attr.isInvalid()); if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoCommonAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -823,7 +1286,7 @@ static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { assert(!Attr.isInvalid()); if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -840,7 +1303,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { return; } - D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoReturnAttr(attr.getRange(), S.Context)); } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { @@ -874,7 +1337,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, } } - D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context)); } // PS3 PPU-specific. @@ -935,7 +1398,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { count++; } - D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) VecReturnAttr(Attr.getRange(), S.Context)); } static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -961,7 +1424,24 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UnusedAttr(Attr.getRange(), S.Context)); +} + +static void handleReturnsTwiceAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // check the attribute arguments. + if (Attr.hasParameterOrArguments()) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunction; + return; + } + + D->addAttr(::new (S.Context) ReturnsTwiceAttr(Attr.getRange(), S.Context)); } static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -982,7 +1462,7 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UsedAttr(Attr.getRange(), S.Context)); } static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1011,7 +1491,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context, priority)); } @@ -1041,7 +1521,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context, priority)); } @@ -1053,7 +1533,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // Handle the case where deprecated attribute has a text message. - llvm::StringRef Str; + StringRef Str; if (NumArgs == 1) { StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0)); if (!SE) { @@ -1064,7 +1544,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Str = SE->getString(); } - D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str)); } static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1075,7 +1555,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // Handle the case where unavailable attribute has a text message. - llvm::StringRef Str; + StringRef Str; if (NumArgs == 1) { StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0)); if (!SE) { @@ -1085,7 +1565,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { } Str = SE->getString(); } - D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) UnavailableAttr(Attr.getRange(), S.Context, Str)); } static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, @@ -1097,7 +1577,7 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr( - Attr.getLoc(), S.Context)); + Attr.getRange(), S.Context)); } static void handleAvailabilityAttr(Sema &S, Decl *D, @@ -1105,7 +1585,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, IdentifierInfo *Platform = Attr.getParameterName(); SourceLocation PlatformLoc = Attr.getParameterLoc(); - llvm::StringRef PlatformName + StringRef PlatformName = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); if (PlatformName.empty()) { S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) @@ -1119,10 +1599,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); bool IsUnavailable = Attr.getUnavailableLoc().isValid(); - // Ensure that Introduced < Deprecated < Obsoleted (although not all + // Ensure that Introduced <= Deprecated <= Obsoleted (although not all // of these steps are needed). if (Introduced.isValid() && Deprecated.isValid() && - !(Introduced.Version < Deprecated.Version)) { + !(Introduced.Version <= Deprecated.Version)) { S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) << 1 << PlatformName << Deprecated.Version.getAsString() << 0 << Introduced.Version.getAsString(); @@ -1130,7 +1610,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } if (Introduced.isValid() && Obsoleted.isValid() && - !(Introduced.Version < Obsoleted.Version)) { + !(Introduced.Version <= Obsoleted.Version)) { S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) << 2 << PlatformName << Obsoleted.Version.getAsString() << 0 << Introduced.Version.getAsString(); @@ -1138,14 +1618,14 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } if (Deprecated.isValid() && Obsoleted.isValid() && - !(Deprecated.Version < Obsoleted.Version)) { + !(Deprecated.Version <= Obsoleted.Version)) { S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering) << 2 << PlatformName << Obsoleted.Version.getAsString() << 1 << Deprecated.Version.getAsString(); return; } - D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context, Platform, Introduced.Version, Deprecated.Version, @@ -1162,13 +1642,13 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "visibility" << 1; return; } - llvm::StringRef TypeStr = Str->getString(); + StringRef TypeStr = Str->getString(); VisibilityAttr::VisibilityType type; if (TypeStr == "default") @@ -1184,7 +1664,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type)); } static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, @@ -1207,7 +1687,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, return; } - llvm::StringRef param = Attr.getParameterName()->getName(); + StringRef param = Attr.getParameterName()->getName(); ObjCMethodFamilyAttr::FamilyKind family; if (param == "none") family = ObjCMethodFamilyAttr::OMF_None; @@ -1236,7 +1716,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, return; } - method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(), + method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), S.Context, family)); } @@ -1251,7 +1731,7 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getRange(), S.Context)); } static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1267,7 +1747,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { return; } } - D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context)); } static void @@ -1282,7 +1762,7 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) OverloadableAttr(Attr.getRange(), S.Context)); } static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1306,7 +1786,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) BlocksAttr(Attr.getRange(), S.Context, type)); } static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1316,7 +1796,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - int sentinel = 0; + unsigned sentinel = 0; if (Attr.getNumArgs() > 0) { Expr *E = Attr.getArg(0); llvm::APSInt Idx(32); @@ -1326,16 +1806,17 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { << "sentinel" << 1 << E->getSourceRange(); return; } - sentinel = Idx.getZExtValue(); - if (sentinel < 0) { + if (Idx.isSigned() && Idx.isNegative()) { S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } + + sentinel = Idx.getZExtValue(); } - int nullPos = 0; + unsigned nullPos = 0; if (Attr.getNumArgs() > 1) { Expr *E = Attr.getArg(1); llvm::APSInt Idx(32); @@ -1347,7 +1828,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } nullPos = Idx.getZExtValue(); - if (nullPos > 1 || nullPos < 0) { + if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) @@ -1357,9 +1838,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - const FunctionType *FT = FD->getType()->getAs<FunctionType>(); - assert(FT && "FunctionDecl has non-function type?"); - + const FunctionType *FT = FD->getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; @@ -1398,7 +1877,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } - D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, + D->addAttr(::new (S.Context) SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos)); } @@ -1425,7 +1904,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) return; } - D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context)); } static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1449,7 +1928,7 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context)); + nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context)); } static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1466,7 +1945,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { diag::warn_attribute_weak_import_invalid_on_definition) << "weak_import" << 2 /*variable and function*/; else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || - (S.Context.Target.getTriple().isOSDarwin() && + (S.Context.getTargetInfo().getTriple().isOSDarwin() && isa<ObjCInterfaceDecl>(D))) { // Nothing to warn about here. } else @@ -1476,7 +1955,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context)); } static void handleReqdWorkGroupSize(Sema &S, Decl *D, @@ -1497,7 +1976,7 @@ static void handleReqdWorkGroupSize(Sema &S, Decl *D, } WGSize[i] = (unsigned) ArgNum.getZExtValue(); } - D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2])); } @@ -1517,7 +1996,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // If the target wants to validate the section specifier, make it happen. - std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString()); + std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(SE->getString()); if (!Error.empty()) { S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) << Error; @@ -1530,7 +2009,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) SectionAttr(Attr.getRange(), S.Context, SE->getString())); } @@ -1544,9 +2023,9 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) { if (Existing->getLocation().isInvalid()) - Existing->setLocation(Attr.getLoc()); + Existing->setRange(Attr.getRange()); } else { - D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoThrowAttr(Attr.getRange(), S.Context)); } } @@ -1559,9 +2038,9 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (ConstAttr *Existing = D->getAttr<ConstAttr>()) { if (Existing->getLocation().isInvalid()) - Existing->setLocation(Attr.getLoc()); + Existing->setRange(Attr.getRange()); } else { - D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ConstAttr(Attr.getRange(), S.Context)); } } @@ -1570,7 +2049,7 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 0)) return; - D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PureAttr(Attr.getRange(), S.Context)); } static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1629,7 +2108,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); + D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD)); S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD); } @@ -1704,7 +2183,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) FormatArgAttr(Attr.getRange(), S.Context, Idx.getZExtValue())); } @@ -1719,7 +2198,7 @@ enum FormatAttrKind { /// getFormatAttrKind - Map from format attribute names to supported format /// types. -static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { +static FormatAttrKind getFormatAttrKind(StringRef Format) { // Check for formats that get handled specially. if (Format == "NSString") return NSStringFormat; @@ -1788,7 +2267,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, Attr.setInvalid(); return; } - D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getRange(), S.Context, prioritynum)); } @@ -1819,7 +2298,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; unsigned FirstIdx = 1; - llvm::StringRef Format = Attr.getParameterName()->getName(); + StringRef Format = Attr.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. if (Format.startswith("__") && Format.endswith("__")) @@ -1939,12 +2418,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // If we don't have a valid location for this attribute, adopt the // location. if (f->getLocation().isInvalid()) - f->setLocation(Attr.getLoc()); + f->setRange(Attr.getRange()); return; } } - D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format, + D->addAttr(::new (S.Context) FormatAttr(Attr.getRange(), S.Context, Format, Idx.getZExtValue(), FirstArg.getZExtValue())); } @@ -1970,7 +2449,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, return; } - if (!RD->isDefinition()) { + if (!RD->isCompleteDefinition()) { S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; @@ -2013,7 +2492,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } } - RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context)); + RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getRange(), S.Context)); } static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2030,7 +2509,15 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, + + // Don't duplicate annotations that are already set. + for (specific_attr_iterator<AnnotateAttr> + i = D->specific_attr_begin<AnnotateAttr>(), + e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) { + if ((*i)->getAnnotation() == SE->getString()) + return; + } + D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context, SE->getString())); } @@ -2046,20 +2533,21 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // weaker alignment, rather than being silently ignored. if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getLoc(), S.Context, true, 0)); + D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, true, 0)); return; } - S.AddAlignedAttr(Attr.getLoc(), D, Attr.getArg(0)); + S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0)); } -void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) { if (E->isTypeDependent() || E->isValueDependent()) { // Save dependent expressions in the AST to be instantiated. - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E)); return; } + SourceLocation AttrLoc = AttrRange.getBegin(); // FIXME: Cache the number on the Attr object? llvm::APSInt Alignment(32); if (!E->isIntegerConstantExpr(Alignment, Context)) { @@ -2073,13 +2561,13 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { return; } - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E)); } -void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) { // FIXME: Cache the number on the Attr object if non-dependent? // FIXME: Perform checking of type validity - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, false, TS)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS)); return; } @@ -2104,7 +2592,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - llvm::StringRef Str = Attr.getParameterName()->getName(); + StringRef Str = Attr.getParameterName()->getName(); // Normalize the attribute name, __foo__ becomes foo. if (Str.startswith("__") && Str.endswith("__")) @@ -2136,13 +2624,13 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. if (Str == "word") - DestWidth = S.Context.Target.getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(0); else if (Str == "byte") - DestWidth = S.Context.Target.getCharWidth(); + DestWidth = S.Context.getTargetInfo().getCharWidth(); break; case 7: if (Str == "pointer") - DestWidth = S.Context.Target.getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(0); break; } @@ -2153,7 +2641,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { OldTy = VD->getType(); else { S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc()); + << "mode" << Attr.getRange(); return; } @@ -2216,12 +2704,12 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!IntegerMode) NewTy = S.Context.DoubleTy; else if (OldTy->isSignedIntegerType()) - if (S.Context.Target.getLongWidth() == 64) + if (S.Context.getTargetInfo().getLongWidth() == 64) NewTy = S.Context.LongTy; else NewTy = S.Context.LongLongTy; else - if (S.Context.Target.getLongWidth() == 64) + if (S.Context.getTargetInfo().getLongWidth() == 64) NewTy = S.Context.UnsignedLongTy; else NewTy = S.Context.UnsignedLongLongTy; @@ -2264,7 +2752,7 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context)); } static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2279,7 +2767,7 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoInlineAttr(Attr.getRange(), S.Context)); } static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, @@ -2295,7 +2783,7 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getRange(), S.Context)); } @@ -2313,7 +2801,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant"; } @@ -2333,7 +2821,7 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; } @@ -2366,7 +2854,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global"; } @@ -2385,7 +2873,7 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; } @@ -2404,7 +2892,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared"; } @@ -2427,7 +2915,7 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getRange(), S.Context)); } static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2447,31 +2935,31 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { switch (Attr.getKind()) { case AttributeList::AT_fastcall: - D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_stdcall: - D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_thiscall: - D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cdecl: - D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_pascal: - D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_pcs: { Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "pcs" << 1; Attr.setInvalid(); return; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); PcsAttr::PCSType PCS; if (StrRef == "aapcs") PCS = PcsAttr::AAPCS; @@ -2483,7 +2971,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS)); + D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS)); } default: llvm_unreachable("unexpected attribute kind"); @@ -2493,7 +2981,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ assert(!Attr.isInvalid()); - D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); } bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { @@ -2519,14 +3007,14 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { case AttributeList::AT_pcs: { Expr *Arg = attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) << "pcs" << 1; attr.setInvalid(); return true; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); if (StrRef == "aapcs") { CC = CC_AAPCS; break; @@ -2555,7 +3043,7 @@ static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams)); + D->addAttr(::new (S.Context) RegparmAttr(Attr.getRange(), S.Context, numParams)); } /// Checks a regparm attribute, returning true if it is ill-formed and @@ -2580,7 +3068,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return true; } - if (Context.Target.getRegParmMax() == 0) { + if (Context.getTargetInfo().getRegParmMax() == 0) { Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); Attr.setInvalid(); @@ -2588,9 +3076,9 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { } numParams = NumParams.getZExtValue(); - if (numParams > Context.Target.getRegParmMax()) { + if (numParams > Context.getTargetInfo().getRegParmMax()) { Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) - << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); + << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); Attr.setInvalid(); return true; } @@ -2635,7 +3123,7 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ } } - D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getRange(), S.Context, MaxThreads.getZExtValue(), MinBlocks.getZExtValue())); } else { @@ -2648,17 +3136,21 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ //===----------------------------------------------------------------------===// static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); + return type->isDependentType() || + type->isObjCObjectPointerType() || + S.Context.isObjCNSObjectType(type); } static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isPointerType() || isValidSubjectOfNSAttribute(S, type); + return type->isDependentType() || + type->isPointerType() || + isValidSubjectOfNSAttribute(S, type); } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { ParmVarDecl *param = dyn_cast<ParmVarDecl>(D); if (!param) { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter; + << Attr.getRange() << Attr.getName() << ExpectedParameter; return; } @@ -2673,25 +3165,25 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!typeOK) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << cf; + << Attr.getRange() << Attr.getName() << cf; return; } if (cf) - param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getRange(), S.Context)); else - param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getRange(), S.Context)); } static void handleNSConsumesSelfAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod; + << Attr.getRange() << Attr.getName() << ExpectedMethod; return; } - D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getRange(), S.Context)); } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, @@ -2710,7 +3202,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, returnType = FD->getResultType(); else { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() + << Attr.getRange() << Attr.getName() << ExpectedFunctionOrMethod; return; } @@ -2735,53 +3227,143 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, if (!typeOK) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(Attr.getLoc()) - << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; + << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; return; } switch (Attr.getKind()) { default: - assert(0 && "invalid ownership attribute"); - return; + llvm_unreachable("invalid ownership attribute"); case AttributeList::AT_ns_returns_autoreleased: - D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cf_returns_not_retained: - D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cf_returns_retained: - D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_ns_returns_retained: - D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(), S.Context)); return; }; } +static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, + const AttributeList &attr) { + SourceLocation loc = attr.getLoc(); + + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); + + if (!isa<ObjCMethodDecl>(method)) { + S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(loc, loc) << attr.getName() << 13 /* methods */; + return; + } + + // Check that the method returns a normal pointer. + QualType resultType = method->getResultType(); + + if (!resultType->isReferenceType() && + (!resultType->isPointerType() || resultType->isObjCRetainableType())) { + S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) + << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2; + + // Drop the attribute. + return; + } + + method->addAttr( + ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context)); +} + +/// Handle cf_audited_transfer and cf_unknown_transfer. +static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) { + if (!isa<FunctionDecl>(D)) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << A.getRange() << A.getName() << 0 /*function*/; + return; + } + + bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer); + + // Check whether there's a conflicting attribute already present. + Attr *Existing; + if (IsAudited) { + Existing = D->getAttr<CFUnknownTransferAttr>(); + } else { + Existing = D->getAttr<CFAuditedTransferAttr>(); + } + if (Existing) { + S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible) + << A.getName() + << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer") + << A.getRange() << Existing->getRange(); + return; + } + + // All clear; add the attribute. + if (IsAudited) { + D->addAttr( + ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context)); + } else { + D->addAttr( + ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context)); + } +} + +static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + RecordDecl *RD = dyn_cast<RecordDecl>(D); + if (!RD || RD->isUnion()) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << Attr.getRange() << Attr.getName() << 14 /*struct */; + } + + IdentifierInfo *ParmName = Attr.getParameterName(); + + // In Objective-C, verify that the type names an Objective-C type. + // We don't want to check this outside of ObjC because people sometimes + // do crazy C declarations of Objective-C types. + if (ParmName && S.getLangOptions().ObjC1) { + // Check for an existing type with this name. + LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(), + Sema::LookupOrdinaryName); + if (S.LookupName(R, Sc)) { + NamedDecl *Target = R.getFoundDecl(); + if (Target && !isa<ObjCInterfaceDecl>(Target)) { + S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface); + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + } + } + + D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context, + ParmName)); +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; - SourceLocation L = Attr.getLoc(); S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 12 /* variable */; + << Attr.getRange() << Attr.getName() << 12 /* variable */; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) { - SourceLocation L = Attr.getLoc(); S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 12 /* variable */; + << Attr.getRange() << Attr.getName() << 12 /* variable */; return; } @@ -2820,7 +3402,7 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context)); + ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context)); } static bool isKnownDeclSpecAttr(const AttributeList &Attr) { @@ -2834,20 +3416,20 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) { //===----------------------------------------------------------------------===// static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.Microsoft || S.LangOpts.Borland) { + if (S.LangOpts.MicrosoftExt || S.LangOpts.Borland) { // check the attribute arguments. if (!checkAttributeNumArgs(S, Attr, 1)) return; Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "uuid" << 1; return; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' && StrRef.back() == '}'; @@ -2864,7 +3446,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" - llvm::StringRef::iterator I = StrRef.begin(); + StringRef::iterator I = StrRef.begin(); if (IsCurly) // Skip the optional '{' ++I; @@ -2881,7 +3463,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { I++; } - D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context, Str->getString())); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid"; @@ -2969,6 +3551,16 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_objc_precise_lifetime: handleObjCPreciseLifetimeAttr(S, D, Attr); break; + case AttributeList::AT_objc_returns_inner_pointer: + handleObjCReturnsInnerPointerAttr(S, D, Attr); break; + + case AttributeList::AT_ns_bridged: + handleNSBridgedAttr(S, scope, D, Attr); break; + + case AttributeList::AT_cf_audited_transfer: + case AttributeList::AT_cf_unknown_transfer: + handleCFTransferAttr(S, D, Attr); break; + // Checker-specific. case AttributeList::AT_cf_consumed: case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break; @@ -2996,6 +3588,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, handleArcWeakrefUnavailableAttr (S, D, Attr); break; case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break; + case AttributeList::AT_returns_twice: + handleReturnsTwiceAttr(S, D, Attr); + break; case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break; case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break; case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr); @@ -3041,6 +3636,63 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_uuid: handleUuidAttr(S, D, Attr); break; + + // Thread safety attributes: + case AttributeList::AT_guarded_var: + handleGuardedVarAttr(S, D, Attr); + break; + case AttributeList::AT_pt_guarded_var: + handleGuardedVarAttr(S, D, Attr, /*pointer = */true); + break; + case AttributeList::AT_scoped_lockable: + handleLockableAttr(S, D, Attr, /*scoped = */true); + break; + case AttributeList::AT_no_thread_safety_analysis: + handleNoThreadSafetyAttr(S, D, Attr); + break; + case AttributeList::AT_lockable: + handleLockableAttr(S, D, Attr); + break; + case AttributeList::AT_guarded_by: + handleGuardedByAttr(S, D, Attr); + break; + case AttributeList::AT_pt_guarded_by: + handleGuardedByAttr(S, D, Attr, /*pointer = */true); + break; + case AttributeList::AT_exclusive_lock_function: + handleLockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_locks_required: + handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_trylock_function: + handleTrylockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_lock_returned: + handleLockReturnedAttr(S, D, Attr); + break; + case AttributeList::AT_locks_excluded: + handleLocksExcludedAttr(S, D, Attr); + break; + case AttributeList::AT_shared_lock_function: + handleLockFunAttr(S, D, Attr); + break; + case AttributeList::AT_shared_locks_required: + handleLocksRequiredAttr(S, D, Attr); + break; + case AttributeList::AT_shared_trylock_function: + handleTrylockFunAttr(S, D, Attr); + break; + case AttributeList::AT_unlock_function: + handleUnlockFunAttr(S, D, Attr); + break; + case AttributeList::AT_acquired_before: + handleAcquireOrderAttr(S, D, Attr, /*before = */true); + break; + case AttributeList::AT_acquired_after: + handleAcquireOrderAttr(S, D, Attr, /*before = */false); + break; + default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); @@ -3091,19 +3743,86 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } +// Annotation attributes are the only attributes allowed after an access +// specifier. +bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList) { + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (l->getKind() == AttributeList::AT_annotate) { + handleAnnotateAttr(*this, ASDecl, *l); + } else { + Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + return true; + } + } + + return false; +} + +/// checkUnusedDeclAttributes - Check a list of attributes to see if it +/// contains any decl attributes that we should warn about. +static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { + for ( ; A; A = A->getNext()) { + // Only warn if the attribute is an unignored, non-type attribute. + if (A->isUsedAsTypeAttr()) continue; + if (A->getKind() == AttributeList::IgnoredAttribute) continue; + + if (A->getKind() == AttributeList::UnknownAttribute) { + S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored) + << A->getName() << A->getRange(); + } else { + S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl) + << A->getName() << A->getRange(); + } + } +} + +/// checkUnusedDeclAttributes - Given a declarator which is not being +/// used to build a declaration, complain about any decl attributes +/// which might be lying around on it. +void Sema::checkUnusedDeclAttributes(Declarator &D) { + ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList()); + ::checkUnusedDeclAttributes(*this, D.getAttributes()); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) + ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); +} + /// DeclClonePragmaWeak - clone existing decl (maybe definition), /// #pragma weak needs a non-definition decl and source may not have one -NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { +NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); NamedDecl *NewD = 0; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), - FD->getInnerLocStart(), - FD->getLocation(), DeclarationName(II), - FD->getType(), FD->getTypeSourceInfo()); - if (FD->getQualifier()) { - FunctionDecl *NewFD = cast<FunctionDecl>(NewD); + FunctionDecl *NewFD; + // FIXME: Missing call to CheckFunctionDeclaration(). + // FIXME: Mangling? + // FIXME: Is the qualifier info correct? + // FIXME: Is the DeclContext correct? + NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), + Loc, Loc, DeclarationName(II), + FD->getType(), FD->getTypeSourceInfo(), + SC_None, SC_None, + false/*isInlineSpecified*/, + FD->hasPrototype(), + false/*isConstexprSpecified*/); + NewD = NewFD; + + if (FD->getQualifier()) NewFD->setQualifierInfo(FD->getQualifierLoc()); + + // Fake up parameter variables; they are declared as if this were + // a typedef. + QualType FDTy = FD->getType(); + if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { + SmallVector<ParmVarDecl*, 16> Params; + for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), + AE = FT->arg_type_end(); AI != AE; ++AI) { + ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, *AI); + Param->setScopeInfo(0, Params.size()); + Params.push_back(Param); + } + NewFD->setParams(Params); } } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), @@ -3126,7 +3845,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { W.setUsed(true); if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); - NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias()); + NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context, NDId->getName())); NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); @@ -3149,15 +3868,18 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, bool NonInheritable, bool Inheritable) { // It's valid to "forward-declare" #pragma weak, in which case we // have to do this. - if (Inheritable && !WeakUndeclaredIdentifiers.empty()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { - if (IdentifierInfo *Id = ND->getIdentifier()) { - llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I - = WeakUndeclaredIdentifiers.find(Id); - if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) { - WeakInfo W = I->second; - DeclApplyPragmaWeak(S, ND, W); - WeakUndeclaredIdentifiers[Id] = W; + if (Inheritable) { + LoadExternalWeakUndeclaredIdentifiers(); + if (!WeakUndeclaredIdentifiers.empty()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + if (IdentifierInfo *Id = ND->getIdentifier()) { + llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I + = WeakUndeclaredIdentifiers.find(Id); + if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) { + WeakInfo W = I->second; + DeclApplyPragmaWeak(S, ND, W); + WeakUndeclaredIdentifiers[Id] = W; + } } } } @@ -3185,7 +3907,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl)) + // Function declarations in sys headers will be marked unavailable. + if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && + !isa<FunctionDecl>(decl)) return false; // Require it to be declared in a system header. @@ -3200,6 +3924,17 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, "this system declaration uses an unsupported type")); return; } + if (S.getLangOptions().ObjCAutoRefCount) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { + // FIXME. we may want to supress diagnostics for all + // kind of forbidden type messages on unavailable functions. + if (FD->hasAttr<UnavailableAttr>() && + diag.getForbiddenTypeDiagnostic() == + diag::err_arc_array_param_no_ownership) { + diag.Triggered = true; + return; + } + } S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); @@ -3287,6 +4022,9 @@ static bool isDeclDeprecated(Decl *D) { do { if (D->isDeprecated()) return true; + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + return CatD->getClassInterface()->isDeprecated(); } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; } @@ -3306,7 +4044,7 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, << DD.getDeprecationDecl()->getDeclName(); } -void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, +void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass) { // Delay if we're currently parsing a declaration. @@ -3316,7 +4054,7 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, } // Otherwise, don't warn if our current context is deprecated. - if (isDeclDeprecated(cast<Decl>(CurContext))) + if (isDeclDeprecated(cast<Decl>(getCurLexicalContext()))) return; if (!Message.empty()) Diag(Loc, diag::warn_deprecated_message) << D->getDeclName() diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index d793daf..a39584a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -392,7 +392,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { // MSVC accepts that default parameters be redefined for member functions // of template class. The new default parameter's value is ignored. Invalid = true; - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New); if (MD && MD->getParent()->getDescribedClassTemplate()) { // Merge the old default argument into the new parameter. @@ -502,6 +502,20 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { } } + // C++0x [dcl.constexpr]p1: If any declaration of a function or function + // template has a constexpr specifier then all its declarations shall + // contain the constexpr specifier. [Note: An explicit specialization can + // differ from the template declaration with respect to the constexpr + // specifier. -- end note] + // + // FIXME: Don't reject changes in constexpr in explicit specializations. + if (New->isConstexpr() != Old->isConstexpr()) { + Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) + << New << New->isConstexpr(); + Diag(Old->getLocation(), diag::note_previous_declaration); + Invalid = true; + } + if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; @@ -602,6 +616,363 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { } } +// CheckConstexprParameterTypes - Check whether a function's parameter types +// are all literal types. If so, return true. If not, produce a suitable +// diagnostic depending on @p CCK and return false. +static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD, + Sema::CheckConstexprKind CCK) { + unsigned ArgIndex = 0; + const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>(); + for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(), + e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) { + const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); + SourceLocation ParamLoc = PD->getLocation(); + if (!(*i)->isDependentType() && + SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ? + SemaRef.PDiag(diag::err_constexpr_non_literal_param) + << ArgIndex+1 << PD->getSourceRange() + << isa<CXXConstructorDecl>(FD) : + SemaRef.PDiag(), + /*AllowIncompleteType*/ true)) { + if (CCK == Sema::CCK_NoteNonConstexprInstantiation) + SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param) + << ArgIndex+1 << PD->getSourceRange() + << isa<CXXConstructorDecl>(FD) << *i; + return false; + } + } + return true; +} + +// CheckConstexprFunctionDecl - Check whether a function declaration satisfies +// the requirements of a constexpr function declaration or a constexpr +// constructor declaration. Return true if it does, false if not. +// +// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308. +// +// \param CCK Specifies whether to produce diagnostics if the function does not +// satisfy the requirements. +bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD, + CheckConstexprKind CCK) { + assert((CCK != CCK_NoteNonConstexprInstantiation || + (NewFD->getTemplateInstantiationPattern() && + NewFD->getTemplateInstantiationPattern()->isConstexpr())) && + "only constexpr templates can be instantiated non-constexpr"); + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) { + // C++0x [dcl.constexpr]p4: + // In the definition of a constexpr constructor, each of the parameter + // types shall be a literal type. + if (!CheckConstexprParameterTypes(*this, NewFD, CCK)) + return false; + + // In addition, either its function-body shall be = delete or = default or + // it shall satisfy the following constraints: + // - the class shall not have any virtual base classes; + const CXXRecordDecl *RD = CD->getParent(); + if (RD->getNumVBases()) { + // Note, this is still illegal if the body is = default, since the + // implicit body does not satisfy the requirements of a constexpr + // constructor. We also reject cases where the body is = delete, as + // required by N3308. + if (CCK != CCK_Instantiation) { + Diag(NewFD->getLocation(), + CCK == CCK_Declaration ? diag::err_constexpr_virtual_base + : diag::note_constexpr_tmpl_virtual_base) + << RD->isStruct() << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getSourceRange().getBegin(), + diag::note_constexpr_virtual_base_here) << I->getSourceRange(); + } + return false; + } + } else { + // C++0x [dcl.constexpr]p3: + // The definition of a constexpr function shall satisfy the following + // constraints: + // - it shall not be virtual; + const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); + if (Method && Method->isVirtual()) { + if (CCK != CCK_Instantiation) { + Diag(NewFD->getLocation(), + CCK == CCK_Declaration ? diag::err_constexpr_virtual + : diag::note_constexpr_tmpl_virtual); + + // If it's not obvious why this function is virtual, find an overridden + // function which uses the 'virtual' keyword. + const CXXMethodDecl *WrittenVirtual = Method; + while (!WrittenVirtual->isVirtualAsWritten()) + WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); + if (WrittenVirtual != Method) + Diag(WrittenVirtual->getLocation(), + diag::note_overridden_virtual_function); + } + return false; + } + + // - its return type shall be a literal type; + QualType RT = NewFD->getResultType(); + if (!RT->isDependentType() && + RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ? + PDiag(diag::err_constexpr_non_literal_return) : + PDiag(), + /*AllowIncompleteType*/ true)) { + if (CCK == CCK_NoteNonConstexprInstantiation) + Diag(NewFD->getLocation(), + diag::note_constexpr_tmpl_non_literal_return) << RT; + return false; + } + + // - each of its parameter types shall be a literal type; + if (!CheckConstexprParameterTypes(*this, NewFD, CCK)) + return false; + } + + return true; +} + +/// Check the given declaration statement is legal within a constexpr function +/// body. C++0x [dcl.constexpr]p3,p4. +/// +/// \return true if the body is OK, false if we have diagnosed a problem. +static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, + DeclStmt *DS) { + // C++0x [dcl.constexpr]p3 and p4: + // The definition of a constexpr function(p3) or constructor(p4) [...] shall + // contain only + for (DeclStmt::decl_iterator DclIt = DS->decl_begin(), + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) { + switch ((*DclIt)->getKind()) { + case Decl::StaticAssert: + case Decl::Using: + case Decl::UsingShadow: + case Decl::UsingDirective: + case Decl::UnresolvedUsingTypename: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + continue; + + case Decl::Typedef: + case Decl::TypeAlias: { + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt); + if (TN->getUnderlyingType()->isVariablyModifiedType()) { + // Don't allow variably-modified types in constexpr functions. + TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc(); + SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla) + << TL.getSourceRange() << TL.getType() + << isa<CXXConstructorDecl>(Dcl); + return false; + } + continue; + } + + case Decl::Enum: + case Decl::CXXRecord: + // As an extension, we allow the declaration (but not the definition) of + // classes and enumerations in all declarations, not just in typedef and + // alias declarations. + if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) { + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + continue; + + case Decl::Var: + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration) + << isa<CXXConstructorDecl>(Dcl); + return false; + + default: + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + } + + return true; +} + +/// Check that the given field is initialized within a constexpr constructor. +/// +/// \param Dcl The constexpr constructor being checked. +/// \param Field The field being checked. This may be a member of an anonymous +/// struct or union nested within the class being checked. +/// \param Inits All declarations, including anonymous struct/union members and +/// indirect members, for which any initialization was provided. +/// \param Diagnosed Set to true if an error is produced. +static void CheckConstexprCtorInitializer(Sema &SemaRef, + const FunctionDecl *Dcl, + FieldDecl *Field, + llvm::SmallSet<Decl*, 16> &Inits, + bool &Diagnosed) { + if (Field->isUnnamedBitfield()) + return; + + if (!Inits.count(Field)) { + if (!Diagnosed) { + SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init); + Diagnosed = true; + } + SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); + } else if (Field->isAnonymousStructOrUnion()) { + const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) + // If an anonymous union contains an anonymous struct of which any member + // is initialized, all members must be initialized. + if (!RD->isUnion() || Inits.count(*I)) + CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed); + } +} + +/// Check the body for the given constexpr function declaration only contains +/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. +/// +/// \return true if the body is OK, false if we have diagnosed a problem. +bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { + if (isa<CXXTryStmt>(Body)) { + // C++0x [dcl.constexpr]p3: + // The definition of a constexpr function shall satisfy the following + // constraints: [...] + // - its function-body shall be = delete, = default, or a + // compound-statement + // + // C++0x [dcl.constexpr]p4: + // In the definition of a constexpr constructor, [...] + // - its function-body shall not be a function-try-block; + Diag(Body->getLocStart(), diag::err_constexpr_function_try_block) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + + // - its function-body shall be [...] a compound-statement that contains only + CompoundStmt *CompBody = cast<CompoundStmt>(Body); + + llvm::SmallVector<SourceLocation, 4> ReturnStmts; + for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(), + BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) { + switch ((*BodyIt)->getStmtClass()) { + case Stmt::NullStmtClass: + // - null statements, + continue; + + case Stmt::DeclStmtClass: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt))) + return false; + continue; + + case Stmt::ReturnStmtClass: + // - and exactly one return statement; + if (isa<CXXConstructorDecl>(Dcl)) + break; + + ReturnStmts.push_back((*BodyIt)->getLocStart()); + // FIXME + // - every constructor call and implicit conversion used in initializing + // the return value shall be one of those allowed in a constant + // expression. + // Deal with this as part of a general check that the function can produce + // a constant expression (for [dcl.constexpr]p5). + continue; + + default: + break; + } + + Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + + if (const CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(Dcl)) { + const CXXRecordDecl *RD = Constructor->getParent(); + // - every non-static data member and base class sub-object shall be + // initialized; + if (RD->isUnion()) { + // DR1359: Exactly one member of a union shall be initialized. + if (Constructor->getNumCtorInitializers() == 0) { + Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init); + return false; + } + } else if (!Constructor->isDependentContext() && + !Constructor->isDelegatingConstructor()) { + assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases"); + + // Skip detailed checking if we have enough initializers, and we would + // allow at most one initializer per member. + bool AnyAnonStructUnionMembers = false; + unsigned Fields = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++Fields) { + if ((*I)->isAnonymousStructOrUnion()) { + AnyAnonStructUnionMembers = true; + break; + } + } + if (AnyAnonStructUnionMembers || + Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) { + // Check initialization of non-static data members. Base classes are + // always initialized so do not need to be checked. Dependent bases + // might not have initializers in the member initializer list. + llvm::SmallSet<Decl*, 16> Inits; + for (CXXConstructorDecl::init_const_iterator + I = Constructor->init_begin(), E = Constructor->init_end(); + I != E; ++I) { + if (FieldDecl *FD = (*I)->getMember()) + Inits.insert(FD); + else if (IndirectFieldDecl *ID = (*I)->getIndirectMember()) + Inits.insert(ID->chain_begin(), ID->chain_end()); + } + + bool Diagnosed = false; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) + CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed); + if (Diagnosed) + return false; + } + } + + // FIXME + // - every constructor involved in initializing non-static data members + // and base class sub-objects shall be a constexpr constructor; + // - every assignment-expression that is an initializer-clause appearing + // directly or indirectly within a brace-or-equal-initializer for + // a non-static data member that is not named by a mem-initializer-id + // shall be a constant expression; and + // - every implicit conversion used in converting a constructor argument + // to the corresponding parameter type and converting + // a full-expression to the corresponding member type shall be one of + // those allowed in a constant expression. + // Deal with these as part of a general check that the function can produce + // a constant expression (for [dcl.constexpr]p5). + } else { + if (ReturnStmts.empty()) { + Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return); + return false; + } + if (ReturnStmts.size() > 1) { + Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return); + for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) + Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); + return false; + } + } + + return true; +} + /// isCurrentClassName - Determine whether the identifier II is the /// name of the class type currently being defined. In the case of /// nested classes, this will only return true if II is the name of @@ -797,7 +1168,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, /// ActOnBaseSpecifiers - Attach the given base specifiers to the /// class, after checking whether there are any duplicate base /// classes. -void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, BaseTy **Bases, +void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, unsigned NumBases) { if (!ClassDecl || !Bases || !NumBases) return; @@ -1005,19 +1376,20 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. -Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, - SourceLocation ColonLoc) { +bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); CurContext->addHiddenDecl(ASDecl); - return ASDecl; + return ProcessAccessDeclAttributeList(ASDecl, Attrs); } /// CheckOverrideControl - Check C++0x override control semantics. void Sema::CheckOverrideControl(const Decl *D) { - const CXXMethodDecl *MD = llvm::dyn_cast<CXXMethodDecl>(D); + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); if (!MD || !MD->isVirtual()) return; @@ -1060,9 +1432,8 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - ExprTy *BW, const VirtSpecifiers &VS, - ExprTy *InitExpr, bool HasDeferredInit, - bool IsDefinition) { + Expr *BW, const VirtSpecifiers &VS, + bool HasDeferredInit) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1073,11 +1444,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Loc = D.getSourceRange().getBegin(); Expr *BitWidth = static_cast<Expr*>(BW); - Expr *Init = static_cast<Expr*>(InitExpr); assert(isa<CXXRecordDecl>(CurContext)); assert(!DS.isFriendSpecified()); - assert(!Init || !HasDeferredInit); bool isFunc = D.isDeclarationOfFunction(); @@ -1120,7 +1489,37 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Decl *Member; if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); + + // Data members must have identifiers for names. + if (Name.getNameKind() != DeclarationName::Identifier) { + Diag(Loc, diag::err_bad_variable_name) + << Name; + return 0; + } + IdentifierInfo *II = Name.getAsIdentifierInfo(); + + // Member field could not be with "template" keyword. + // So TemplateParameterLists should be empty in this case. + if (TemplateParameterLists.size()) { + TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0]; + if (TemplateParams->size()) { + // There is no such thing as a member field template. + Diag(D.getIdentifierLoc(), diag::err_template_member) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + } else { + // There is an extraneous 'template<>' for this member. + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_member_noparams) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + } + return 0; + } + if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: @@ -1138,16 +1537,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, SS.clear(); } - - // FIXME: Check for template parameters! - // FIXME: Check that the name is an identifier! + Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { assert(!HasDeferredInit); - Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); + Member = HandleDeclarator(S, D, move(TemplateParameterLists)); if (!Member) { return 0; } @@ -1214,28 +1611,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert((Name || isInstField) && "No identifier for non-field ?"); - if (Init) - AddInitializerToDecl(Member, Init, false, - DS.getTypeSpecType() == DeclSpec::TST_auto); - else if (DS.getTypeSpecType() == DeclSpec::TST_auto && - DS.getStorageClassSpec() == DeclSpec::SCS_static) { - // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static - // data member if a brace-or-equal-initializer is provided. - Diag(Loc, diag::err_auto_var_requires_init) - << Name << cast<ValueDecl>(Member)->getType(); - Member->setInvalidDecl(); - } - - FinalizeDeclaration(Member); - if (isInstField) FieldCollector->Add(cast<FieldDecl>(Member)); return Member; } /// ActOnCXXInClassMemberInitializer - This is invoked after parsing an -/// in-class initializer for a non-static C++ class member. Such parsing -/// is deferred until the class is complete. +/// in-class initializer for a non-static C++ class member, and after +/// instantiating an in-class initializer in a class template. Such actions +/// are deferred until the class is complete. void Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, Expr *InitExpr) { @@ -1319,7 +1703,21 @@ static bool FindBaseInitializer(Sema &SemaRef, return DirectBaseSpec || VirtualBaseSpec; } -/// ActOnMemInitializer - Handle a C++ member initializer. +/// \brief Handle a C++ member initializer using braced-init-list syntax. +MemInitResult +Sema::ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + SourceLocation IdLoc, + Expr *InitList, + SourceLocation EllipsisLoc) { + return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, + IdLoc, MultiInitializer(InitList), EllipsisLoc); +} + +/// \brief Handle a C++ member initializer using parentheses syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, @@ -1328,9 +1726,25 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, ParsedType TemplateTypeTy, SourceLocation IdLoc, SourceLocation LParenLoc, - ExprTy **Args, unsigned NumArgs, + Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { + return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, + IdLoc, MultiInitializer(LParenLoc, Args, NumArgs, + RParenLoc), + EllipsisLoc); +} + +/// \brief Handle a C++ member initializer. +MemInitResult +Sema::BuildMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + SourceLocation IdLoc, + const MultiInitializer &Args, + SourceLocation EllipsisLoc) { if (!ConstructorD) return true; @@ -1365,26 +1779,23 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, = ClassDecl->lookup(MemberOrBase); if (Result.first != Result.second) { Member = dyn_cast<FieldDecl>(*Result.first); - + if (Member) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); - - return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - LParenLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); + + return BuildMemberInitializer(Member, Args, IdLoc); } - + // Handle anonymous union case. if (IndirectFieldDecl* IndirectField = dyn_cast<IndirectFieldDecl>(*Result.first)) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); - return BuildMemberInitializer(IndirectField, (Expr**)Args, - NumArgs, IdLoc, - LParenLoc, RParenLoc); + return BuildMemberInitializer(IndirectField, Args, IdLoc); } } } @@ -1443,8 +1854,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, Diag(Member->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; - return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - LParenLoc, RParenLoc); + return BuildMemberInitializer(Member, Args, IdLoc); } } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) { const CXXBaseSpecifier *DirectBaseSpec; @@ -1473,7 +1883,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); return true; } } @@ -1493,8 +1903,62 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs, - LParenLoc, RParenLoc, ClassDecl, EllipsisLoc); + return BuildBaseInitializer(BaseType, TInfo, Args, ClassDecl, EllipsisLoc); +} + +/// Checks a member initializer expression for cases where reference (or +/// pointer) members are bound to by-value parameters (or their addresses). +static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, + Expr *Init, + SourceLocation IdLoc) { + QualType MemberTy = Member->getType(); + + // We only handle pointers and references currently. + // FIXME: Would this be relevant for ObjC object pointers? Or block pointers? + if (!MemberTy->isReferenceType() && !MemberTy->isPointerType()) + return; + + const bool IsPointer = MemberTy->isPointerType(); + if (IsPointer) { + if (const UnaryOperator *Op + = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) { + // The only case we're worried about with pointers requires taking the + // address. + if (Op->getOpcode() != UO_AddrOf) + return; + + Init = Op->getSubExpr(); + } else { + // We only handle address-of expression initializers for pointers. + return; + } + } + + if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) { + // Taking the address of a temporary will be diagnosed as a hard error. + if (IsPointer) + return; + + S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary) + << Member << Init->getSourceRange(); + } else if (const DeclRefExpr *DRE + = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { + // We only warn when referring to a non-reference parameter declaration. + const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl()); + if (!Parameter || Parameter->getType()->isReferenceType()) + return; + + S.Diag(Init->getExprLoc(), + IsPointer ? diag::warn_init_ptr_member_to_parameter_addr + : diag::warn_bind_ref_member_to_parameter) + << Member << Parameter << Init->getSourceRange(); + } else { + // Other initializers are fine. + return; + } + + S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) + << (unsigned)IsPointer; } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1566,10 +2030,9 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, } MemInitResult -Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { +Sema::BuildMemberInitializer(ValueDecl *Member, + const MultiInitializer &Args, + SourceLocation IdLoc) { FieldDecl *DirectMember = dyn_cast<FieldDecl>(Member); IndirectFieldDecl *IndirectMember = dyn_cast<IndirectFieldDecl>(Member); assert((DirectMember || IndirectMember) && @@ -1582,9 +2045,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. - for (unsigned i = 0; i < NumArgs; ++i) { + for (MultiInitializer::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { SourceLocation L; - if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { + Expr *Arg = *I; + if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Arg)) + Arg = DIE->getInit(); + if (InitExprContainsUninitializedFields(Arg, Member, &L)) { // FIXME: Return true in the case when other fields are used before being // uninitialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th @@ -1595,17 +2062,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, } } - bool HasDependentArg = false; - for (unsigned i = 0; i < NumArgs; i++) - HasDependentArg |= Args[i]->isTypeDependent(); + bool HasDependentArg = Args.isTypeDependent(); Expr *Init; if (Member->getType()->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. - Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, - Member->getType().getNonReferenceType()); + Init = Args.CreateInitExpr(Context,Member->getType().getNonReferenceType()); DiscardCleanupsInEvaluationContext(); } else { @@ -1614,17 +2077,14 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0) : InitializedEntity::InitializeMember(IndirectMember, 0); InitializationKind Kind = - InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); + InitializationKind::CreateDirect(IdLoc, Args.getStartLoc(), + Args.getEndLoc()); - InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - - ExprResult MemberInit = - InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + ExprResult MemberInit = Args.PerformInit(*this, MemberEntity, Kind); if (MemberInit.isInvalid()) return true; - CheckImplicitConversions(MemberInit.get(), LParenLoc); + CheckImplicitConversions(MemberInit.get(), Args.getStartLoc()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -1640,31 +2100,30 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // of the information that we have about the member // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - Init = new (Context) ParenListExpr( - Context, LParenLoc, Args, NumArgs, RParenLoc, - Member->getType().getNonReferenceType()); - else + if (CurContext->isDependentContext()) { + Init = Args.CreateInitExpr(Context, + Member->getType().getNonReferenceType()); + } else { Init = MemberInit.get(); + CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc); + } } if (DirectMember) { return new (Context) CXXCtorInitializer(Context, DirectMember, - IdLoc, LParenLoc, Init, - RParenLoc); + IdLoc, Args.getStartLoc(), + Init, Args.getEndLoc()); } else { return new (Context) CXXCtorInitializer(Context, IndirectMember, - IdLoc, LParenLoc, Init, - RParenLoc); + IdLoc, Args.getStartLoc(), + Init, Args.getEndLoc()); } } MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, - Expr **Args, unsigned NumArgs, + const MultiInitializer &Args, SourceLocation NameLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) @@ -1675,13 +2134,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = - InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc); + InitializationKind::CreateDirect(NameLoc, Args.getStartLoc(), + Args.getEndLoc()); - InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); - - ExprResult DelegationInit = - InitSeq.Perform(*this, DelegationEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + ExprResult DelegationInit = Args.PerformInit(*this, DelegationEntity, Kind); if (DelegationInit.isInvalid()) return true; @@ -1690,7 +2146,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, = ConExpr->getConstructor(); assert(Constructor && "Delegating constructor with no target?"); - CheckImplicitConversions(DelegationInit.get(), LParenLoc); + CheckImplicitConversions(DelegationInit.get(), Args.getStartLoc()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -1700,24 +2156,22 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, return true; assert(!CurContext->isDependentContext()); - return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, + return new (Context) CXXCtorInitializer(Context, Loc, Args.getStartLoc(), + Constructor, DelegationInit.takeAs<Expr>(), - RParenLoc); + Args.getEndLoc()); } MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, - Expr **Args, unsigned NumArgs, - SourceLocation LParenLoc, SourceLocation RParenLoc, + const MultiInitializer &Args, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { - bool HasDependentArg = false; - for (unsigned i = 0; i < NumArgs; i++) - HasDependentArg |= Args[i]->isTypeDependent(); + bool HasDependentArg = Args.isTypeDependent(); SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); - + if (!BaseType->isDependentType() && !BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); @@ -1734,28 +2188,26 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // This is a pack expansion. if (!BaseType->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << SourceRange(BaseLoc, RParenLoc); - + << SourceRange(BaseLoc, Args.getEndLoc()); + EllipsisLoc = SourceLocation(); } } else { // Check for any unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer)) return true; - - for (unsigned I = 0; I != NumArgs; ++I) - if (DiagnoseUnexpandedParameterPack(Args[I])) - return true; + + if (Args.DiagnoseUnexpandedParameterPack(*this)) + return true; } - + // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = 0; const CXXBaseSpecifier *VirtualBaseSpec = 0; if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) - return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc, - LParenLoc, RParenLoc, ClassDecl); + return BuildDelegatingInitializer(BaseTInfo, Args, BaseLoc, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -1782,18 +2234,14 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (Dependent) { // Can't check initialization for a base of dependent type or when // any of the arguments are type-dependent expressions. - ExprResult BaseInit - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, BaseType)); + Expr *BaseInit = Args.CreateInitExpr(Context, BaseType); DiscardCleanupsInEvaluationContext(); - return new (Context) CXXCtorInitializer(Context, BaseTInfo, - /*IsVirtual=*/false, - LParenLoc, - BaseInit.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); + return new (Context) CXXCtorInitializer(Context, BaseTInfo, + /*IsVirtual=*/false, + Args.getStartLoc(), BaseInit, + Args.getEndLoc(), EllipsisLoc); } // C++ [base.class.init]p2: @@ -1813,18 +2261,15 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = - InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); - - InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); - - ExprResult BaseInit = - InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + InitializationKind::CreateDirect(BaseLoc, Args.getStartLoc(), + Args.getEndLoc()); + + ExprResult BaseInit = Args.PerformInit(*this, BaseEntity, Kind); if (BaseInit.isInvalid()) return true; - CheckImplicitConversions(BaseInit.get(), LParenLoc); - + CheckImplicitConversions(BaseInit.get(), Args.getStartLoc()); + // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. @@ -1839,24 +2284,27 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // of the information that we have about the base // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) { - ExprResult Init - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, BaseType)); - return new (Context) CXXCtorInitializer(Context, BaseTInfo, - BaseSpec->isVirtual(), - LParenLoc, - Init.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); - } + if (CurContext->isDependentContext()) + BaseInit = Owned(Args.CreateInitExpr(Context, BaseType)); return new (Context) CXXCtorInitializer(Context, BaseTInfo, - BaseSpec->isVirtual(), - LParenLoc, - BaseInit.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); + BaseSpec->isVirtual(), + Args.getStartLoc(), + BaseInit.takeAs<Expr>(), + Args.getEndLoc(), EllipsisLoc); +} + +// Create a static_cast\<T&&>(expr). +static Expr *CastForMoving(Sema &SemaRef, Expr *E) { + QualType ExprType = E->getType(); + QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType); + SourceLocation ExprLoc = E->getLocStart(); + TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( + TargetType, ExprLoc); + + return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E, + SourceRange(ExprLoc, ExprLoc), + E->getSourceRange()).take(); } /// ImplicitInitializerKind - How an implicit base or member initializer should @@ -1889,7 +2337,9 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, break; } + case IIK_Move: case IIK_Copy: { + bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); @@ -1897,17 +2347,22 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Constructor->getLocation(), ParamType, VK_LValue, 0); - + // Cast to the base class to avoid ambiguities. QualType ArgTy = SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), ParamType.getQualifiers()); + if (Moving) { + CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg); + } + CXXCastPath BasePath; BasePath.push_back(BaseSpec); CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, CK_UncheckedDerivedToBase, - VK_LValue, &BasePath).take(); + Moving ? VK_XValue : VK_LValue, + &BasePath).take(); InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), @@ -1918,9 +2373,6 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, MultiExprArg(&CopyCtorArg, 1)); break; } - - case IIK_Move: - assert(false && "Unhandled initializer kind!"); } BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit); @@ -1940,36 +2392,46 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, return false; } +static bool RefersToRValueRef(Expr *MemRef) { + ValueDecl *Referenced = cast<MemberExpr>(MemRef)->getMemberDecl(); + return Referenced->getType()->isRValueReferenceType(); +} + static bool BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, - FieldDecl *Field, + FieldDecl *Field, IndirectFieldDecl *Indirect, CXXCtorInitializer *&CXXMemberInit) { if (Field->isInvalidDecl()) return true; SourceLocation Loc = Constructor->getLocation(); - if (ImplicitInitKind == IIK_Copy) { + if (ImplicitInitKind == IIK_Copy || ImplicitInitKind == IIK_Move) { + bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); // Suppress copying zero-width bitfields. - if (const Expr *Width = Field->getBitWidth()) - if (Width->EvaluateAsInt(SemaRef.Context) == 0) - return false; + if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0) + return false; Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Loc, ParamType, VK_LValue, 0); + if (Moving) { + MemberExprBase = CastForMoving(SemaRef, MemberExprBase); + } + // Build a reference to this field within the parameter. CXXScopeSpec SS; LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc, Sema::LookupMemberName); - MemberLookup.addDecl(Field, AS_public); + MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect) + : cast<ValueDecl>(Field), AS_public); MemberLookup.resolveKind(); - ExprResult CopyCtorArg + ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr(MemberExprBase, ParamType, Loc, /*IsArrow=*/false, @@ -1977,18 +2439,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, /*FirstQualifierInScope=*/0, MemberLookup, /*TemplateArgs=*/0); - if (CopyCtorArg.isInvalid()) + if (CtorArg.isInvalid()) return true; - + + // C++11 [class.copy]p15: + // - if a member m has rvalue reference type T&&, it is direct-initialized + // with static_cast<T&&>(x.m); + if (RefersToRValueRef(CtorArg.get())) { + CtorArg = CastForMoving(SemaRef, CtorArg.take()); + } + // When the field we are copying is an array, create index variables for // each dimension of the array. We use these index variables to subscript // the source array, and other clients (e.g., CodeGen) will perform the // necessary iteration with these index variables. - llvm::SmallVector<VarDecl *, 4> IndexVariables; + SmallVector<VarDecl *, 4> IndexVariables; QualType BaseType = Field->getType(); QualType SizeType = SemaRef.Context.getSizeType(); + bool InitializingArray = false; while (const ConstantArrayType *Array = SemaRef.Context.getAsConstantArrayType(BaseType)) { + InitializingArray = true; // Create the iteration variable for this array index. IdentifierInfo *IterationVarName = 0; { @@ -2009,24 +2480,30 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc); assert(!IterationVarRef.isInvalid() && "Reference to invented variable cannot fail!"); - + // Subscript the array with this iteration variable. - CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CopyCtorArg.take(), - Loc, + CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc, IterationVarRef.take(), - Loc); - if (CopyCtorArg.isInvalid()) + Loc); + if (CtorArg.isInvalid()) return true; - + BaseType = Array->getElementType(); } - + + // The array subscript expression is an lvalue, which is wrong for moving. + if (Moving && InitializingArray) + CtorArg = CastForMoving(SemaRef, CtorArg.take()); + // Construct the entity that we will be initializing. For an array, this // will be first element in the array, which may require several levels // of array-subscript entities. - llvm::SmallVector<InitializedEntity, 4> Entities; + SmallVector<InitializedEntity, 4> Entities; Entities.reserve(1 + IndexVariables.size()); - Entities.push_back(InitializedEntity::InitializeMember(Field)); + if (Indirect) + Entities.push_back(InitializedEntity::InitializeMember(Indirect)); + else + Entities.push_back(InitializedEntity::InitializeMember(Field)); for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, 0, @@ -2036,22 +2513,31 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); - Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>(); + Expr *CtorArgE = CtorArg.takeAs<Expr>(); InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, - &CopyCtorArgE, 1); + &CtorArgE, 1); ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, - MultiExprArg(&CopyCtorArgE, 1)); + MultiExprArg(&CtorArgE, 1)); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; - CXXMemberInit - = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, Loc, - MemberInit.takeAs<Expr>(), Loc, - IndexVariables.data(), - IndexVariables.size()); + if (Indirect) { + assert(IndexVariables.size() == 0 && + "Indirect field improperly initialized"); + CXXMemberInit + = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, + Loc, Loc, + MemberInit.takeAs<Expr>(), + Loc); + } else + CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, + Loc, MemberInit.takeAs<Expr>(), + Loc, + IndexVariables.data(), + IndexVariables.size()); return false; } @@ -2061,7 +2547,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, SemaRef.Context.getBaseElementType(Field->getType()); if (FieldBaseElementType->isRecordType()) { - InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializedEntity InitEntity + = Indirect? InitializedEntity::InitializeMember(Indirect) + : InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); @@ -2073,11 +2561,17 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, if (MemberInit.isInvalid()) return true; - CXXMemberInit = - new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, - Field, Loc, Loc, - MemberInit.get(), - Loc); + if (Indirect) + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, + Indirect, Loc, + Loc, + MemberInit.get(), + Loc); + else + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, + Field, Loc, Loc, + MemberInit.get(), + Loc); return false; } @@ -2129,21 +2623,37 @@ struct BaseAndFieldInfo { bool AnyErrorsInInits; ImplicitInitializerKind IIK; llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields; - llvm::SmallVector<CXXCtorInitializer*, 8> AllToInit; + SmallVector<CXXCtorInitializer*, 8> AllToInit; BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { - // FIXME: Handle implicit move constructors. - if (Ctor->isImplicit() && Ctor->isCopyConstructor()) + bool Generated = Ctor->isImplicit() || Ctor->isDefaulted(); + if (Generated && Ctor->isCopyConstructor()) IIK = IIK_Copy; + else if (Generated && Ctor->isMoveConstructor()) + IIK = IIK_Move; else IIK = IIK_Default; } }; } +/// \brief Determine whether the given indirect field declaration is somewhere +/// within an anonymous union. +static bool isWithinAnonymousUnion(IndirectFieldDecl *F) { + for (IndirectFieldDecl::chain_iterator C = F->chain_begin(), + CEnd = F->chain_end(); + C != CEnd; ++C) + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((*C)->getDeclContext())) + if (Record->isUnion()) + return true; + + return false; +} + static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, - FieldDecl *Top, FieldDecl *Field) { + FieldDecl *Field, + IndirectFieldDecl *Indirect = 0) { // Overwhelmingly common case: we have a direct initializer for this field. if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) { @@ -2155,53 +2665,26 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer()) { - Info.AllToInit.push_back( - new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, - SourceLocation(), - SourceLocation(), 0, - SourceLocation())); + CXXCtorInitializer *Init; + if (Indirect) + Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, + SourceLocation(), + SourceLocation(), 0, + SourceLocation()); + else + Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + SourceLocation(), + SourceLocation(), 0, + SourceLocation()); + Info.AllToInit.push_back(Init); return false; } - if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { - const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); - assert(FieldClassType && "anonymous struct/union without record type"); - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - - // Even though union members never have non-trivial default - // constructions in C++03, we still build member initializers for aggregate - // record types which can be union members, and C++0x allows non-trivial - // default constructors for union members, so we ensure that only one - // member is initialized for these. - if (FieldClassDecl->isUnion()) { - // First check for an explicit initializer for one field. - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(*FA)) { - Info.AllToInit.push_back(Init); - - // Once we've initialized a field of an anonymous union, the union - // field in the class is also initialized, so exit immediately. - return false; - } else if ((*FA)->isAnonymousStructOrUnion()) { - if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) - return true; - } - } - - // FIXME: C++0x unrestricted unions might call a default constructor here. - return false; - } else { - // For structs, we simply descend through to initialize all members where - // necessary. - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) - return true; - } - } - } + // Don't build an implicit initializer for union members if none was + // explicitly specified. + if (Field->getParent()->isUnion() || + (Indirect && isWithinAnonymousUnion(Indirect))) + return false; // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be @@ -2210,7 +2693,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, return false; CXXCtorInitializer *Init = 0; - if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init)) + if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, + Indirect, Init)) return true; if (Init) @@ -2238,12 +2722,12 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, return false; } - + bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { - if (Constructor->getDeclContext()->isDependentContext()) { + if (Constructor->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { @@ -2330,15 +2814,51 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, } // Fields. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - if ((*Field)->getType()->isIncompleteArrayType()) { - assert(ClassDecl->hasFlexibleArrayMember() && - "Incomplete array type is not valid"); + for (DeclContext::decl_iterator Mem = ClassDecl->decls_begin(), + MemEnd = ClassDecl->decls_end(); + Mem != MemEnd; ++Mem) { + if (FieldDecl *F = dyn_cast<FieldDecl>(*Mem)) { + // C++ [class.bit]p2: + // A declaration for a bit-field that omits the identifier declares an + // unnamed bit-field. Unnamed bit-fields are not members and cannot be + // initialized. + if (F->isUnnamedBitfield()) + continue; + + if (F->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // If we're not generating the implicit copy/move constructor, then we'll + // handle anonymous struct/union fields based on their individual + // indirect fields. + if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default) + continue; + + if (CollectFieldInitializer(*this, Info, F)) + HadError = true; continue; } - if (CollectFieldInitializer(*this, Info, *Field, *Field)) - HadError = true; + + // Beyond this point, we only consider default initialization. + if (Info.IIK != IIK_Default) + continue; + + if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) { + if (F->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // Initialize each field of an anonymous struct individually. + if (CollectFieldInitializer(*this, Info, F->getAnonField(), F)) + HadError = true; + + continue; + } } NumInitializers = Info.AllToInit.size(); @@ -2414,7 +2934,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, CXXCtorInitializer *Init = Inits[InitIndex]; if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order, Init->getSourceLocation()) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { ShouldCheckOrder = true; break; } @@ -2425,7 +2945,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // Build the list of bases and members in the order that they'll // actually be initialized. The explicit initializers should be in // this same order but may be missing things. - llvm::SmallVector<const void*, 32> IdealInitKeys; + SmallVector<const void*, 32> IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); @@ -2445,9 +2965,13 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) + E = ClassDecl->field_end(); Field != E; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - + } + unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; @@ -2561,7 +3085,8 @@ bool CheckRedundantUnionInit(Sema &S, /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **meminits, unsigned NumMemInits, + CXXCtorInitializer **meminits, + unsigned NumMemInits, bool AnyErrors) { if (!ConstructorDecl) return; @@ -2630,8 +3155,9 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXRecordDecl *ClassDecl) { - // Ignore dependent contexts. - if (ClassDecl->isDependentContext()) + // Ignore dependent contexts. Also ignore unions, since their members never + // have destructors implicitly called. + if (ClassDecl->isDependentContext() || ClassDecl->isUnion()) return; // FIXME: all the access-control diagnostics are positioned on the @@ -2903,6 +3429,7 @@ struct CheckAbstractUsage { CheckPolymorphic(ReferenceTypeLoc) CheckPolymorphic(MemberPointerTypeLoc) CheckPolymorphic(BlockPointerTypeLoc) + CheckPolymorphic(AtomicTypeLoc) /// Handle all the types we haven't given a more specific /// implementation for above. @@ -3016,7 +3543,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { - if (F->hasInClassInitializer()) + if (F->hasInClassInitializer() || F->isUnnamedBitfield()) continue; if (F->getType()->isReferenceType() || @@ -3077,6 +3604,47 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that member function to be + // const. [...] The class of which that function is a member shall be + // a literal type. + // + // It's fine to diagnose constructors here too: such constructors cannot + // produce a constant expression, so are ill-formed (no diagnostic required). + // + // If the class has virtual bases, any constexpr members will already have + // been diagnosed by the checks performed on the member declaration, so + // suppress this (less useful) diagnostic. + if (LangOpts.CPlusPlus0x && !Record->isDependentType() && + !Record->isLiteral() && !Record->getNumVBases()) { + for (CXXRecordDecl::method_iterator M = Record->method_begin(), + MEnd = Record->method_end(); + M != MEnd; ++M) { + if ((*M)->isConstexpr()) { + switch (Record->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // If a template instantiates to a non-literal type, but its members + // instantiate to constexpr functions, the template is technically + // ill-formed, but we allow it for sanity. Such members are treated as + // non-constexpr. + (*M)->setConstexpr(false); + continue; + + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record), + PDiag(diag::err_constexpr_method_non_literal)); + break; + } + + // Only produce one error per class. + break; + } + } + } + // Declare inherited constructors. We do this eagerly here because: // - The standard requires an eager diagnostic for conflicting inherited // constructors from different classes. @@ -3114,12 +3682,14 @@ void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { break; case CXXMoveConstructor: + CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI)); + break; + case CXXMoveAssignment: - Diag(MI->getLocation(), diag::err_defaulted_move_unsupported); + CheckExplicitlyDefaultedMoveAssignment(*MI); break; - default: - // FIXME: Do moves once they exist + case CXXInvalid: llvm_unreachable("non-special member explicitly defaulted!"); } } @@ -3176,7 +3746,7 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { return; } - if (ShouldDeleteDefaultConstructor(CD)) { + if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { @@ -3243,7 +3813,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { return; } - if (ShouldDeleteCopyConstructor(CD)) { + if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { @@ -3288,7 +3858,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); QualType ArgType = OperType->getArgType(0); - if (!ArgType->isReferenceType()) { + if (!ArgType->isLValueReferenceType()) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); HadError = true; } else { @@ -3340,6 +3910,155 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { } } +void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor()); + + // Whether this was the first-declared instance of the constructor. + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 1) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(CD->getParent())); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + // Check for parameter type matching. + // This is a move ctor so we know it's a cv-qualified rvalue reference to T. + QualType ArgType = CtorType->getArgType(0); + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param); + HadError = true; + } + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXMoveConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXMoveConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { + assert(MD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the operator + bool First = MD == MD->getCanonicalDecl(); + + bool HadError = false; + if (MD->getNumParams() != 1) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_params) + << MD->getSourceRange(); + HadError = true; + } + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + if (!ReturnType->isLValueReferenceType() || + !Context.hasSameType( + Context.getCanonicalType(ReturnType->getPointeeType()), + Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type); + HadError = true; + } + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(MD->getParent())); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + QualType ArgType = OperType->getArgType(0); + if (!ArgType->isRValueReferenceType()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref); + HadError = true; + } else { + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param); + HadError = true; + } + } + + if (OperType->getTypeQuals()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals); + HadError = true; + } + + if (OperType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXMoveAssignment, + PDiag(), + ExceptionType, SourceLocation(), + OperType, MD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.RefQualifier = OperType->getRefQualifier(); + EPI.ExtInfo = OperType->getExtInfo(); + MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + } + + if (HadError) { + MD->setInvalidDecl(); + return; + } + + if (ShouldDeleteMoveAssignmentOperator(MD)) { + if (First) { + MD->setDeletedAsWritten(); + } else { + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXMoveAssignment; + MD->setInvalidDecl(); + } + } +} + void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { assert(DD->isExplicitlyDefaulted()); @@ -3381,30 +4100,53 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { } } -bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { - CXXRecordDecl *RD = CD->getParent(); +/// This function implements the following C++0x paragraphs: +/// - [class.ctor]/5 +/// - [class.copy]/11 +bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) { + assert(!MD->isInvalidDecl()); + CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; - SourceLocation Loc = CD->getLocation(); + bool IsUnion = RD->isUnion(); + bool IsConstructor = false; + bool IsAssignment = false; + bool IsMove = false; + + bool ConstArg = false; - // Do access control from the constructor - ContextRAII CtorContext(*this, CD); + switch (CSM) { + case CXXDefaultConstructor: + IsConstructor = true; + break; + case CXXCopyConstructor: + IsConstructor = true; + ConstArg = MD->getParamDecl(0)->getType().isConstQualified(); + break; + case CXXMoveConstructor: + IsConstructor = true; + IsMove = true; + break; + default: + llvm_unreachable("function only currently implemented for default ctors"); + } + + SourceLocation Loc = MD->getLocation(); + + // Do access control from the special member function + ContextRAII MethodContext(*this, MD); - bool Union = RD->isUnion(); bool AllConst = true; // We do this because we should never actually use an anonymous // union's constructor. - if (Union && RD->isAnonymousStructOrUnion()) + if (IsUnion && RD->isAnonymousStructOrUnion()) return false; // FIXME: We should put some diagnostic logic right into this function. - // C++0x [class.ctor]/5 - // A defaulted default constructor for class X is defined as deleted if: - for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) { @@ -3415,26 +4157,41 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [direct base class] has a type with a destructor that is - // deleted or inaccessible from the defaulted default constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; + // Unless we have an assignment operator, the base's destructor must + // be accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } - // -- any [direct base class either] has no default constructor or - // overload resolution as applied to [its] default constructor - // results in an ambiguity or in a function that is deleted or - // inaccessible from the defaulted default constructor - CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); - if (!BaseDefault || BaseDefault->isDeleted()) - return true; + // Finding the corresponding member in the base should lead to a + // unique, accessible, non-deleted function. If we are doing + // a destructor, we have already checked this case. + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + CXXMethodDecl *BaseMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember); + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), + PDiag()) != AR_accessible) + return true; - if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), - PDiag()) != AR_accessible) - return true; + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !BaseCtor->isMoveConstructor() && + !BaseDecl->isTriviallyCopyable()) + return true; + } + } } for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), @@ -3443,69 +4200,76 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [virtual base class] has a type with a destructor that is - // delete or inaccessible from the defaulted default constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; + // Unless we have an assignment operator, the base's destructor must + // be accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } - // -- any [virtual base class either] has no default constructor or - // overload resolution as applied to [its] default constructor - // results in an ambiguity or in a function that is deleted or - // inaccessible from the defaulted default constructor - CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); - if (!BaseDefault || BaseDefault->isDeleted()) - return true; + // Finding the corresponding member in the base should lead to a + // unique, accessible, non-deleted function. + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + CXXMethodDecl *BaseMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember); + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), + PDiag()) != AR_accessible) + return true; - if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), - PDiag()) != AR_accessible) - return true; + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !BaseCtor->isMoveConstructor() && + !BaseDecl->isTriviallyCopyable()) + return true; + } + } } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { - if (FI->isInvalidDecl()) + if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) continue; QualType FieldType = Context.getBaseElementType(FI->getType()); CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); - // -- any non-static data member with no brace-or-equal-initializer is of - // reference type - if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) - return true; - - // -- X is a union and all its variant members are of const-qualified type - // (or array thereof) - if (Union && !FieldType.isConstQualified()) - AllConst = false; - - if (FieldRecord) { - // -- X is a union-like class that has a variant member with a non-trivial - // default constructor - if (Union && !FieldRecord->hasTrivialDefaultConstructor()) + // For a default constructor, all references must be initialized in-class + // and, if a union, it must have a non-const member. + if (CSM == CXXDefaultConstructor) { + if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) return true; - CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); - if (FieldDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != - AR_accessible) + if (IsUnion && !FieldType.isConstQualified()) + AllConst = false; + // For a copy constructor, data members must not be of rvalue reference + // type. + } else if (CSM == CXXCopyConstructor) { + if (FieldType->isRValueReferenceType()) return true; + } - // -- any non-variant non-static data member of const-qualified type (or - // array thereof) with no brace-or-equal-initializer does not have a - // user-provided default constructor - if (FieldType.isConstQualified() && + if (FieldRecord) { + // For a default constructor, a const member must have a user-provided + // default constructor or else be explicitly initialized. + if (CSM == CXXDefaultConstructor && FieldType.isConstQualified() && !FI->hasInClassInitializer() && !FieldRecord->hasUserProvidedDefaultConstructor()) return true; - if (!Union && FieldRecord->isUnion() && + // Some additional restrictions exist on the variant members. + if (!IsUnion && FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { // We're okay to reuse AllConst here since we only care about the // value otherwise if we're in a union. @@ -3521,12 +4285,49 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { if (!UnionFieldType.isConstQualified()) AllConst = false; - if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialDefaultConstructor()) - return true; + if (UnionFieldRecord) { + // FIXME: Checking for accessibility and validity of this + // destructor is technically going beyond the + // standard, but this is believed to be a defect. + if (!IsAssignment) { + CXXDestructorDecl *FieldDtor = LookupDestructor(UnionFieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + if (!FieldDtor->isTrivial()) + return true; + } + + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(UnionFieldRecord, CSM, ConstArg, false, + false, false, false); + // FIXME: Checking for accessibility and validity of this + // corresponding member is technically going beyond the + // standard, but this is believed to be a defect. + if (!SMOR->hasSuccess()) + return true; + + CXXMethodDecl *FieldMember = SMOR->getMethod(); + // A member of a union must have a trivial corresponding + // constructor. + if (!FieldMember->isTrivial()) + return true; + + if (IsConstructor) { + CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember); + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } + } } - if (AllConst) + // At least one member in each anonymous union must be non-const + if (CSM == CXXDefaultConstructor && AllConst) return true; // Don't try to initialize the anonymous union @@ -3534,51 +4335,81 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { continue; } - // -- any non-static data member with no brace-or-equal-initializer has - // class type M (or array thereof) and either M has no default - // constructor or overload resolution as applied to M's default - // constructor results in an ambiguity or in a function that is deleted - // or inaccessible from the defaulted default constructor. - if (!FI->hasInClassInitializer()) { - CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); - if (!FieldDefault || FieldDefault->isDeleted()) + // Unless we're doing assignment, the field's destructor must be + // accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) return true; - if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), - PDiag()) != AR_accessible) + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + } + + // Check that the corresponding member of the field is accessible, + // unique, and non-deleted. We don't do this if it has an explicit + // initialization when default-constructing. + if (CSM != CXXDestructor && + (CSM != CXXDefaultConstructor || !FI->hasInClassInitializer())) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(FieldRecord, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + + CXXMethodDecl *FieldMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember); + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !FieldCtor->isMoveConstructor() && + !FieldRecord->isTriviallyCopyable()) + return true; + } + + // We need the corresponding member of a union to be trivial so that + // we can safely copy them all simultaneously. + // FIXME: Note that performing the check here (where we rely on the lack + // of an in-class initializer) is technically ill-formed. However, this + // seems most obviously to be a bug in the standard. + if (IsUnion && !FieldMember->isTrivial()) return true; } - } else if (!Union && FieldType.isConstQualified() && - !FI->hasInClassInitializer()) { - // -- any non-variant non-static data member of const-qualified type (or - // array thereof) with no brace-or-equal-initializer does not have a - // user-provided default constructor + } else if (CSM == CXXDefaultConstructor && !IsUnion && + FieldType.isConstQualified() && !FI->hasInClassInitializer()) { + // We can't initialize a const member of non-class type to any value. return true; } } - if (Union && AllConst) + // We can't have all const members in a union when default-constructing, + // or else they're all nonsensical garbage values that can't be changed. + if (CSM == CXXDefaultConstructor && IsUnion && AllConst) return true; return false; } -bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { - CXXRecordDecl *RD = CD->getParent(); +bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; - SourceLocation Loc = CD->getLocation(); + SourceLocation Loc = MD->getLocation(); // Do access control from the constructor - ContextRAII CtorContext(*this, CD); + ContextRAII MethodContext(*this, MD); bool Union = RD->isUnion(); - assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() && - "copy assignment arg has no pointee type"); unsigned ArgQuals = - CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? + MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? Qualifiers::Const : 0; // We do this because we should never actually use an anonymous @@ -3588,8 +4419,9 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { // FIXME: We should put some diagnostic logic right into this function. - // C++0x [class.copy]/11 - // A defaulted [copy] constructor for class X is defined as delete if X has: + // C++0x [class.copy]/20 + // A defaulted [copy] assignment operator for class X is defined as deleted + // if X has: for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); @@ -3602,24 +4434,15 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [direct base class] of a type with a destructor that is deleted or - // inaccessible from the defaulted constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; - // -- a [direct base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] constructor, results in an - // ambiguity or a function that is deleted or inaccessible from the - // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); - if (!BaseCtor || BaseCtor->isDeleted()) + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != - AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } @@ -3630,35 +4453,32 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [virtual base class] of a type with a destructor that is deleted or - // inaccessible from the defaulted constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; - // -- a [virtual base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] constructor, results in an - // ambiguity or a function that is deleted or inaccessible from the - // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); - if (!BaseCtor || BaseCtor->isDeleted()) + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != - AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); - // -- for a copy constructor, a non-static data member of rvalue reference - // type - if (FieldType->isRValueReferenceType()) + // -- a non-static data member of reference type + if (FieldType->isReferenceType()) + return true; + + // -- a non-static data member of const non-class type (or array thereof) + if (FieldType.isConstQualified() && !FieldType->isRecordType()) return true; CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); @@ -3675,42 +4495,27 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); - // -- a variant member with a non-trivial [copy] constructor and X - // is a union-like class + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialCopyConstructor()) + !UnionFieldRecord->hasTrivialCopyAssignment()) return true; } } // Don't try to initalize an anonymous union continue; - } else { - // -- a variant member with a non-trivial [copy] constructor and X is a - // union-like class - if (Union && !FieldRecord->hasTrivialCopyConstructor()) - return true; - - // -- any [non-static data member] of a type with a destructor that is - // deleted or inaccessible from the defaulted constructor - CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); - if (FieldDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != - AR_accessible) + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { return true; } - // -- a [non-static data member of class type (or array thereof)] B that - // cannot be [copied] because overload resolution, as applied to B's - // [copy] constructor, results in an ambiguity or a function that is - // deleted or inaccessible from the defaulted constructor - CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord, - ArgQuals); - if (!FieldCtor || FieldCtor->isDeleted()) + CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals, + false, 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), - PDiag()) != AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } } @@ -3718,7 +4523,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { return false; } -bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { +bool Sema::ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) @@ -3731,66 +4536,52 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { bool Union = RD->isUnion(); - unsigned ArgQuals = - MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? - Qualifiers::Const : 0; - // We do this because we should never actually use an anonymous // union's constructor. if (Union && RD->isAnonymousStructOrUnion()) return false; - // FIXME: We should put some diagnostic logic right into this function. - - // C++0x [class.copy]/11 - // A defaulted [copy] assignment operator for class X is defined as deleted + // C++0x [class.copy]/20 + // A defaulted [move] assignment operator for class X is defined as deleted // if X has: + // -- for the move constructor, [...] any direct or indirect virtual base + // class. + if (RD->getNumVBases() != 0) + return true; + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) { - // We'll handle this one later - if (BI->isVirtual()) - continue; QualType BaseType = BI->getType(); CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- a [direct base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] assignment operator, results in + // -- a [direct base class] B that cannot be [moved] because overload + // resolution, as applied to B's [move] assignment operator, results in // an ambiguity or a function that is deleted or inaccessible from the // assignment operator - CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, - 0); - if (!CopyOper || CopyOper->isDeleted()) + CXXMethodDecl *MoveOper = LookupMovingAssignment(BaseDecl, false, 0); + if (!MoveOper || MoveOper->isDeleted()) return true; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) + if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible) return true; - } - for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), - BE = RD->vbases_end(); - BI != BE; ++BI) { - QualType BaseType = BI->getType(); - CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); - assert(BaseDecl && "base isn't a CXXRecordDecl"); - - // -- a [virtual base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] assignment operator, results in - // an ambiguity or a function that is deleted or inaccessible from the - // assignment operator - CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, - 0); - if (!CopyOper || CopyOper->isDeleted()) - return true; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) + // -- for the move assignment operator, a [direct base class] with a type + // that does not have a move assignment operator and is not trivially + // copyable. + if (!MoveOper->isMoveAssignmentOperator() && + !BaseDecl->isTriviallyCopyable()) return true; } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); // -- a non-static data member of reference type @@ -3800,7 +4591,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { // -- a non-static data member of const non-class type (or array thereof) if (FieldType.isConstQualified() && !FieldType->isRecordType()) return true; - + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); if (FieldRecord) { @@ -3815,28 +4606,34 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); - // -- a variant member with a non-trivial [copy] assignment operator + // -- a variant member with a non-trivial [move] assignment operator // and X is a union-like class if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialCopyAssignment()) + !UnionFieldRecord->hasTrivialMoveAssignment()) return true; } } // Don't try to initalize an anonymous union continue; - // -- a variant member with a non-trivial [copy] assignment operator + // -- a variant member with a non-trivial [move] assignment operator // and X is a union-like class - } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { + } else if (Union && !FieldRecord->hasTrivialMoveAssignment()) { return true; } - CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals, - false, 0); - if (!CopyOper || CopyOper->isDeleted()) - return false; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) - return false; + CXXMethodDecl *MoveOper = LookupMovingAssignment(FieldRecord, false, 0); + if (!MoveOper || MoveOper->isDeleted()) + return true; + if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible) + return true; + + // -- for the move assignment operator, a [non-static data member] with a + // type that does not have a move assignment operator and is not + // trivially copyable. + if (!MoveOper->isMoveAssignmentOperator() && + !FieldRecord->isTriviallyCopyable()) + return true; } } @@ -3959,7 +4756,7 @@ namespace { Sema *S; CXXMethodDecl *Method; llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; - llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods; + SmallVector<CXXMethodDecl *, 8> OverloadedMethods; }; } @@ -3978,7 +4775,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, assert(Name.getNameKind() == DeclarationName::Identifier); bool foundSameNameMethod = false; - llvm::SmallVector<CXXMethodDecl *, 8> overloadedMethods; + SmallVector<CXXMethodDecl *, 8> overloadedMethods; for (Path.Decls = BaseRecord->lookup(Name); Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { @@ -4009,7 +4806,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, /// overriding any. void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual, - MD->getLocation()) == Diagnostic::Ignored) + MD->getLocation()) == DiagnosticsEngine::Ignored) return; if (MD->getDeclName().getNameKind() != DeclarationName::Identifier) return; @@ -4058,10 +4855,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, AdjustDeclIfTemplate(TagDecl); - ActOnFields(S, RLoc, TagDecl, + ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( // strict aliasing violation! reinterpret_cast<Decl**>(FieldCollector->getCurFields()), - FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); + FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); CheckCompletedCXXClass( dyn_cast_or_null<CXXRecordDecl>(TagDecl)); @@ -4946,7 +5743,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, IdentLoc, Named, CommonAncestor); if (IsUsingDirectiveInToplevelContext(CurContext) && - !SourceMgr.isFromMainFile(SourceMgr.getInstantiationLoc(IdentLoc))) { + !SourceMgr.isFromMainFile(SourceMgr.getExpansionLoc(IdentLoc))) { Diag(IdentLoc, diag::warn_using_directive_in_header); } @@ -5361,7 +6158,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); - R.setUsingDeclaration(true); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration @@ -5968,7 +6764,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); @@ -5981,7 +6779,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); - if (ShouldDeleteDefaultConstructor(DefaultCon)) + if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) DefaultCon->setDeletedAsWritten(); return DefaultCon; @@ -6075,7 +6873,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further // processing. - typedef llvm::SmallVector<const RecordType *, 4> BasesVector; + typedef SmallVector<const RecordType *, 4> BasesVector; BasesVector BasesToInheritFrom; for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), BaseE = ClassDecl->bases_end(); @@ -6171,7 +6969,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { if (params == maxParams) NewCtorType = BaseCtorType; else { - llvm::SmallVector<QualType, 16> Args; + SmallVector<QualType, 16> Args; for (unsigned i = 0; i < params; ++i) { Args.push_back(BaseCtorType->getArgType(i)); } @@ -6219,16 +7017,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // OK, we're there, now add the constructor. // C++0x [class.inhctor]p8: [...] that would be performed by a - // user-writtern inline constructor [...] + // user-written inline constructor [...] DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true); + /*ImplicitlyDeclared=*/true, + // FIXME: Due to a defect in the standard, we treat inherited + // constructors as constexpr even if that makes them ill-formed. + /*Constexpr=*/BaseCtor->isConstexpr()); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. - llvm::SmallVector<ParmVarDecl *, 16> ParamDecls; + SmallVector<ParmVarDecl *, 16> ParamDecls; for (unsigned i = 0; i < params; ++i) { ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc, UsingLoc, @@ -6237,7 +7038,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { /*TInfo=*/0, SC_None, SC_None, /*DefaultArg=*/0)); } - NewCtor->setParams(ParamDecls.data(), ParamDecls.size()); + NewCtor->setParams(ParamDecls); NewCtor->setInheritedConstructor(BaseCtor); PushOnScopeChains(NewCtor, S, false); @@ -6365,7 +7166,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, SourceLocation Loc = Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); - + Destructor->setImplicitlyDefined(true); Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -6388,8 +7189,10 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, ImplicitExceptionSpecification exceptSpec = ComputeDefaultedDtorExceptionSpec(classDecl); - // Replace the destructor's type. - FunctionProtoType::ExtProtoInfo epi; + // Replace the destructor's type, building off the existing one. Fortunately, + // the only thing of interest in the destructor type is its extended info. + // The return and arguments are fixed. + FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); epi.NumExceptions = exceptSpec.size(); epi.Exceptions = exceptSpec.data(); @@ -6403,41 +7206,45 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, // However, we don't have a body yet, so it needs to be done somewhere else. } -/// \brief Builds a statement that copies the given entity from \p From to +/// \brief Builds a statement that copies/moves the given entity from \p From to /// \c To. /// -/// This routine is used to copy the members of a class with an -/// implicitly-declared copy assignment operator. When the entities being +/// This routine is used to copy/move the members of a class with an +/// implicitly-declared copy/move assignment operator. When the entities being /// copied are arrays, this routine builds for loops to copy them. /// /// \param S The Sema object used for type-checking. /// -/// \param Loc The location where the implicit copy is being generated. +/// \param Loc The location where the implicit copy/move is being generated. /// -/// \param T The type of the expressions being copied. Both expressions must -/// have this type. +/// \param T The type of the expressions being copied/moved. Both expressions +/// must have this type. /// -/// \param To The expression we are copying to. +/// \param To The expression we are copying/moving to. /// -/// \param From The expression we are copying from. +/// \param From The expression we are copying/moving from. /// -/// \param CopyingBaseSubobject Whether we're copying a base subobject. +/// \param CopyingBaseSubobject Whether we're copying/moving a base subobject. /// Otherwise, it's a non-static member subobject. /// +/// \param Copying Whether we're copying or moving. +/// /// \param Depth Internal parameter recording the depth of the recursion. /// /// \returns A statement or a loop that copies the expressions. static StmtResult BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Expr *To, Expr *From, - bool CopyingBaseSubobject, unsigned Depth = 0) { - // C++0x [class.copy]p30: + bool CopyingBaseSubobject, bool Copying, + unsigned Depth = 0) { + // C++0x [class.copy]p28: // Each subobject is assigned in the manner appropriate to its type: // - // - if the subobject is of class type, the copy assignment operator - // for the class is used (as if by explicit qualification; that is, - // ignoring any possible virtual overriding functions in more derived - // classes); + // - if the subobject is of class type, as if by a call to operator= with + // the subobject as the object expression and the corresponding + // subobject of x as a single function argument (as if by explicit + // qualification; that is, ignoring any possible virtual overriding + // functions in more derived classes); if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -6447,14 +7254,15 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(OpLookup, ClassDecl, false); - // Filter out any result that isn't a copy-assignment operator. + // Filter out any result that isn't a copy/move-assignment operator. LookupResult::Filter F = OpLookup.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - if (Method->isCopyAssignmentOperator()) + if (Copying ? Method->isCopyAssignmentOperator() : + Method->isMoveAssignmentOperator()) continue; - + F.erase(); } F.done(); @@ -6573,11 +7381,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, IterationVarRef, Loc)); To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc, IterationVarRef, Loc)); - - // Build the copy for an individual element of the array. + if (!Copying) // Cast to rvalue + From = CastForMoving(S, From); + + // Build the copy/move for an individual element of the array. StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), To, From, CopyingBaseSubobject, - Depth + 1); + Copying, Depth + 1); if (Copy.isInvalid()) return StmtError(); @@ -6733,7 +7543,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, - /*isInline=*/true, + /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); @@ -6746,7 +7556,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ArgType, /*TInfo=*/0, SC_None, SC_None, 0); - CopyAssignment->setParams(&FromParam, 1); + CopyAssignment->setParams(FromParam); // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; @@ -6857,7 +7667,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, To.get(), From, - /*CopyingBaseSubobject=*/true); + /*CopyingBaseSubobject=*/true, + /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); @@ -6878,6 +7689,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + // Check for members of reference type; we can't copy those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) @@ -6902,9 +7716,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } // Suppress assigning zero-width bitfields. - if (const Expr *Width = Field->getBitWidth()) - if (Width->EvaluateAsInt(Context) == 0) - continue; + if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + continue; QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { @@ -6932,8 +7745,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // explicit assignments, do so. This optimization only applies for arrays // of scalars and arrays of class type with trivial copy-assignment // operators. - if (FieldType->isArrayType() && - BaseType.hasTrivialCopyAssignment(Context)) { + if (FieldType->isArrayType() && !FieldType.isVolatileQualified() + && BaseType.hasTrivialAssignment(Context, /*Copying=*/true)) { // Compute the size of the memory buffer to be copied. QualType SizeType = Context.getSizeType(); llvm::APInt Size(Context.getTypeSize(SizeType), @@ -7020,8 +7833,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy of this field. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, - To.get(), From.get(), - /*CopyingBaseSubobject=*/false); + To.get(), From.get(), + /*CopyingBaseSubobject=*/false, + /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); @@ -7066,6 +7880,436 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { + ImplicitExceptionSpecification ExceptSpec(Context); + + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // C++0x [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + + // It is unspecified whether or not an implicit move assignment operator + // attempts to deduplicate calls to assignment operators of virtual bases are + // made. As such, this exception specification is effectively unspecified. + // Based on a similar decision made for constness in C++0x, we're erring on + // the side of assuming such calls to be made regardless of whether they + // actually happen. + // Note that a move constructor is not implicitly declared when there are + // virtual bases, but it can still be user-declared and explicitly defaulted. + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + BaseEnd = ClassDecl->bases_end(); + Base != BaseEnd; ++Base) { + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + Base != BaseEnd; ++Base) { + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; + ++Field) { + QualType FieldType = Context.getBaseElementType((*Field)->getType()); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + } + + return ExceptSpec; +} + +CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { + // Note: The following rules are largely analoguous to the move + // constructor rules. + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl)); + + QualType ArgType = Context.getTypeDeclType(ClassDecl); + QualType RetType = Context.getLValueReferenceType(ArgType); + ArgType = Context.getRValueReferenceType(ArgType); + + // An implicitly-declared move assignment operator is an inline public + // member of its class. + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); + CXXMethodDecl *MoveAssignment + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(RetType, &ArgType, 1, EPI), + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/SC_None, + /*isInline=*/true, + /*isConstexpr=*/false, + SourceLocation()); + MoveAssignment->setAccess(AS_public); + MoveAssignment->setDefaulted(); + MoveAssignment->setImplicit(); + MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); + + // Add the parameter to the operator. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, + ClassLoc, ClassLoc, /*Id=*/0, + ArgType, /*TInfo=*/0, + SC_None, + SC_None, 0); + MoveAssignment->setParams(FromParam); + + // Note that we have added this copy-assignment operator. + ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + + // C++0x [class.copy]p9: + // If the definition of a class X does not explicitly declare a move + // assignment operator, one will be implicitly declared as defaulted if and + // only if: + // [...] + // - the move assignment operator would not be implicitly defined as + // deleted. + if (ShouldDeleteMoveAssignmentOperator(MoveAssignment)) { + // Cache this result so that we don't try to generate this over and over + // on every lookup, leaking memory and wasting time. + ClassDecl->setFailedImplicitMoveAssignment(); + return 0; + } + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(MoveAssignment, S, false); + ClassDecl->addDecl(MoveAssignment); + + AddOverriddenMethods(ClassDecl, MoveAssignment); + return MoveAssignment; +} + +void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MoveAssignOperator) { + assert((MoveAssignOperator->isDefaulted() && + MoveAssignOperator->isOverloadedOperator() && + MoveAssignOperator->getOverloadedOperator() == OO_Equal && + !MoveAssignOperator->doesThisDeclarationHaveABody()) && + "DefineImplicitMoveAssignment called for wrong function"); + + CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); + + if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { + MoveAssignOperator->setInvalidDecl(); + return; + } + + MoveAssignOperator->setUsed(); + + ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator); + DiagnosticErrorTrap Trap(Diags); + + // C++0x [class.copy]p28: + // The implicitly-defined or move assignment operator for a non-union class + // X performs memberwise move assignment of its subobjects. The direct base + // classes of X are assigned first, in the order of their declaration in the + // base-specifier-list, and then the immediate non-static data members of X + // are assigned, in the order in which they were declared in the class + // definition. + + // The statements that form the synthesized function body. + ASTOwningVector<Stmt*> Statements(*this); + + // The parameter for the "other" object, which we are move from. + ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); + QualType OtherRefType = Other->getType()-> + getAs<RValueReferenceType>()->getPointeeType(); + assert(OtherRefType.getQualifiers() == 0 && + "Bad argument type of defaulted move assignment"); + + // Our location for everything implicitly-generated. + SourceLocation Loc = MoveAssignOperator->getLocation(); + + // Construct a reference to the "other" object. We'll be using this + // throughout the generated ASTs. + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); + assert(OtherRef && "Reference to parameter cannot fail!"); + // Cast to rvalue. + OtherRef = CastForMoving(*this, OtherRef); + + // Construct the "this" pointer. We'll be using this throughout the generated + // ASTs. + Expr *This = ActOnCXXThis(Loc).takeAs<Expr>(); + assert(This && "Reference to this cannot fail!"); + + // Assign base classes. + bool Invalid = false; + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Form the assignment: + // static_cast<Base*>(this)->Base::operator=(static_cast<Base&&>(other)); + QualType BaseType = Base->getType().getUnqualifiedType(); + if (!BaseType->isRecordType()) { + Invalid = true; + continue; + } + + CXXCastPath BasePath; + BasePath.push_back(Base); + + // Construct the "from" expression, which is an implicit cast to the + // appropriately-qualified base type. + Expr *From = OtherRef; + From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase, + VK_XValue, &BasePath).take(); + + // Dereference "this". + ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); + + // Implicitly cast "this" to the appropriately-qualified base type. + To = ImpCastExprToType(To.take(), + Context.getCVRQualifiedType(BaseType, + MoveAssignOperator->getTypeQualifiers()), + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); + + // Build the move. + StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType, + To.get(), From, + /*CopyingBaseSubobject=*/true, + /*Copying=*/false); + if (Move.isInvalid()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + MoveAssignOperator->setInvalidDecl(); + return; + } + + // Success! Record the move. + Statements.push_back(Move.takeAs<Expr>()); + } + + // \brief Reference to the __builtin_memcpy function. + Expr *BuiltinMemCpyRef = 0; + // \brief Reference to the __builtin_objc_memmove_collectable function. + Expr *CollectableMemCpyRef = 0; + + // Assign non-static members. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + // Check for members of reference type; we can't move those. + if (Field->getType()->isReferenceType()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + continue; + } + + // Check for members of const-qualified, non-class type. + QualType BaseType = Context.getBaseElementType(Field->getType()); + if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + continue; + } + + // Suppress assigning zero-width bitfields. + if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + continue; + + QualType FieldType = Field->getType().getNonReferenceType(); + if (FieldType->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // Build references to the field in the object we're copying from and to. + CXXScopeSpec SS; // Intentionally empty + LookupResult MemberLookup(*this, Field->getDeclName(), Loc, + LookupMemberName); + MemberLookup.addDecl(*Field); + MemberLookup.resolveKind(); + ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); + ExprResult To = BuildMemberReferenceExpr(This, This->getType(), + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); + assert(!From.isInvalid() && "Implicit field reference cannot fail"); + assert(!To.isInvalid() && "Implicit field reference cannot fail"); + + assert(!From.get()->isLValue() && // could be xvalue or prvalue + "Member reference with rvalue base must be rvalue except for reference " + "members, which aren't allowed for move assignment."); + + // If the field should be copied with __builtin_memcpy rather than via + // explicit assignments, do so. This optimization only applies for arrays + // of scalars and arrays of class type with trivial move-assignment + // operators. + if (FieldType->isArrayType() && !FieldType.isVolatileQualified() + && BaseType.hasTrivialAssignment(Context, /*Copying=*/false)) { + // Compute the size of the memory buffer to be copied. + QualType SizeType = Context.getSizeType(); + llvm::APInt Size(Context.getTypeSize(SizeType), + Context.getTypeSizeInChars(BaseType).getQuantity()); + for (const ConstantArrayType *Array + = Context.getAsConstantArrayType(FieldType); + Array; + Array = Context.getAsConstantArrayType(Array->getElementType())) { + llvm::APInt ArraySize + = Array->getSize().zextOrTrunc(Size.getBitWidth()); + Size *= ArraySize; + } + + // Take the address of the field references for "from" and "to". We + // directly construct UnaryOperators here because semantic analysis + // does not permit us to take the address of an xvalue. + From = new (Context) UnaryOperator(From.get(), UO_AddrOf, + Context.getPointerType(From.get()->getType()), + VK_RValue, OK_Ordinary, Loc); + To = new (Context) UnaryOperator(To.get(), UO_AddrOf, + Context.getPointerType(To.get()->getType()), + VK_RValue, OK_Ordinary, Loc); + + bool NeedsCollectableMemCpy = + (BaseType->isRecordType() && + BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()); + + if (NeedsCollectableMemCpy) { + if (!CollectableMemCpyRef) { + // Create a reference to the __builtin_objc_memmove_collectable function. + LookupResult R(*this, + &Context.Idents.get("__builtin_objc_memmove_collectable"), + Loc, LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>(); + if (!CollectableMemCpy) { + // Something went horribly wrong earlier, and we will have + // complained about it. + Invalid = true; + continue; + } + + CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, + CollectableMemCpy->getType(), + VK_LValue, Loc, 0).take(); + assert(CollectableMemCpyRef && "Builtin reference cannot fail"); + } + } + // Create a reference to the __builtin_memcpy builtin function. + else if (!BuiltinMemCpyRef) { + LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, + LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>(); + if (!BuiltinMemCpy) { + // Something went horribly wrong earlier, and we will have complained + // about it. + Invalid = true; + continue; + } + + BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, + BuiltinMemCpy->getType(), + VK_LValue, Loc, 0).take(); + assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); + } + + ASTOwningVector<Expr*> CallArgs(*this); + CallArgs.push_back(To.takeAs<Expr>()); + CallArgs.push_back(From.takeAs<Expr>()); + CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); + ExprResult Call = ExprError(); + if (NeedsCollectableMemCpy) + Call = ActOnCallExpr(/*Scope=*/0, + CollectableMemCpyRef, + Loc, move_arg(CallArgs), + Loc); + else + Call = ActOnCallExpr(/*Scope=*/0, + BuiltinMemCpyRef, + Loc, move_arg(CallArgs), + Loc); + + assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); + Statements.push_back(Call.takeAs<Expr>()); + continue; + } + + // Build the move of this field. + StmtResult Move = BuildSingleCopyAssign(*this, Loc, FieldType, + To.get(), From.get(), + /*CopyingBaseSubobject=*/false, + /*Copying=*/false); + if (Move.isInvalid()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + MoveAssignOperator->setInvalidDecl(); + return; + } + + // Success! Record the copy. + Statements.push_back(Move.takeAs<Stmt>()); + } + + if (!Invalid) { + // Add a "return *this;" + ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This); + + StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get()); + if (Return.isInvalid()) + Invalid = true; + else { + Statements.push_back(Return.takeAs<Stmt>()); + + if (Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + } + } + } + + if (Invalid) { + MoveAssignOperator->setInvalidDecl(); + return; + } + + StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + /*isStmtExpr=*/false); + assert(!Body.isInvalid() && "Compound statement creation cannot fail"); + MoveAssignOperator->setBody(Body.takeAs<Stmt>()); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(MoveAssignOperator); + } +} + std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) @@ -7205,7 +8449,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); @@ -7220,7 +8466,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ArgType, /*TInfo=*/0, SC_None, SC_None, 0); - CopyConstructor->setParams(&FromParam, 1); + CopyConstructor->setParams(FromParam); if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); @@ -7232,7 +8478,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // deleted; ... if (ClassDecl->hasUserDeclaredMoveConstructor() || ClassDecl->hasUserDeclaredMoveAssignment() || - ShouldDeleteCopyConstructor(CopyConstructor)) + ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) CopyConstructor->setDeletedAsWritten(); return CopyConstructor; @@ -7262,19 +8508,184 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, MultiStmtArg(*this, 0, 0), /*isStmtExpr=*/false) .takeAs<Stmt>()); + CopyConstructor->setImplicitlyDefined(true); } CopyConstructor->setUsed(); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } } +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { + // C++ [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + ImplicitExceptionSpecification ExceptSpec(Context); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // Direct base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), + BEnd = ClassDecl->bases_end(); + B != BEnd; ++B) { + if (B->isVirtual()) // Handled below. + continue; + + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + // Virtual base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), + BEnd = ClassDecl->vbases_end(); + B != BEnd; ++B) { + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + // Field constructors. + for (RecordDecl::field_iterator F = ClassDecl->field_begin(), + FEnd = ClassDecl->field_end(); + F != FEnd; ++F) { + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + ExceptSpec.SetDelayed(); + } else if (const RecordType *RecordTy + = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + // In particular, the problem is that this function never gets called. It + // might just be ill-formed because this function attempts to refer to + // a deleted function here. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + return ExceptSpec; +} + +CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( + CXXRecordDecl *ClassDecl) { + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(ClassDecl)); + + QualType ClassType = Context.getTypeDeclType(ClassDecl); + QualType ArgType = Context.getRValueReferenceType(ClassType); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + + DeclarationName Name + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType)); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); + + // C++0x [class.copy]p11: + // An implicitly-declared copy/move constructor is an inline public + // member of its class. + CXXConstructorDecl *MoveConstructor + = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(Context.VoidTy, + &ArgType, 1, EPI), + /*TInfo=*/0, + /*isExplicit=*/false, + /*isInline=*/true, + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); + MoveConstructor->setAccess(AS_public); + MoveConstructor->setDefaulted(); + MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); + + // Add the parameter to the constructor. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, + ClassLoc, ClassLoc, + /*IdentifierInfo=*/0, + ArgType, /*TInfo=*/0, + SC_None, + SC_None, 0); + MoveConstructor->setParams(FromParam); + + // C++0x [class.copy]p9: + // If the definition of a class X does not explicitly declare a move + // constructor, one will be implicitly declared as defaulted if and only if: + // [...] + // - the move constructor would not be implicitly defined as deleted. + if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) { + // Cache this result so that we don't try to generate this over and over + // on every lookup, leaking memory and wasting time. + ClassDecl->setFailedImplicitMoveConstructor(); + return 0; + } + + // Note that we have declared this constructor. + ++ASTContext::NumImplicitMoveConstructorsDeclared; + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(MoveConstructor, S, false); + ClassDecl->addDecl(MoveConstructor); + + return MoveConstructor; +} + +void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *MoveConstructor) { + assert((MoveConstructor->isDefaulted() && + MoveConstructor->isMoveConstructor() && + !MoveConstructor->doesThisDeclarationHaveABody()) && + "DefineImplicitMoveConstructor - call it for implicit move ctor"); + + CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); + assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); + + ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor); + DiagnosticErrorTrap Trap(Diags); + + if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); + MoveConstructor->setInvalidDecl(); + } else { + MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(), + MoveConstructor->getLocation(), + MultiStmtArg(*this, 0, 0), + /*isStmtExpr=*/false) + .takeAs<Stmt>()); + MoveConstructor->setImplicitlyDefined(true); + } + + MoveConstructor->setUsed(); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(MoveConstructor); + } +} + ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, + bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { @@ -7297,8 +8708,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, - Elidable, move(ExprArgs), RequiresZeroInit, - ConstructKind, ParenRange); + Elidable, move(ExprArgs), HadMultipleCandidates, + RequiresZeroInit, ConstructKind, ParenRange); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -7307,6 +8718,7 @@ ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, + bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { @@ -7322,20 +8734,21 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, - Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, + Constructor, Elidable, Exprs, NumExprs, + HadMultipleCandidates, RequiresZeroInit, static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), ParenRange)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - MultiExprArg Exprs) { + MultiExprArg Exprs, + bool HadMultipleCandidates) { // FIXME: Provide the correct paren SourceRange when available. ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, - move(Exprs), false, CXXConstructExpr::CK_Complete, - SourceRange()); + move(Exprs), HadMultipleCandidates, false, + CXXConstructExpr::CK_Complete, SourceRange()); if (TempResult.isInvalid()) return true; @@ -7447,6 +8860,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, // class type. if (!VDecl->getType()->isDependentType() && + !VDecl->getType()->isIncompleteArrayType() && RequireCompleteType(VDecl->getLocation(), VDecl->getType(), diag::err_typecheck_decl_incomplete_type)) { VDecl->setInvalidDecl(); @@ -7522,18 +8936,34 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, = InitializationKind::CreateDirect(VDecl->getLocation(), LParenLoc, RParenLoc); + QualType T = VDecl->getType(); InitializationSequence InitSeq(*this, Entity, Kind, Exprs.get(), Exprs.size()); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs), &T); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; + } else if (T != VDecl->getType()) { + VDecl->setType(T); + Result.get()->setType(T); } - CheckImplicitConversions(Result.get(), LParenLoc); - Result = MaybeCreateExprWithCleanups(Result); - VDecl->setInit(Result.takeAs<Expr>()); + Expr *Init = Result.get(); + CheckImplicitConversions(Init, LParenLoc); + + if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() && + !Init->isValueDependent() && + !Init->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) { + // FIXME: Improve this diagnostic to explain why the initializer is not + // a constant expression. + Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init) + << VDecl << Init->getSourceRange(); + } + + Init = MaybeCreateExprWithCleanups(Init); + VDecl->setInit(Init); VDecl->setCXXDirectInitializer(true); CheckCompleteVariableDeclaration(VDecl); @@ -7566,7 +8996,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; - llvm::SmallVector<Expr *, 8> AllArgs; + SmallVector<Expr *, 8> AllArgs; bool Invalid = GatherArgumentsForCall(Loc, Constructor, Proto, 0, Args, NumArgs, AllArgs, CallType); @@ -7928,6 +9358,30 @@ FinishedParams: return true; } + StringRef LiteralName + = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); + if (LiteralName[0] != '_') { + // C++0x [usrlit.suffix]p1: + // Literal suffix identifiers that do not start with an underscore are + // reserved for future standardization. + bool IsHexFloat = true; + if (LiteralName.size() > 1 && + (LiteralName[0] == 'P' || LiteralName[0] == 'p')) { + for (unsigned I = 1, N = LiteralName.size(); I < N; ++I) { + if (!isdigit(LiteralName[I])) { + IsHexFloat = false; + break; + } + } + } + + if (IsHexFloat) + Diag(FnDecl->getLocation(), diag::warn_user_literal_hexfloat) + << LiteralName; + else + Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved); + } + return false; } @@ -7940,7 +9394,7 @@ FinishedParams: /// have any braces. Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - llvm::StringRef Lang, + StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; if (Lang == "\"C\"") @@ -8265,6 +9719,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, + /*ModulePrivateLoc=*/SourceLocation(), TempParamLists.size() - 1, (TemplateParameterList**) TempParamLists.release()).take(); } else { @@ -8427,7 +9882,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, return D; } -Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, +Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams) { const DeclSpec &DS = D.getDeclSpec(); @@ -8436,7 +9891,6 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, SourceLocation Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType T = TInfo->getType(); // C++ [class.friend]p1 // A friend of a class is a function or class.... @@ -8448,7 +9902,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // a declaration that does not use the syntactic form of a // function declarator to have a function type, the program // is ill-formed. - if (!T->isFunctionType()) { + if (!TInfo->getType()->isFunctionType()) { Diag(Loc, diag::err_unexpected_friend); // It might be worthwhile to try to recover by creating an @@ -8551,6 +10005,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, DCScope = getScopeForDeclContext(S, DC); + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + if (isLocal && D.isFunctionDefinition()) { + Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); + } + // - There's a non-dependent scope specifier, in which case we // compute it and do a previous lookup there for a function // or function template. @@ -8576,7 +10038,8 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, if (Previous.empty()) { D.setInvalidType(); - Diag(Loc, diag::err_qualified_friend_not_found) << Name << T; + Diag(Loc, diag::err_qualified_friend_not_found) + << Name << TInfo->getType(); return 0; } @@ -8584,6 +10047,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // class that is not a member of the class . . . if (DC->Equals(CurContext)) Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + + if (D.isFunctionDefinition()) { + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + SemaDiagnosticBuilder DB + = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); + + DB << SS.getScopeRep(); + if (DC->isFileContext()) + DB << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } // - There's a scope specifier that does not match any template // parameter lists, in which case we use some arbitrary context, @@ -8591,10 +10068,19 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // - There's a scope specifier that does match some template // parameter lists, which we don't handle right now. } else { + if (D.isFunctionDefinition()) { + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) + << SS.getScopeRep(); + } + DC = CurContext; assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?"); } - + if (!DC->isRecord()) { // This implies that it has to be an operator or function. if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || @@ -8607,11 +10093,9 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, } } - bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous, - move(TemplateParams), - IsDefinition, - Redeclaration); + bool AddToScope = true; + NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous, + move(TemplateParams), AddToScope); if (!ND) return 0; assert(ND->getDeclContext() == DC); @@ -8732,15 +10216,24 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { break; } - case CXXMoveConstructor: - case CXXMoveAssignment: - Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported); + case CXXMoveConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedMoveConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitMoveConstructor(DefaultLoc, CD); break; + } - default: - // FIXME: Do the rest once we have move functions + case CXXMoveAssignment: { + CheckExplicitlyDefaultedMoveAssignment(MD); + if (!MD->isInvalidDecl()) + DefineImplicitMoveAssignment(DefaultLoc, MD); break; } + + case CXXInvalid: + llvm_unreachable("Invalid special member."); + } } else { Diag(DefaultLoc, diag::err_default_special_members); } @@ -8934,6 +10427,30 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } +void Sema::LoadExternalVTableUses() { + if (!ExternalSource) + return; + + SmallVector<ExternalVTableUse, 4> VTables; + ExternalSource->ReadUsedVTables(VTables); + SmallVector<VTableUse, 4> NewUses; + for (unsigned I = 0, N = VTables.size(); I != N; ++I) { + llvm::DenseMap<CXXRecordDecl *, bool>::iterator Pos + = VTablesUsed.find(VTables[I].Record); + // Even if a definition wasn't required before, it may be required now. + if (Pos != VTablesUsed.end()) { + if (!Pos->second && VTables[I].DefinitionRequired) + Pos->second = true; + continue; + } + + VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired; + NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location)); + } + + VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end()); +} + void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired) { // Ignore any vtable uses in unevaluated operands or for classes that do @@ -8944,6 +10461,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Try to insert this class into the map. + LoadExternalVTableUses(); Class = cast<CXXRecordDecl>(Class->getCanonicalDecl()); std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool> Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); @@ -8969,6 +10487,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, } bool Sema::DefineUsedVTables() { + LoadExternalVTableUses(); if (VTableUses.empty()) return false; @@ -9037,7 +10556,10 @@ bool Sema::DefineUsedVTables() { // Optionally warn if we're emitting a weak vtable. if (Class->getLinkage() == ExternalLinkage && Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { - if (!KeyFunction || (KeyFunction->hasBody() && KeyFunction->isInlined())) + const FunctionDecl *KeyFunctionDef = 0; + if (!KeyFunction || + (KeyFunction->hasBody(KeyFunctionDef) && + KeyFunctionDef->isInlined())) Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; } } @@ -9078,11 +10600,11 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { if (!getLangOptions().CPlusPlus) return; if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { - llvm::SmallVector<ObjCIvarDecl*, 8> ivars; + SmallVector<ObjCIvarDecl*, 8> ivars; CollectIvarsToConstructOrDestruct(OID, ivars); if (ivars.empty()) return; - llvm::SmallVector<CXXCtorInitializer*, 32> AllToInit; + SmallVector<CXXCtorInitializer*, 32> AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; if (Field->isInvalidDecl()) @@ -9199,8 +10721,8 @@ void Sema::CheckDelegatingCtorCycles() { llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), CE = Current.end(); - for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator - I = DelegatingCtorDecls.begin(), + for (DelegatingCtorDeclsType::iterator + I = DelegatingCtorDecls.begin(ExternalSource), E = DelegatingCtorDecls.end(); I != E; ++I) { DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); @@ -9209,3 +10731,44 @@ void Sema::CheckDelegatingCtorCycles() { for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) (*CI)->setInvalidDecl(); } + +/// IdentifyCUDATarget - Determine the CUDA compilation target for this function +Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { + // Implicitly declared functions (e.g. copy constructors) are + // __host__ __device__ + if (D->isImplicit()) + return CFT_HostDevice; + + if (D->hasAttr<CUDAGlobalAttr>()) + return CFT_Global; + + if (D->hasAttr<CUDADeviceAttr>()) { + if (D->hasAttr<CUDAHostAttr>()) + return CFT_HostDevice; + else + return CFT_Device; + } + + return CFT_Host; +} + +bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, + CUDAFunctionTarget CalleeTarget) { + // CUDA B.1.1 "The __device__ qualifier declares a function that is... + // Callable from the device only." + if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) + return true; + + // CUDA B.1.2 "The __global__ qualifier declares a function that is... + // Callable from the host only." + // CUDA B.1.3 "The __host__ qualifier declares a function that is... + // Callable from the host only." + if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && + (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) + return true; + + if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) + return true; + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index aa8152b..62b4a7c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -106,7 +106,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method, return true; } -bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, +void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden, bool IsImplementation) { if (Overridden->hasRelatedResultType() && @@ -148,105 +148,44 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, << ResultTypeRange; } - Diag(Overridden->getLocation(), diag::note_related_result_type_overridden) - << Overridden->getMethodFamily(); + if (ObjCMethodFamily Family = Overridden->getMethodFamily()) + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden_family) + << Family; + else + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden); } - - return false; -} - -/// \brief Check for consistency between a given method declaration and the -/// methods it overrides within the class hierarchy. -/// -/// This method walks the inheritance hierarchy starting at the given -/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with -/// the given new method (\p NewMethod) and any method it directly overrides -/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for -/// checking consistency, e.g., among return types for methods that return a -/// related result type. -static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, - DeclContext *DC, - bool SkipCurrent = true) { - if (!DC) - return false; - - if (!SkipCurrent) { - // Look for this method. If we find it, we're done. - Selector Sel = NewMethod->getSelector(); - bool IsInstance = NewMethod->isInstanceMethod(); - DeclContext::lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isInstanceMethod() == IsInstance) - return S.CheckObjCMethodOverride(NewMethod, MD, false); + if (getLangOptions().ObjCAutoRefCount) { + if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() != + Overridden->hasAttr<NSReturnsRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::err_nsreturns_retained_attribute_mismatch) << 1; + Diag(Overridden->getLocation(), diag::note_previous_decl) + << "method"; } - } - - if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) { - // Look through categories. - for (ObjCCategoryDecl *Category = Class->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - if (CheckObjCMethodOverrides(S, NewMethod, Category, false)) - return true; + if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() != + Overridden->hasAttr<NSReturnsNotRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::err_nsreturns_retained_attribute_mismatch) << 0; + Diag(Overridden->getLocation(), diag::note_previous_decl) + << "method"; + } + ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(); + for (ObjCMethodDecl::param_iterator + ni = NewMethod->param_begin(), ne = NewMethod->param_end(); + ni != ne; ++ni, ++oi) { + const ParmVarDecl *oldDecl = (*oi); + ParmVarDecl *newDecl = (*ni); + if (newDecl->hasAttr<NSConsumedAttr>() != + oldDecl->hasAttr<NSConsumedAttr>()) { + Diag(newDecl->getLocation(), + diag::err_nsconsumed_attribute_mismatch); + Diag(oldDecl->getLocation(), diag::note_previous_decl) + << "parameter"; + } } - - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(), - IEnd = Class->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - // Look in our superclass. - return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(), - false); - } - - if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) { - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(), - IEnd = Category->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - return false; - } - - if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) { - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(), - IEnd = Protocol->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - return false; } - - return false; -} - -bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, - DeclContext *DC) { - if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Class); - - if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Category); - - if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol); - - if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, - Impl->getClassInterface()); - - if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, - CatImpl->getClassInterface()); - - return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext); } /// \brief Check a method declaration for compatibility with the Objective-C @@ -256,11 +195,13 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { switch (family) { case OMF_None: case OMF_dealloc: + case OMF_finalize: case OMF_retain: case OMF_release: case OMF_autorelease: case OMF_retainCount: case OMF_self: + case OMF_performSelector: return false; case OMF_init: @@ -286,11 +227,6 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { method->hasAttr<NSReturnsAutoreleasedAttr>()) return false; break; - - case OMF_performSelector: - // we don't annotate performSelector's - return true; - } method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), @@ -311,6 +247,20 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, } } +/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global +/// pool. +void Sema::AddAnyMethodToGlobalPool(Decl *D) { + ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D); + + // If we don't have a valid method decl, simply return. + if (!MDecl) + return; + if (MDecl->isInstanceMethod()) + AddInstanceMethodToGlobalPool(MDecl, true); + else + AddFactoryMethodToGlobalPool(MDecl, true); +} + /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { @@ -321,12 +271,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { if (!MDecl) return; - // Allow the rest of sema to find private method decl implementations. - if (MDecl->isInstanceMethod()) - AddInstanceMethodToGlobalPool(MDecl, true); - else - AddFactoryMethodToGlobalPool(MDecl, true); - // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); PushFunctionScope(); @@ -365,6 +309,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { case OMF_None: case OMF_dealloc: + case OMF_finalize: case OMF_alloc: case OMF_init: case OMF_mutableCopy: @@ -376,14 +321,29 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { } } - // Warn on implementating deprecated methods under - // -Wdeprecated-implementations flag. - if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) + // Warn on deprecated methods under -Wdeprecated-implementations, + // and prepare for warning on missing super calls. + if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) { if (ObjCMethodDecl *IMD = IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod())) DiagnoseObjCImplementedDeprecations(*this, dyn_cast<NamedDecl>(IMD), MDecl->getLocation(), 0); + + // If this is "dealloc" or "finalize", set some bit here. + // Then in ActOnSuperMessage() (SemaExprObjC), set it back to false. + // Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set. + // Only do this if the current class actually has a superclass. + if (IC->getSuperClass()) { + ObjCShouldCallSuperDealloc = + !(Context.getLangOptions().ObjCAutoRefCount || + Context.getLangOptions().getGC() == LangOptions::GCOnly) && + MDecl->getMethodFamily() == OMF_dealloc; + ObjCShouldCallSuperFinalize = + Context.getLangOptions().getGC() != LangOptions::NonGC && + MDecl->getMethodFamily() == OMF_finalize; + } + } } Decl *Sema:: @@ -414,11 +374,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Return the previous class interface. // FIXME: don't leak the objects passed in! - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } else { - IDecl->setLocation(AtInterfaceLoc); + IDecl->setLocation(ClassLoc); IDecl->setForwardDecl(false); - IDecl->setClassLoc(ClassLoc); + IDecl->setAtStartLoc(AtInterfaceLoc); // If the forward decl was in a PCH, we need to write it again in a // dependent AST file. IDecl->setChangedSinceDeserialization(true); @@ -522,7 +482,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(IDecl); - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } /// ActOnCompatiblityAlias - this action is called after complete parsing of @@ -618,7 +578,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, Diag(PDecl->getLocation(), diag::note_previous_definition); // Just return the protocol we already had. // FIXME: don't leak the objects passed in! - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } ObjCList<ObjCProtocolDecl> PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); @@ -626,14 +586,18 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); // Make sure the cached decl gets a valid start location. - PDecl->setLocation(AtProtoInterfaceLoc); + PDecl->setAtStartLoc(AtProtoInterfaceLoc); + PDecl->setLocation(ProtocolLoc); PDecl->setForwardDecl(false); + // Since this ObjCProtocolDecl was created by a forward declaration, + // we now add it to the DeclContext since it wasn't added before + PDecl->setLexicalDeclContext(CurContext); CurContext->addDecl(PDecl); // Repeat in dependent AST files. PDecl->setChangedSinceDeserialization(true); } else { - PDecl = ObjCProtocolDecl::Create(Context, CurContext, - AtProtoInterfaceLoc,ProtocolName); + PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, + ProtocolLoc, AtProtoInterfaceLoc); PushOnScopeChains(PDecl, TUScope); PDecl->setForwardDecl(false); } @@ -647,7 +611,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } CheckObjCDeclScope(PDecl); - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } /// FindProtocolDeclaration - This routine looks up protocols and @@ -657,7 +621,7 @@ void Sema::FindProtocolDeclaration(bool WarnOnDeclarations, const IdentifierLocPair *ProtocolId, unsigned NumProtocols, - llvm::SmallVectorImpl<Decl *> &Protocols) { + SmallVectorImpl<Decl *> &Protocols) { for (unsigned i = 0; i != NumProtocols; ++i) { ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); @@ -725,16 +689,16 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, const IdentifierLocPair *IdentList, unsigned NumElts, AttributeList *attrList) { - llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; - llvm::SmallVector<SourceLocation, 8> ProtoLocs; + SmallVector<ObjCProtocolDecl*, 32> Protocols; + SmallVector<SourceLocation, 8> ProtoLocs; for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); bool isNew = false; if (PDecl == 0) { // Not already seen? - PDecl = ObjCProtocolDecl::Create(Context, CurContext, - IdentList[i].second, Ident); + PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident, + IdentList[i].second, AtProtocolLoc); PushOnScopeChains(PDecl, TUScope, false); isNew = true; } @@ -774,10 +738,10 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // the enclosing method declarations. We mark the decl invalid // to make it clear that this isn't a valid AST. CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName); + ClassLoc, CategoryLoc, CategoryName,IDecl); CDecl->setInvalidDecl(); Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } if (!CategoryName && IDecl->getImplementation()) { @@ -786,19 +750,6 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, diag::note_implementation_declared); } - CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName); - // FIXME: PushOnScopeChains? - CurContext->addDecl(CDecl); - - CDecl->setClassInterface(IDecl); - // Insert class extension to the list of class's categories. - if (!CategoryName) - CDecl->insertNextClassCategory(); - - // If the interface is deprecated, warn about it. - (void)DiagnoseUseOfDecl(IDecl, ClassLoc); - if (CategoryName) { /// Check for duplicate interface declaration for this category ObjCCategoryDecl *CDeclChain; @@ -812,10 +763,13 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, break; } } - if (!CDeclChain) - CDecl->insertNextClassCategory(); } + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName, IDecl); + // FIXME: PushOnScopeChains? + CurContext->addDecl(CDecl); + if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -826,7 +780,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } /// ActOnStartCategoryImplementation - Perform semantic checks on the @@ -845,22 +799,26 @@ Decl *Sema::ActOnStartCategoryImplementation( // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), SourceLocation(), SourceLocation(), - CatName); - CatIDecl->setClassInterface(IDecl); - CatIDecl->insertNextClassCategory(); + CatName, IDecl); } } ObjCCategoryImplDecl *CDecl = - ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName, - IDecl); + ObjCCategoryImplDecl::Create(Context, CurContext, CatName, IDecl, + ClassLoc, AtCatImplLoc); /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) + if (!IDecl || IDecl->isForwardDecl()) { Diag(ClassLoc, diag::err_undef_interface) << ClassName; + CDecl->setInvalidDecl(); + } // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); + // If the interface is deprecated/unavailable, warn/error about it. + if (IDecl) + DiagnoseUseOfDecl(IDecl, ClassLoc); + /// Check that CatName, category name, is not used in another implementation. if (CatIDecl) { if (CatIDecl->getImplementation()) { @@ -879,7 +837,7 @@ Decl *Sema::ActOnStartCategoryImplementation( } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } Decl *Sema::ActOnStartClassImplementation( @@ -969,11 +927,11 @@ Decl *Sema::ActOnStartClassImplementation( } ObjCImplementationDecl* IMPDecl = - ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc, - IDecl, SDecl); + ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, + ClassLoc, AtClassImplLoc); if (CheckObjCDeclScope(IMPDecl)) - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); // Check that there is no duplicate implementation of this class. if (IDecl->getImplementation()) { @@ -990,7 +948,7 @@ Decl *Sema::ActOnStartClassImplementation( dyn_cast<NamedDecl>(IDecl), IMPDecl->getLocation(), 1); } - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); } void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, @@ -1050,21 +1008,18 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, assert (ClsIvar && "missing class ivar"); // First, make sure the types match. - if (Context.getCanonicalType(ImplIvar->getType()) != - Context.getCanonicalType(ClsIvar->getType())) { + if (!Context.hasSameType(ImplIvar->getType(), ClsIvar->getType())) { Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type) << ImplIvar->getIdentifier() << ImplIvar->getType() << ClsIvar->getType(); Diag(ClsIvar->getLocation(), diag::note_previous_definition); - } else if (ImplIvar->isBitField() && ClsIvar->isBitField()) { - Expr *ImplBitWidth = ImplIvar->getBitWidth(); - Expr *ClsBitWidth = ClsIvar->getBitWidth(); - if (ImplBitWidth->EvaluateAsInt(Context).getZExtValue() != - ClsBitWidth->EvaluateAsInt(Context).getZExtValue()) { - Diag(ImplBitWidth->getLocStart(), diag::err_conflicting_ivar_bitwidth) - << ImplIvar->getIdentifier(); - Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition); - } + } else if (ImplIvar->isBitField() && ClsIvar->isBitField() && + ImplIvar->getBitWidthValue(Context) != + ClsIvar->getBitWidthValue(Context)) { + Diag(ImplIvar->getBitWidth()->getLocStart(), + diag::err_conflicting_ivar_bitwidth) << ImplIvar->getIdentifier(); + Diag(ClsIvar->getBitWidth()->getLocStart(), + diag::note_previous_definition); } // Make sure the names are identical. if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { @@ -1167,26 +1122,38 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) { return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange()); } -static void CheckMethodOverrideReturn(Sema &S, +static bool CheckMethodOverrideReturn(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsOverridingMode, + bool Warn) { if (IsProtocolMethodDecl && (MethodDecl->getObjCDeclQualifier() != MethodImpl->getObjCDeclQualifier())) { - S.Diag(MethodImpl->getLocation(), - diag::warn_conflicting_ret_type_modifiers) - << MethodImpl->getDeclName() - << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) - << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + if (Warn) { + S.Diag(MethodImpl->getLocation(), + (IsOverridingMode ? + diag::warn_conflicting_overriding_ret_type_modifiers + : diag::warn_conflicting_ret_type_modifiers)) + << MethodImpl->getDeclName() + << getTypeRange(MethodImpl->getResultTypeSourceInfo()); + S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) + << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + } + else + return false; } if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(), MethodDecl->getResultType())) - return; + return true; + if (!Warn) + return false; - unsigned DiagID = diag::warn_conflicting_ret_types; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_ret_types + : diag::warn_conflicting_ret_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1199,9 +1166,11 @@ static void CheckMethodOverrideReturn(Sema &S, // return types that are subclasses of the declared return type, // or that are more-qualified versions of the declared type. if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false)) - return; + return false; - DiagID = diag::warn_non_covariant_ret_types; + DiagID = + IsOverridingMode ? diag::warn_non_covariant_overriding_ret_types + : diag::warn_non_covariant_ret_types; } } @@ -1210,34 +1179,52 @@ static void CheckMethodOverrideReturn(Sema &S, << MethodDecl->getResultType() << MethodImpl->getResultType() << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_definition) + S.Diag(MethodDecl->getLocation(), + IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + return false; } -static void CheckMethodOverrideParam(Sema &S, +static bool CheckMethodOverrideParam(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, ParmVarDecl *ImplVar, ParmVarDecl *IfaceVar, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsOverridingMode, + bool Warn) { if (IsProtocolMethodDecl && (ImplVar->getObjCDeclQualifier() != IfaceVar->getObjCDeclQualifier())) { - S.Diag(ImplVar->getLocation(), - diag::warn_conflicting_param_modifiers) - << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName(); - S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) - << getTypeRange(IfaceVar->getTypeSourceInfo()); + if (Warn) { + if (IsOverridingMode) + S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_overriding_param_modifiers) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName(); + else S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_param_modifiers) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName(); + S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) + << getTypeRange(IfaceVar->getTypeSourceInfo()); + } + else + return false; } QualType ImplTy = ImplVar->getType(); QualType IfaceTy = IfaceVar->getType(); if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) - return; - - unsigned DiagID = diag::warn_conflicting_param_types; + return true; + + if (!Warn) + return false; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_param_types + : diag::warn_conflicting_param_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1250,17 +1237,22 @@ static void CheckMethodOverrideParam(Sema &S, // implementation must accept any objects that the superclass // accepts, however it may also accept others. if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true)) - return; + return false; - DiagID = diag::warn_non_contravariant_param_types; + DiagID = + IsOverridingMode ? diag::warn_non_contravariant_overriding_param_types + : diag::warn_non_contravariant_param_types; } } S.Diag(ImplVar->getLocation(), DiagID) << getTypeRange(ImplVar->getTypeSourceInfo()) << MethodImpl->getDeclName() << IfaceTy << ImplTy; - S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) + S.Diag(IfaceVar->getLocation(), + (IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition)) << getTypeRange(IfaceVar->getTypeSourceInfo()); + return false; } /// In ARC, check whether the conventional meanings of the two methods @@ -1302,6 +1294,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, case OMF_release: case OMF_autorelease: case OMF_dealloc: + case OMF_finalize: case OMF_retainCount: case OMF_self: case OMF_performSelector: @@ -1341,20 +1334,86 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, return; CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, - IsProtocolMethodDecl); + IsProtocolMethodDecl, false, + true); for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); - IM != EM; ++IM, ++IF) + IM != EM; ++IM, ++IF) { CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF, - IsProtocolMethodDecl); + IsProtocolMethodDecl, false, true); + } if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); + Diag(ImpMethodDecl->getLocation(), + diag::warn_conflicting_variadic); Diag(MethodDecl->getLocation(), diag::note_previous_declaration); } } +void Sema::CheckConflictingOverridingMethod(ObjCMethodDecl *Method, + ObjCMethodDecl *Overridden, + bool IsProtocolMethodDecl) { + + CheckMethodOverrideReturn(*this, Method, Overridden, + IsProtocolMethodDecl, true, + true); + + for (ObjCMethodDecl::param_iterator IM = Method->param_begin(), + IF = Overridden->param_begin(), EM = Method->param_end(); + IM != EM; ++IM, ++IF) { + CheckMethodOverrideParam(*this, Method, Overridden, *IM, *IF, + IsProtocolMethodDecl, true, true); + } + + if (Method->isVariadic() != Overridden->isVariadic()) { + Diag(Method->getLocation(), + diag::warn_conflicting_overriding_variadic); + Diag(Overridden->getLocation(), diag::note_previous_declaration); + } +} + +/// WarnExactTypedMethods - This routine issues a warning if method +/// implementation declaration matches exactly that of its declaration. +void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl) { + // don't issue warning when protocol method is optional because primary + // class is not required to implement it and it is safe for protocol + // to implement it. + if (MethodDecl->getImplementationControl() == ObjCMethodDecl::Optional) + return; + // don't issue warning when primary class's method is + // depecated/unavailable. + if (MethodDecl->hasAttr<UnavailableAttr>() || + MethodDecl->hasAttr<DeprecatedAttr>()) + return; + + bool match = CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, + IsProtocolMethodDecl, false, false); + if (match) + for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), + IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); + IM != EM; ++IM, ++IF) { + match = CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, + *IM, *IF, + IsProtocolMethodDecl, false, false); + if (!match) + break; + } + if (match) + match = (ImpMethodDecl->isVariadic() == MethodDecl->isVariadic()); + if (match) + match = !(MethodDecl->isClassMethod() && + MethodDecl->getSelector() == GetNullarySelector("load", Context)); + + if (match) { + Diag(ImpMethodDecl->getLocation(), + diag::warn_category_method_impl_match); + Diag(MethodDecl->getLocation(), diag::note_method_declared_at); + } +} + /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely /// improve the efficiency of selector lookups and type checking by associating /// with each protocol / interface / category the flattened instance tables. If @@ -1416,7 +1475,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, if (!MethodInClass || !MethodInClass->isSynthesized()) { unsigned DIAG = diag::warn_unimplemented_protocol_method; if (Diags.getDiagnosticLevel(DIAG, ImpLoc) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); Diag(method->getLocation(), diag::note_method_declared_at); Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) @@ -1434,7 +1493,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, !ClsMap.count(method->getSelector()) && (!Super || !Super->lookupClassMethod(method->getSelector()))) { unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != Diagnostic::Ignored) { + if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != + DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); Diag(method->getLocation(), diag::note_method_declared_at); Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << @@ -1458,7 +1518,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool &IncompleteImpl, - bool ImmediateClass) { + bool ImmediateClass, + bool WarnExactMatch) { // Check and see if instance methods in class interface have been // implemented in the implementation class. If so, their types match. for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(), @@ -1474,15 +1535,19 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, continue; } else { ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getInstanceMethod((*I)->getSelector()); - ObjCMethodDecl *MethodDecl = - CDecl->getInstanceMethod((*I)->getSelector()); - assert(MethodDecl && - "MethodDecl is null in ImplMethodsVsClassMethods"); + IMPDecl->getInstanceMethod((*I)->getSelector()); + assert(CDecl->getInstanceMethod((*I)->getSelector()) && + "Expected to find the method through lookup as well"); + ObjCMethodDecl *MethodDecl = *I; // ImpMethodDecl may be null as in a @dynamic property. - if (ImpMethodDecl) - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, - isa<ObjCProtocolDecl>(CDecl)); + if (ImpMethodDecl) { + if (!WarnExactMatch) + WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + else if (!MethodDecl->isSynthesized()) + WarnExactTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + } } } @@ -1500,10 +1565,15 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); - ObjCMethodDecl *MethodDecl = - CDecl->getClassMethod((*I)->getSelector()); - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, - isa<ObjCProtocolDecl>(CDecl)); + assert(CDecl->getClassMethod((*I)->getSelector()) && + "Expected to find the method through lookup as well"); + ObjCMethodDecl *MethodDecl = *I; + if (!WarnExactMatch) + WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + else + WarnExactTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); } } @@ -1514,7 +1584,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, const_cast<ObjCCategoryDecl *>(ClsExtDecl), - IncompleteImpl, false); + IncompleteImpl, false, WarnExactMatch); // Check for any implementation of a methods declared in protocol. for (ObjCInterfaceDecl::all_protocol_iterator @@ -1522,14 +1592,50 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, E = I->all_referenced_protocol_end(); PI != E; ++PI) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, - (*PI), IncompleteImpl, false); - if (I->getSuperClass()) + (*PI), IncompleteImpl, false, WarnExactMatch); + + // FIXME. For now, we are not checking for extact match of methods + // in category implementation and its primary class's super class. + if (!WarnExactMatch && I->getSuperClass()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, I->getSuperClass(), IncompleteImpl, false); } } +/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in +/// category matches with those implemented in its primary class and +/// warns each time an exact match is found. +void Sema::CheckCategoryVsClassMethodMatches( + ObjCCategoryImplDecl *CatIMPDecl) { + llvm::DenseSet<Selector> InsMap, ClsMap; + + for (ObjCImplementationDecl::instmeth_iterator + I = CatIMPDecl->instmeth_begin(), + E = CatIMPDecl->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + + for (ObjCImplementationDecl::classmeth_iterator + I = CatIMPDecl->classmeth_begin(), + E = CatIMPDecl->classmeth_end(); I != E; ++I) + ClsMap.insert((*I)->getSelector()); + if (InsMap.empty() && ClsMap.empty()) + return; + + // Get category's primary class. + ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl(); + if (!CatDecl) + return; + ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface(); + if (!IDecl) + return; + llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen; + bool IncompleteImpl = false; + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + CatIMPDecl, IDecl, + IncompleteImpl, false, true /*WarnExactMatch*/); +} + void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1559,6 +1665,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, CDecl, IncompleteImpl, true); + + // check all methods implemented in category against those declared + // in its primary class. + if (ObjCCategoryImplDecl *CatDecl = + dyn_cast<ObjCCategoryImplDecl>(IMPDecl)) + CheckCategoryVsClassMethodMatches(CatDecl); // Check the protocol list for unimplemented methods in the @implementation // class. @@ -1598,17 +1710,16 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); } } else - assert(false && "invalid ObjCContainerDecl type."); + llvm_unreachable("invalid ObjCContainerDecl type."); } /// ActOnForwardClassDeclaration - -Decl * +Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, unsigned NumElts) { - llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces; - + SmallVector<Decl *, 8> DeclsInGroup; for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. NamedDecl *PrevDecl @@ -1653,17 +1764,14 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, PushOnScopeChains(IDecl, TUScope, false); CurContext->makeDeclVisibleInContext(IDecl, true); } - - Interfaces.push_back(IDecl); + ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, + IDecl, IdentLocs[i]); + CurContext->addDecl(CDecl); + CheckObjCDeclScope(CDecl); + DeclsInGroup.push_back(CDecl); } - - assert(Interfaces.size() == NumElts); - ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, - Interfaces.data(), IdentLocs, - Interfaces.size()); - CurContext->addDecl(CDecl); - CheckObjCDeclScope(CDecl); - return CDecl; + + return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false); } static bool tryMatchRecordTypes(ASTContext &Context, @@ -1705,11 +1813,16 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy, if (!left->isScalarType() || !right->isScalarType()) return tryMatchRecordTypes(Context, strategy, left, right); - // Make scalars agree in kind, except count bools as chars. + // Make scalars agree in kind, except count bools as chars, and group + // all non-member pointers together. Type::ScalarTypeKind leftSK = left->getScalarTypeKind(); Type::ScalarTypeKind rightSK = right->getScalarTypeKind(); if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral; if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral; + if (leftSK == Type::STK_CPointer || leftSK == Type::STK_BlockPointer) + leftSK = Type::STK_ObjCObjectPointer; + if (rightSK == Type::STK_CPointer || rightSK == Type::STK_BlockPointer) + rightSK = Type::STK_ObjCObjectPointer; // Note that data member pointers and function member pointers don't // intermix because of the size differences. @@ -1764,12 +1877,12 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, != right->hasAttr<NSConsumesSelfAttr>())) return false; - ObjCMethodDecl::param_iterator + ObjCMethodDecl::param_const_iterator li = left->param_begin(), le = left->param_end(), ri = right->param_begin(); for (; li != le; ++li, ++ri) { assert(ri != right->param_end() && "Param mismatch"); - ParmVarDecl *lparm = *li, *rparm = *ri; + const ParmVarDecl *lparm = *li, *rparm = *ri; if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType())) return false; @@ -1887,7 +2000,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, (receiverIdOrClass && warn && (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, R.getBegin()) != - Diagnostic::Ignored)); + DiagnosticsEngine::Ignored)); if (strictSelectorMatch) for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, @@ -2010,15 +2123,14 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, - Decl *ClassDecl, Decl **allMethods, unsigned allNum, Decl **allProperties, unsigned pNum, DeclGroupPtrTy *allTUVars, unsigned tuvNum) { - // FIXME: If we don't have a ClassDecl, we have an error. We should consider - // always passing in a decl. If the decl has an error, isInvalidDecl() - // should be true. - if (!ClassDecl) + + if (!CurContext->isObjCContainer()) return; + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + Decl *ClassDecl = cast<Decl>(OCD); bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) @@ -2055,6 +2167,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(PrevMethod->getLocation(), diag::note_previous_declaration); Method->setInvalidDecl(); } else { + if (PrevMethod) + Method->setAsRedeclaration(PrevMethod); InsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "id". AddInstanceMethodToGlobalPool(Method); @@ -2074,6 +2188,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(PrevMethod->getLocation(), diag::note_previous_declaration); Method->setInvalidDecl(); } else { + if (PrevMethod) + Method->setAsRedeclaration(PrevMethod); ClsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "Class". AddFactoryMethodToGlobalPool(Method); @@ -2145,10 +2261,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } } } - - if (LangOpts.ObjCDefaultSynthProperties && - LangOpts.ObjCNonFragileABI2) - DefaultSynthesizeProperties(S, IC, IDecl); ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); DiagnoseOwningPropertyGetterSynthesis(IC); @@ -2187,6 +2299,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } } } + ActOnObjCContainerFinishDefinition(); } @@ -2208,16 +2321,22 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { return false; } +namespace { + /// \brief Describes the compatibility of a result type with its method. + enum ResultTypeCompatibilityKind { + RTC_Compatible, + RTC_Incompatible, + RTC_Unknown + }; +} + /// \brief Check whether the declared result type of the given Objective-C /// method declaration is compatible with the method's class. /// -static bool +static ResultTypeCompatibilityKind CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, ObjCInterfaceDecl *CurrentClass) { QualType ResultType = Method->getResultType(); - SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo()) - ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); // If an Objective-C method inherits its related result type, then its // declared result type must be compatible with its own class type. The @@ -2227,52 +2346,171 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, // - it is id or qualified id, or if (ResultObjectType->isObjCIdType() || ResultObjectType->isObjCQualifiedIdType()) - return false; + return RTC_Compatible; if (CurrentClass) { if (ObjCInterfaceDecl *ResultClass = ResultObjectType->getInterfaceDecl()) { // - it is the same as the method's class type, or if (CurrentClass == ResultClass) - return false; + return RTC_Compatible; // - it is a superclass of the method's class type if (ResultClass->isSuperClassOf(CurrentClass)) - return false; + return RTC_Compatible; } + } else { + // Any Objective-C pointer type might be acceptable for a protocol + // method; we just don't know. + return RTC_Unknown; } } - return true; + return RTC_Incompatible; } -/// \brief Determine if any method in the global method pool has an inferred -/// result type. -static bool -anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) { - Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel); - if (Pos == S.MethodPool.end()) { - if (S.ExternalSource) - Pos = S.ReadMethodPool(Sel); - else - return 0; +namespace { +/// A helper class for searching for methods which a particular method +/// overrides. +class OverrideSearch { + Sema &S; + ObjCMethodDecl *Method; + llvm::SmallPtrSet<ObjCContainerDecl*, 8> Searched; + llvm::SmallPtrSet<ObjCMethodDecl*, 8> Overridden; + bool Recursive; + +public: + OverrideSearch(Sema &S, ObjCMethodDecl *method) : S(S), Method(method) { + Selector selector = method->getSelector(); + + // Bypass this search if we've never seen an instance/class method + // with this selector before. + Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector); + if (it == S.MethodPool.end()) { + if (!S.ExternalSource) return; + it = S.ReadMethodPool(selector); + } + ObjCMethodList &list = + method->isInstanceMethod() ? it->second.first : it->second.second; + if (!list.Method) return; + + ObjCContainerDecl *container + = cast<ObjCContainerDecl>(method->getDeclContext()); + + // Prevent the search from reaching this container again. This is + // important with categories, which override methods from the + // interface and each other. + Searched.insert(container); + searchFromContainer(container); } - - ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second; - for (ObjCMethodList *M = &List; M; M = M->Next) { - if (M->Method && M->Method->hasRelatedResultType()) - return true; - } - - return false; + + typedef llvm::SmallPtrSet<ObjCMethodDecl*,8>::iterator iterator; + iterator begin() const { return Overridden.begin(); } + iterator end() const { return Overridden.end(); } + +private: + void searchFromContainer(ObjCContainerDecl *container) { + if (container->isInvalidDecl()) return; + + switch (container->getDeclKind()) { +#define OBJCCONTAINER(type, base) \ + case Decl::type: \ + searchFrom(cast<type##Decl>(container)); \ + break; +#define ABSTRACT_DECL(expansion) +#define DECL(type, base) \ + case Decl::type: +#include "clang/AST/DeclNodes.inc" + llvm_unreachable("not an ObjC container!"); + } + } + + void searchFrom(ObjCProtocolDecl *protocol) { + // A method in a protocol declaration overrides declarations from + // referenced ("parent") protocols. + search(protocol->getReferencedProtocols()); + } + + void searchFrom(ObjCCategoryDecl *category) { + // A method in a category declaration overrides declarations from + // the main class and from protocols the category references. + search(category->getClassInterface()); + search(category->getReferencedProtocols()); + } + + void searchFrom(ObjCCategoryImplDecl *impl) { + // A method in a category definition that has a category + // declaration overrides declarations from the category + // declaration. + if (ObjCCategoryDecl *category = impl->getCategoryDecl()) { + search(category); + + // Otherwise it overrides declarations from the class. + } else { + search(impl->getClassInterface()); + } + } + + void searchFrom(ObjCInterfaceDecl *iface) { + // A method in a class declaration overrides declarations from + + // - categories, + for (ObjCCategoryDecl *category = iface->getCategoryList(); + category; category = category->getNextClassCategory()) + search(category); + + // - the super class, and + if (ObjCInterfaceDecl *super = iface->getSuperClass()) + search(super); + + // - any referenced protocols. + search(iface->getReferencedProtocols()); + } + + void searchFrom(ObjCImplementationDecl *impl) { + // A method in a class implementation overrides declarations from + // the class interface. + search(impl->getClassInterface()); + } + + + void search(const ObjCProtocolList &protocols) { + for (ObjCProtocolList::iterator i = protocols.begin(), e = protocols.end(); + i != e; ++i) + search(*i); + } + + void search(ObjCContainerDecl *container) { + // Abort if we've already searched this container. + if (!Searched.insert(container)) return; + + // Check for a method in this container which matches this selector. + ObjCMethodDecl *meth = container->getMethod(Method->getSelector(), + Method->isInstanceMethod()); + + // If we find one, record it and bail out. + if (meth) { + Overridden.insert(meth); + return; + } + + // Otherwise, search for methods that a hypothetical method here + // would have overridden. + + // Note that we're now in a recursive case. + Recursive = true; + + searchFromContainer(container); + } +}; } Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, Decl *ClassDecl, + tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, - SourceLocation SelectorStartLoc, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -2281,12 +2519,15 @@ Decl *Sema::ActOnMethodDeclaration( AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic, bool MethodDefinition) { // Make sure we can establish a context for the method. - if (!ClassDecl) { + if (!CurContext->isObjCContainer()) { Diag(MethodLoc, diag::error_missing_method_context); return 0; } + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + Decl *ClassDecl = cast<Decl>(OCD); QualType resultDeclType; + bool HasRelatedResultType = false; TypeSourceInfo *ResultTInfo = 0; if (ReturnType) { resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo); @@ -2298,21 +2539,28 @@ Decl *Sema::ActOnMethodDeclaration( << 0 << resultDeclType; return 0; } - } else // get the type for "id". + + HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); + } else { // get the type for "id". resultDeclType = Context.getObjCIdType(); + Diag(MethodLoc, diag::warn_missing_method_return_type) + << FixItHint::CreateInsertion(SelectorLocs.front(), "(id)"); + } ObjCMethodDecl* ObjCMethod = - ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType, + ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, + resultDeclType, ResultTInfo, - cast<DeclContext>(ClassDecl), + CurContext, MethodType == tok::minus, isVariadic, - false, false, + /*isSynthesized=*/false, + /*isImplicitlyDeclared=*/false, /*isDefined=*/false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required, - false); + HasRelatedResultType); - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { QualType ArgType; @@ -2383,20 +2631,16 @@ Decl *Sema::ActOnMethodDeclaration( Params.push_back(Param); } - ObjCMethod->setMethodParams(Context, Params.data(), Params.size(), - Sel.getNumArgs()); + ObjCMethod->setMethodParams(Context, Params, SelectorLocs); ObjCMethod->setObjCDeclQualifier( CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); - const ObjCMethodDecl *PrevMethod = 0; if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); - const ObjCMethodDecl *InterfaceMD = 0; - // Add the method now. - if (ObjCImplementationDecl *ImpDecl = - dyn_cast<ObjCImplementationDecl>(ClassDecl)) { + const ObjCMethodDecl *PrevMethod = 0; + if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(ClassDecl)) { if (MethodType == tok::minus) { PrevMethod = ImpDecl->getInstanceMethod(Sel); ImpDecl->addInstanceMethod(ObjCMethod); @@ -2404,24 +2648,6 @@ Decl *Sema::ActOnMethodDeclaration( PrevMethod = ImpDecl->getClassMethod(Sel); ImpDecl->addClassMethod(ObjCMethod); } - InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, - MethodType == tok::minus); - - if (ObjCMethod->hasAttrs() && - containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) - Diag(EndLoc, diag::warn_attribute_method_def); - } else if (ObjCCategoryImplDecl *CatImpDecl = - dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { - if (MethodType == tok::minus) { - PrevMethod = CatImpDecl->getInstanceMethod(Sel); - CatImpDecl->addInstanceMethod(ObjCMethod); - } else { - PrevMethod = CatImpDecl->getClassMethod(Sel); - CatImpDecl->addClassMethod(ObjCMethod); - } - - if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl()) - InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus); if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) @@ -2429,6 +2655,7 @@ Decl *Sema::ActOnMethodDeclaration( } else { cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); } + if (PrevMethod) { // You can never have two method definitions with the same name. Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) @@ -2449,28 +2676,44 @@ Decl *Sema::ActOnMethodDeclaration( = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) CurrentClass = CatImpl->getClassInterface(); } - - // Merge information down from the interface declaration if we have one. - if (InterfaceMD) { - // Inherit the related result type, if we can. - if (InterfaceMD->hasRelatedResultType() && - !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + + ResultTypeCompatibilityKind RTC + = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass); + + // Search for overridden methods and merge information down from them. + OverrideSearch overrides(*this, ObjCMethod); + for (OverrideSearch::iterator + i = overrides.begin(), e = overrides.end(); i != e; ++i) { + ObjCMethodDecl *overridden = *i; + + // Propagate down the 'related result type' bit from overridden methods. + if (RTC != RTC_Incompatible && overridden->hasRelatedResultType()) ObjCMethod->SetRelatedResultType(); - - mergeObjCMethodDecls(ObjCMethod, InterfaceMD); + + // Then merge the declarations. + mergeObjCMethodDecls(ObjCMethod, overridden); + + // Check for overriding methods + if (isa<ObjCInterfaceDecl>(ObjCMethod->getDeclContext()) || + isa<ObjCImplementationDecl>(ObjCMethod->getDeclContext())) + CheckConflictingOverridingMethod(ObjCMethod, overridden, + isa<ObjCProtocolDecl>(overridden->getDeclContext())); } bool ARCError = false; if (getLangOptions().ObjCAutoRefCount) ARCError = CheckARCMethodDecl(*this, ObjCMethod); - if (!ObjCMethod->hasRelatedResultType() && !ARCError && - getLangOptions().ObjCInferRelatedResultType) { + // Infer the related result type when possible. + if (!ARCError && RTC == RTC_Compatible && + !ObjCMethod->hasRelatedResultType() && + LangOpts.ObjCInferRelatedResultType) { bool InferRelatedResultType = false; switch (ObjCMethod->getMethodFamily()) { case OMF_None: case OMF_copy: case OMF_dealloc: + case OMF_finalize: case OMF_mutableCopy: case OMF_release: case OMF_retainCount: @@ -2490,14 +2733,8 @@ Decl *Sema::ActOnMethodDeclaration( break; } - if (InferRelatedResultType && - !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + if (InferRelatedResultType) ObjCMethod->SetRelatedResultType(); - - if (!InterfaceMD && - anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod())) - CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl)); } return ObjCMethod; @@ -2506,7 +2743,12 @@ Decl *Sema::ActOnMethodDeclaration( bool Sema::CheckObjCDeclScope(Decl *D) { if (isa<TranslationUnitDecl>(CurContext->getRedeclContext())) return false; - + // Following is also an error. But it is caused by a missing @end + // and diagnostic is issued elsewhere. + if (isa<ObjCContainerDecl>(CurContext->getRedeclContext())) { + return false; + } + Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope); D->setInvalidDecl(); @@ -2517,7 +2759,7 @@ bool Sema::CheckObjCDeclScope(Decl *D) { /// instance variables of ClassName into Decls. void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, - llvm::SmallVectorImpl<Decl*> &Decls) { + SmallVectorImpl<Decl*> &Decls) { // Check that ClassName is a valid class ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { @@ -2530,11 +2772,11 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, } // Collect the instance variables - llvm::SmallVector<ObjCIvarDecl*, 32> Ivars; + SmallVector<const ObjCIvarDecl*, 32> Ivars; Context.DeepCollectObjCIvars(Class, true, Ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. for (unsigned i = 0; i < Ivars.size(); i++) { - FieldDecl* ID = cast<FieldDecl>(Ivars[i]); + const FieldDecl* ID = cast<FieldDecl>(Ivars[i]); RecordDecl *Record = dyn_cast<RecordDecl>(TagD); Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, /*FIXME: StartL=*/ID->getLocation(), @@ -2545,7 +2787,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, } // Introduce all of these fields into the appropriate scope. - for (llvm::SmallVectorImpl<Decl*>::iterator D = Decls.begin(); + for (SmallVectorImpl<Decl*>::iterator D = Decls.begin(); D != Decls.end(); ++D) { FieldDecl *FD = cast<FieldDecl>(*D); if (getLangOptions().CPlusPlus) @@ -2647,7 +2889,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + SmallVectorImpl<ObjCIvarDecl*> &Ivars) { for (ObjCIvarDecl *Iv = OI->all_declared_ivar_begin(); Iv; Iv= Iv->getNextIvar()) { QualType QT = Context.getBaseElementType(Iv->getType()); @@ -2656,20 +2898,15 @@ void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, } } -void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, - CXXCtorInitializer ** initializers, - unsigned numInitializers) { - if (numInitializers > 0) { - NumIvarInitializers = numInitializers; - CXXCtorInitializer **ivarInitializers = - new (C) CXXCtorInitializer*[NumIvarInitializers]; - memcpy(ivarInitializers, initializers, - numInitializers * sizeof(CXXCtorInitializer*)); - IvarInitializers = ivarInitializers; - } -} - void Sema::DiagnoseUseOfUnimplementedSelectors() { + // Load referenced selectors from the external source. + if (ExternalSource) { + SmallVector<std::pair<Selector, SourceLocation>, 4> Sels; + ExternalSource->ReadReferencedSelectors(Sels); + for (unsigned I = 0, N = Sels.size(); I != N; ++I) + ReferencedSelectors[Sels[I].first] = Sels[I].second; + } + // Warning will be issued only when selector table is // generated (which means there is at lease one implementation // in the TU). This is to match gcc's behavior. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index 7bcec31..92af2d9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -101,7 +101,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; unsigned DiagID = diag::err_mismatched_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; if (!CheckEquivalentExceptionSpec(PDiag(DiagID), @@ -205,7 +205,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { else OS << ", "; - OS << E->getAsString(Context.PrintingPolicy); + OS << E->getAsString(getPrintingPolicy()); } OS << ")"; break; @@ -217,13 +217,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { case EST_ComputedNoexcept: OS << "noexcept("; - OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, - Context.PrintingPolicy); + OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, + getPrintingPolicy()); OS << ")"; break; default: - assert(false && "This spec type is compatible with none."); + llvm_unreachable("This spec type is compatible with none."); } OS.flush(); @@ -264,7 +264,7 @@ bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { unsigned DiagID = diag::err_mismatched_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; return CheckEquivalentExceptionSpec( PDiag(DiagID), @@ -717,7 +717,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, } } unsigned DiagID = diag::err_override_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_override_exception_spec; return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::note_overridden_virtual_function), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 5efc365..170097c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -36,10 +36,60 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/Template.h" using namespace clang; using namespace sema; +/// \brief Determine whether the use of this declaration is valid, without +/// emitting diagnostics. +bool Sema::CanUseDecl(NamedDecl *D) { + // See if this is an auto-typed variable whose initializer we are parsing. + if (ParsingInitForAutoVars.count(D)) + return false; + + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDeleted()) + return false; + } + return true; +} + +static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, + NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass) { + // See if this declaration is unavailable or deprecated. + std::string Message; + AvailabilityResult Result = D->getAvailability(&Message); + switch (Result) { + case AR_Available: + case AR_NotYetIntroduced: + break; + + case AR_Deprecated: + S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + break; + + case AR_Unavailable: + if (S.getCurContextAvailability() != AR_Unavailable) { + if (Message.empty()) { + if (!UnknownObjCClass) + S.Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + S.Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else + S.Diag(Loc, diag::err_unavailable_message) + << D->getDeclName() << Message; + S.Diag(D->getLocation(), diag::note_unavailable_here) + << isa<FunctionDecl>(D) << false; + } + break; + } + return Result; +} /// \brief Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. @@ -50,9 +100,6 @@ using namespace sema; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// -/// If IgnoreDeprecated is set to true, this should not warn about deprecated -/// decls. -/// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// @@ -61,10 +108,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. - llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); if (Pos != SuppressedDiagnostics.end()) { - llvm::SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second; + SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second; for (unsigned I = 0, N = Suppressed.size(); I != N; ++I) Diag(Suppressed[I].first, Suppressed[I].second); @@ -91,40 +138,22 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } } - - // See if this declaration is unavailable or deprecated. - std::string Message; - switch (D->getAvailability(&Message)) { - case AR_Available: - case AR_NotYetIntroduced: - break; - - case AR_Deprecated: - EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); - break; - - case AR_Unavailable: - if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) { - if (Message.empty()) { - if (!UnknownObjCClass) - Diag(Loc, diag::err_unavailable) << D->getDeclName(); - else - Diag(Loc, diag::warn_unavailable_fwdclass_message) - << D->getDeclName(); - } - else - Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << Message; - Diag(D->getLocation(), diag::note_unavailable_here) - << isa<FunctionDecl>(D) << false; - } - break; - } + AvailabilityResult Result = + DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass); // Warn if this is used but marked unused. if (D->hasAttr<UnusedAttr>()) Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); - + // For available enumerator, it will become unavailable/deprecated + // if its enum declaration is as such. + if (Result == AR_Available) + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { + const DeclContext *DC = ECD->getDeclContext(); + if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) + DiagnoseAvailabilityOfDecl(*this, + const_cast< EnumDecl *>(TheEnumDecl), + Loc, UnknownObjCClass); + } return false; } @@ -145,94 +174,74 @@ std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { return std::string(); } -/// DiagnoseSentinelCalls - This routine checks on method dispatch calls -/// (and other functions in future), which have been declared with sentinel -/// attribute. It warns if call does not have the sentinel argument. -/// +/// DiagnoseSentinelCalls - This routine checks whether a call or +/// message-send is to a declaration with the sentinel attribute, and +/// if so, it checks that the requirements of the sentinel are +/// satisfied. void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, - Expr **Args, unsigned NumArgs) { + Expr **args, unsigned numArgs) { const SentinelAttr *attr = D->getAttr<SentinelAttr>(); if (!attr) return; - // FIXME: In C++0x, if any of the arguments are parameter pack - // expansions, we can't check for the sentinel now. - int sentinelPos = attr->getSentinel(); - int nullPos = attr->getNullPos(); + // The number of formal parameters of the declaration. + unsigned numFormalParams; + + // The kind of declaration. This is also an index into a %select in + // the diagnostic. + enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType; - // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common - // base class. Then we won't be needing two versions of the same code. - unsigned int i = 0; - bool warnNotEnoughArgs = false; - int isMethod = 0; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - // skip over named parameters. - ObjCMethodDecl::param_iterator P, E = MD->param_end(); - for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (P != E || i >= NumArgs); - isMethod = 1; + numFormalParams = MD->param_size(); + calleeType = CT_Method; } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // skip over named parameters. - ObjCMethodDecl::param_iterator P, E = FD->param_end(); - for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (P != E || i >= NumArgs); - } else if (VarDecl *V = dyn_cast<VarDecl>(D)) { - // block or function pointer call. - QualType Ty = V->getType(); - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { - const FunctionType *FT = Ty->isFunctionPointerType() - ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>() - : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) { - unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned k; - for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs); - } - if (Ty->isBlockPointerType()) - isMethod = 2; - } else + numFormalParams = FD->param_size(); + calleeType = CT_Function; + } else if (isa<VarDecl>(D)) { + QualType type = cast<ValueDecl>(D)->getType(); + const FunctionType *fn = 0; + if (const PointerType *ptr = type->getAs<PointerType>()) { + fn = ptr->getPointeeType()->getAs<FunctionType>(); + if (!fn) return; + calleeType = CT_Function; + } else if (const BlockPointerType *ptr = type->getAs<BlockPointerType>()) { + fn = ptr->getPointeeType()->castAs<FunctionType>(); + calleeType = CT_Block; + } else { return; - } else - return; + } - if (warnNotEnoughArgs) { - Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) { + numFormalParams = proto->getNumArgs(); + } else { + numFormalParams = 0; + } + } else { return; } - int sentinel = i; - while (sentinelPos > 0 && i < NumArgs-1) { - --sentinelPos; - ++i; - } - if (sentinelPos > 0) { + + // "nullPos" is the number of formal parameters at the end which + // effectively count as part of the variadic arguments. This is + // useful if you would prefer to not have *any* formal parameters, + // but the language forces you to have at least one. + unsigned nullPos = attr->getNullPos(); + assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel"); + numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos); + + // The number of arguments which should follow the sentinel. + unsigned numArgsAfterSentinel = attr->getSentinel(); + + // If there aren't enough arguments for all the formal parameters, + // the sentinel, and the args after the sentinel, complain. + if (numArgs < numFormalParams + numArgsAfterSentinel + 1) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << calleeType; return; } - while (i < NumArgs-1) { - ++i; - ++sentinel; - } - Expr *sentinelExpr = Args[sentinel]; + + // Otherwise, find the sentinel expression. + Expr *sentinelExpr = args[numArgs - numArgsAfterSentinel - 1]; if (!sentinelExpr) return; - if (sentinelExpr->isTypeDependent()) return; if (sentinelExpr->isValueDependent()) return; // nullptr_t is always treated as null. @@ -246,13 +255,32 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, // Unfortunately, __null has type 'int'. if (isa<GNUNullExpr>(sentinelExpr)) return; - Diag(Loc, diag::warn_missing_sentinel) << isMethod; - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + // Pick a reasonable string to insert. Optimistically use 'nil' or + // 'NULL' if those are actually defined in the context. Only use + // 'nil' for ObjC methods, where it's much more likely that the + // variadic arguments form a list of object pointers. + SourceLocation MissingNilLoc + = PP.getLocForEndOfToken(sentinelExpr->getLocEnd()); + std::string NullValue; + if (calleeType == CT_Method && + PP.getIdentifierInfo("nil")->hasMacroDefinition()) + NullValue = "nil"; + else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition()) + NullValue = "NULL"; + else + NullValue = "(void*) 0"; + + if (MissingNilLoc.isInvalid()) + Diag(Loc, diag::warn_missing_sentinel) << calleeType; + else + Diag(MissingNilLoc, diag::warn_missing_sentinel) + << calleeType + << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); + Diag(D->getLocation(), diag::note_sentinel_here) << calleeType; } -SourceRange Sema::getExprRange(ExprTy *E) const { - Expr *Ex = (Expr *)E; - return Ex? Ex->getSourceRange() : SourceRange(); +SourceRange Sema::getExprRange(Expr *E) const { + return E ? E->getSourceRange() : SourceRange(); } //===----------------------------------------------------------------------===// @@ -261,6 +289,13 @@ SourceRange Sema::getExprRange(ExprTy *E) const { /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { + // Handle any placeholder expressions which made it here. + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); @@ -306,6 +341,13 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) { } ExprResult Sema::DefaultLvalueConversion(Expr *E) { + // Handle any placeholder expressions which made it here. + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + // C++ [conv.lval]p1: // A glvalue of a non-function, non-array type T can be // converted to a prvalue. @@ -314,6 +356,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); + // We can't do lvalue-to-rvalue on atomics yet. + if (T->getAs<AtomicType>()) + return Owned(E); + // Create a load out of an ObjCProperty l-value, if necessary. if (E->getObjectKind() == OK_ObjCProperty) { ExprResult Res = ConvertPropertyForRValue(E); @@ -350,14 +396,14 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // C99 6.3.2.1p2: // If the lvalue has qualified type, the value has the unqualified // version of the type of the lvalue; otherwise, the value has the - // type of the lvalue. + // type of the lvalue. if (T.hasQualifiers()) T = T.getUnqualifiedType(); - CheckArrayAccess(E); - - return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, - E, 0, VK_RValue)); + ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, + E, 0, VK_RValue)); + + return Res; } ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { @@ -382,10 +428,15 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { if (Res.isInvalid()) return Owned(E); E = Res.take(); - + QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - + + // Half FP is a bit different: it's a storage-only type, meaning that any + // "use" of it should be promoted to float. + if (Ty->isHalfType()) + return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast); + // Try to perform integral promotions if the object has a theoretically // promotable type. if (Ty->isIntegralOrUnscopedEnumerationType()) { @@ -402,7 +453,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { // value is converted to an int; otherwise, it is converted to an // unsigned int. These are called the integer promotions. All // other types are unchanged by the integer promotions. - + QualType PTy = Context.isPromotableBitField(E); if (!PTy.isNull()) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).take(); @@ -433,6 +484,28 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { if (Ty->isSpecificBuiltinType(BuiltinType::Float)) E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take(); + // C++ performs lvalue-to-rvalue conversion as a default argument + // promotion, even on class types, but note: + // C++11 [conv.lval]p2: + // When an lvalue-to-rvalue conversion occurs in an unevaluated + // operand or a subexpression thereof the value contained in the + // referenced object is not accessed. Otherwise, if the glvalue + // has a class type, the conversion copy-initializes a temporary + // of type T from the glvalue and the result of the conversion + // is a prvalue for the temporary. + // FIXME: add some way to gate this entire thing for correctness in + // potentially potentially evaluated contexts. + if (getLangOptions().CPlusPlus && E->isGLValue() && + ExprEvalContexts.back().Context != Unevaluated) { + ExprResult Temp = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(E->getType()), + E->getExprLoc(), + Owned(E)); + if (Temp.isInvalid()) + return ExprError(); + E = Temp.get(); + } + return Owned(E); } @@ -450,20 +523,17 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); E = ExprRes.take(); - // __builtin_va_start takes the second argument as a "varargs" argument, but - // it doesn't actually do anything with it. It doesn't need to be non-pod - // etc. - if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) - return Owned(E); - // Don't allow one to pass an Objective-C interface to a vararg. if (E->getType()->isObjCObjectType() && DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << E->getType() << CT)) return ExprError(); - - if (!E->getType().isPODType(Context)) { + + // Complain about passing non-POD types through varargs. However, don't + // perform this check for incomplete types, which we can get here when we're + // in an unevaluated context. + if (!E->getType()->isIncompleteType() && !E->getType().isPODType(Context)) { // C++0x [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) // having a non-trivial copy constructor, a non-trivial move constructor, @@ -507,8 +577,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, Call.get(), E); if (Comma.isInvalid()) - return ExprError(); - + return ExprError(); E = Comma.get(); } } @@ -516,307 +585,363 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return Owned(E); } -/// UsualArithmeticConversions - Performs various conversions that are common to -/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this -/// routine returns the first non-arithmetic type found. The client is -/// responsible for emitting appropriate error diagnostics. -/// FIXME: verify the conversion rules for "complex int" are consistent with -/// GCC. -QualType Sema::UsualArithmeticConversions(ExprResult &lhsExpr, ExprResult &rhsExpr, - bool isCompAssign) { - if (!isCompAssign) { - lhsExpr = UsualUnaryConversions(lhsExpr.take()); - if (lhsExpr.isInvalid()) - return QualType(); +/// \brief Converts an integer to complex float type. Helper function of +/// UsualArithmeticConversions() +/// +/// \return false if the integer expression is an integer type and is +/// successfully converted to the complex type. +static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, + ExprResult &ComplexExpr, + QualType IntTy, + QualType ComplexTy, + bool SkipCast) { + if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; + if (SkipCast) return false; + if (IntTy->isIntegerType()) { + QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType(); + IntExpr = S.ImpCastExprToType(IntExpr.take(), fpTy, CK_IntegralToFloating); + IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy, + CK_FloatingRealToComplex); + } else { + assert(IntTy->isComplexIntegerType()); + IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy, + CK_IntegralComplexToFloatingComplex); } + return false; +} - rhsExpr = UsualUnaryConversions(rhsExpr.take()); - if (rhsExpr.isInvalid()) - return QualType(); - - // For conversion purposes, we ignore any qualifiers. - // For example, "const float" and "float" are equivalent. - QualType lhs = - Context.getCanonicalType(lhsExpr.get()->getType()).getUnqualifiedType(); - QualType rhs = - Context.getCanonicalType(rhsExpr.get()->getType()).getUnqualifiedType(); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; - - // Apply unary and bitfield promotions to the LHS's type. - QualType lhs_unpromoted = lhs; - if (lhs->isPromotableIntegerType()) - lhs = Context.getPromotedIntegerType(lhs); - QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr.get()); - if (!LHSBitfieldPromoteTy.isNull()) - lhs = LHSBitfieldPromoteTy; - if (lhs != lhs_unpromoted && !isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), lhs, CK_IntegralCast); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // At this point, we have two different arithmetic types. - - // Handle complex types first (C99 6.3.1.8p1). - bool LHSComplexFloat = lhs->isComplexType(); - bool RHSComplexFloat = rhs->isComplexType(); - if (LHSComplexFloat || RHSComplexFloat) { - // if we have an integer operand, the result is the complex type. - - if (!RHSComplexFloat && !rhs->isRealFloatingType()) { - if (rhs->isIntegerType()) { - QualType fp = cast<ComplexType>(lhs)->getElementType(); - rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_IntegralToFloating); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); - } else { - assert(rhs->isComplexIntegerType()); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexToFloatingComplex); - } - return lhs; - } - - if (!LHSComplexFloat && !lhs->isRealFloatingType()) { - if (!isCompAssign) { - // int -> float -> _Complex float - if (lhs->isIntegerType()) { - QualType fp = cast<ComplexType>(rhs)->getElementType(); - lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_IntegralToFloating); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); - } else { - assert(lhs->isComplexIntegerType()); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexToFloatingComplex); - } - } - return rhs; - } - - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int order = Context.getFloatingTypeOrder(lhs, rhs); - - // If both are complex, just cast to the more precise type. - if (LHSComplexFloat && RHSComplexFloat) { - if (order > 0) { - // _Complex float -> _Complex double - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingComplexCast); - return lhs; - - } else if (order < 0) { - // _Complex float -> _Complex double - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingComplexCast); - return rhs; - } - return lhs; - } - - // If just the LHS is complex, the RHS needs to be converted, - // and the LHS might need to be promoted. - if (LHSComplexFloat) { - if (order > 0) { // LHS is wider - // float -> _Complex double - QualType fp = cast<ComplexType>(lhs)->getElementType(); - rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_FloatingCast); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); - return lhs; - } - - // RHS is at least as wide. Find its corresponding complex type. - QualType result = (order == 0 ? lhs : Context.getComplexType(rhs)); - - // double -> _Complex double - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); - - // _Complex float -> _Complex double - if (!isCompAssign && order < 0) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingComplexCast); - - return result; - } - - // Just the RHS is complex, so the LHS needs to be converted - // and the RHS might need to be promoted. - assert(RHSComplexFloat); - - if (order < 0) { // RHS is wider - // float -> _Complex double - if (!isCompAssign) { - QualType fp = cast<ComplexType>(rhs)->getElementType(); - lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_FloatingCast); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); - } - return rhs; - } - - // LHS is at least as wide. Find its corresponding complex type. - QualType result = (order == 0 ? rhs : Context.getComplexType(lhs)); - - // double -> _Complex double - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); +/// \brief Takes two complex float types and converts them to the same type. +/// Helper function of UsualArithmeticConversions() +static QualType +handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); + if (order < 0) { // _Complex float -> _Complex double - if (order > 0) - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingComplexCast); - - return result; + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingComplexCast); + return RHSType; } + if (order > 0) + // _Complex float -> _Complex double + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingComplexCast); + return LHSType; +} + +/// \brief Converts otherExpr to complex float and promotes complexExpr if +/// necessary. Helper function of UsualArithmeticConversions() +static QualType handleOtherComplexFloatConversion(Sema &S, + ExprResult &ComplexExpr, + ExprResult &OtherExpr, + QualType ComplexTy, + QualType OtherTy, + bool ConvertComplexExpr, + bool ConvertOtherExpr) { + int order = S.Context.getFloatingTypeOrder(ComplexTy, OtherTy); + + // If just the complexExpr is complex, the otherExpr needs to be converted, + // and the complexExpr might need to be promoted. + if (order > 0) { // complexExpr is wider + // float -> _Complex double + if (ConvertOtherExpr) { + QualType fp = cast<ComplexType>(ComplexTy)->getElementType(); + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), fp, CK_FloatingCast); + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), ComplexTy, + CK_FloatingRealToComplex); + } + return ComplexTy; + } + + // otherTy is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? ComplexTy : + S.Context.getComplexType(OtherTy)); + + // double -> _Complex double + if (ConvertOtherExpr) + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), result, + CK_FloatingRealToComplex); + + // _Complex float -> _Complex double + if (ConvertComplexExpr && order < 0) + ComplexExpr = S.ImpCastExprToType(ComplexExpr.take(), result, + CK_FloatingComplexCast); - // Now handle "real" floating types (i.e. float, double, long double). - bool LHSFloat = lhs->isRealFloatingType(); - bool RHSFloat = rhs->isRealFloatingType(); - if (LHSFloat || RHSFloat) { - // If we have two real floating types, convert the smaller operand - // to the bigger result. - if (LHSFloat && RHSFloat) { - int order = Context.getFloatingTypeOrder(lhs, rhs); - if (order > 0) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingCast); - return lhs; - } - - assert(order < 0 && "illegal float comparison"); - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingCast); - return rhs; - } - - // If we have an integer operand, the result is the real floating type. - if (LHSFloat) { - if (rhs->isIntegerType()) { - // Convert rhs to the lhs floating point type. - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralToFloating); - return lhs; - } - - // Convert both sides to the appropriate complex float. - assert(rhs->isComplexIntegerType()); - QualType result = Context.getComplexType(lhs); - - // _Complex int -> _Complex float - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); - - // float -> _Complex float - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); - - return result; - } - - assert(RHSFloat); - if (lhs->isIntegerType()) { - // Convert lhs to the rhs floating point type. - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralToFloating); - return rhs; - } - - // Convert both sides to the appropriate complex float. - assert(lhs->isComplexIntegerType()); - QualType result = Context.getComplexType(rhs); + return result; +} - // _Complex int -> _Complex float - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); +/// \brief Handle arithmetic conversion with complex types. Helper function of +/// UsualArithmeticConversions() +static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + // if we have an integer operand, the result is the complex type. + if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, + /*skipCast*/false)) + return LHSType; + if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, + /*skipCast*/IsCompAssign)) + return RHSType; + + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + + bool LHSComplexFloat = LHSType->isComplexType(); + bool RHSComplexFloat = RHSType->isComplexType(); + + // If both are complex, just cast to the more precise type. + if (LHSComplexFloat && RHSComplexFloat) + return handleComplexFloatToComplexFloatConverstion(S, LHS, RHS, + LHSType, RHSType, + IsCompAssign); + + // If only one operand is complex, promote it if necessary and convert the + // other operand to complex. + if (LHSComplexFloat) + return handleOtherComplexFloatConversion( + S, LHS, RHS, LHSType, RHSType, /*convertComplexExpr*/!IsCompAssign, + /*convertOtherExpr*/ true); + + assert(RHSComplexFloat); + return handleOtherComplexFloatConversion( + S, RHS, LHS, RHSType, LHSType, /*convertComplexExpr*/true, + /*convertOtherExpr*/ !IsCompAssign); +} + +/// \brief Hande arithmetic conversion from integer to float. Helper function +/// of UsualArithmeticConversions() +static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, + ExprResult &IntExpr, + QualType FloatTy, QualType IntTy, + bool ConvertFloat, bool ConvertInt) { + if (IntTy->isIntegerType()) { + if (ConvertInt) + // Convert intExpr to the lhs floating point type. + IntExpr = S.ImpCastExprToType(IntExpr.take(), FloatTy, + CK_IntegralToFloating); + return FloatTy; + } + + // Convert both sides to the appropriate complex float. + assert(IntTy->isComplexIntegerType()); + QualType result = S.Context.getComplexType(FloatTy); + + // _Complex int -> _Complex float + if (ConvertInt) + IntExpr = S.ImpCastExprToType(IntExpr.take(), result, + CK_IntegralComplexToFloatingComplex); + + // float -> _Complex float + if (ConvertFloat) + FloatExpr = S.ImpCastExprToType(FloatExpr.take(), result, + CK_FloatingRealToComplex); - // float -> _Complex float - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); + return result; +} - return result; - } +/// \brief Handle arithmethic conversion with floating point types. Helper +/// function of UsualArithmeticConversions() +static QualType handleFloatConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { + bool LHSFloat = LHSType->isRealFloatingType(); + bool RHSFloat = RHSType->isRealFloatingType(); - // Handle GCC complex int extension. - // FIXME: if the operands are (int, _Complex long), we currently - // don't promote the complex. Also, signedness? - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - if (lhsComplexInt && rhsComplexInt) { - int order = Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()); + // If we have two real floating types, convert the smaller operand + // to the bigger result. + if (LHSFloat && RHSFloat) { + int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); + if (order > 0) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingCast); + return LHSType; + } + + assert(order < 0 && "illegal float comparison"); + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingCast); + return RHSType; + } + + if (LHSFloat) + return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, + /*convertFloat=*/!IsCompAssign, + /*convertInt=*/ true); + assert(RHSFloat); + return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, + /*convertInt=*/ true, + /*convertFloat=*/!IsCompAssign); +} + +/// \brief Handle conversions with GCC complex int extension. Helper function +/// of UsualArithmeticConversions() +// FIXME: if the operands are (int, _Complex long), we currently +// don't promote the complex. Also, signedness? +static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType(); + const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType(); + + if (LHSComplexInt && RHSComplexInt) { + int order = S.Context.getIntegerTypeOrder(LHSComplexInt->getElementType(), + RHSComplexInt->getElementType()); assert(order && "inequal types with equal element ordering"); if (order > 0) { // _Complex int -> _Complex long - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexCast); - return lhs; + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralComplexCast); + return LHSType; } - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexCast); - return rhs; - } else if (lhsComplexInt) { - // int -> _Complex int - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralRealToComplex); - return lhs; - } else if (rhsComplexInt) { + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralComplexCast); + return RHSType; + } + + if (LHSComplexInt) { // int -> _Complex int - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralRealToComplex); - return rhs; + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex); + return LHSType; } - // Finally, we have two differing integer types. + assert(RHSComplexInt); + // int -> _Complex int + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex); + return RHSType; +} + +/// \brief Handle integer arithmetic conversions. Helper function of +/// UsualArithmeticConversions() +static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { // The rules for this case are in C99 6.3.1.8 - int compare = Context.getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->hasSignedIntegerRepresentation(), - rhsSigned = rhs->hasSignedIntegerRepresentation(); - if (lhsSigned == rhsSigned) { + int order = S.Context.getIntegerTypeOrder(LHSType, RHSType); + bool LHSSigned = LHSType->hasSignedIntegerRepresentation(); + bool RHSSigned = RHSType->hasSignedIntegerRepresentation(); + if (LHSSigned == RHSSigned) { // Same signedness; use the higher-ranked type - if (compare >= 0) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; - } else if (compare != (lhsSigned ? 1 : -1)) { + if (order >= 0) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; + } else if (order != (LHSSigned ? 1 : -1)) { // The unsigned type has greater than or equal rank to the // signed type, so use the unsigned type - if (rhsSigned) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; - } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { + if (RHSSigned) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; + } else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) { // The two types are different widths; if we are here, that // means the signed type is larger than the unsigned type, so // use the signed type. - if (lhsSigned) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; + if (LHSSigned) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; } else { // The signed type is higher-ranked than the unsigned type, // but isn't actually any bigger (like unsigned int and long // on most 32-bit systems). Use the unsigned type corresponding // to the signed type. QualType result = - Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralCast); - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralCast); + S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType); + RHS = S.ImpCastExprToType(RHS.take(), result, CK_IntegralCast); + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), result, CK_IntegralCast); return result; } } +/// UsualArithmeticConversions - Performs various conversions that are common to +/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this +/// routine returns the first non-arithmetic type found. The client is +/// responsible for emitting appropriate error diagnostics. +/// FIXME: verify the conversion rules for "complex int" are consistent with +/// GCC. +QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, + bool IsCompAssign) { + if (!IsCompAssign) { + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) + return QualType(); + } + + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) + return QualType(); + + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType LHSType = + Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); + QualType RHSType = + Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (LHSType == RHSType) + return LHSType; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType()) + return LHSType; + + // Apply unary and bitfield promotions to the LHS's type. + QualType LHSUnpromotedType = LHSType; + if (LHSType->isPromotableIntegerType()) + LHSType = Context.getPromotedIntegerType(LHSType); + QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); + if (!LHSBitfieldPromoteTy.isNull()) + LHSType = LHSBitfieldPromoteTy; + if (LHSType != LHSUnpromotedType && !IsCompAssign) + LHS = ImpCastExprToType(LHS.take(), LHSType, CK_IntegralCast); + + // If both types are identical, no conversion is needed. + if (LHSType == RHSType) + return LHSType; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + if (LHSType->isComplexType() || RHSType->isComplexType()) + return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Now handle "real" floating types (i.e. float, double, long double). + if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) + return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Handle GCC complex int extension. + if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) + return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Finally, we have two differing integer types. + return handleIntegerConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); +} + //===----------------------------------------------------------------------===// // Semantic Analysis for various Expression Types //===----------------------------------------------------------------------===// @@ -827,13 +952,13 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, - MultiTypeArg types, - MultiExprArg exprs) { - unsigned NumAssocs = types.size(); - assert(NumAssocs == exprs.size()); + MultiTypeArg ArgTypes, + MultiExprArg ArgExprs) { + unsigned NumAssocs = ArgTypes.size(); + assert(NumAssocs == ArgExprs.size()); - ParsedType *ParsedTypes = types.release(); - Expr **Exprs = exprs.release(); + ParsedType *ParsedTypes = ArgTypes.release(); + Expr **Exprs = ArgExprs.release(); TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; for (unsigned i = 0; i < NumAssocs; ++i) { @@ -922,7 +1047,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, Types, Exprs, NumAssocs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack)); - llvm::SmallVector<unsigned, 1> CompatIndices; + SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; for (unsigned i = 0; i < NumAssocs; ++i) { if (!Types[i]) @@ -942,7 +1067,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match) << ControllingExpr->getSourceRange() << ControllingExpr->getType() << (unsigned) CompatIndices.size(); - for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(), + for (SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(), E = CompatIndices.end(); I != E; ++I) { Diag(Types[*I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) @@ -993,16 +1118,30 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { if (Literal.hadError) return ExprError(); - llvm::SmallVector<SourceLocation, 4> StringTokLocs; + SmallVector<SourceLocation, 4> StringTokLocs; for (unsigned i = 0; i != NumStringToks; ++i) StringTokLocs.push_back(StringToks[i].getLocation()); QualType StrTy = Context.CharTy; - if (Literal.AnyWide) + if (Literal.isWide()) StrTy = Context.getWCharType(); + else if (Literal.isUTF16()) + StrTy = Context.Char16Ty; + else if (Literal.isUTF32()) + StrTy = Context.Char32Ty; else if (Literal.Pascal) StrTy = Context.UnsignedCharTy; + StringLiteral::StringKind Kind = StringLiteral::Ascii; + if (Literal.isWide()) + Kind = StringLiteral::Wide; + else if (Literal.isUTF8()) + Kind = StringLiteral::UTF8; + else if (Literal.isUTF16()) + Kind = StringLiteral::UTF16; + else if (Literal.isUTF32()) + Kind = StringLiteral::UTF32; + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) StrTy.addConst(); @@ -1016,7 +1155,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { // Pass &StringTokLocs[0], StringTokLocs.size() to factory! return Owned(StringLiteral::Create(Context, Literal.GetString(), - Literal.AnyWide, Literal.Pascal, StrTy, + Kind, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size())); } @@ -1091,21 +1230,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, /// There is a well-formed capture at a particular scope level; /// propagate it through all the nested blocks. -static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex, - const BlockDecl::Capture &capture) { - VarDecl *var = capture.getVariable(); +static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex, + const BlockDecl::Capture &Capture) { + VarDecl *var = Capture.getVariable(); // Update all the inner blocks with the capture information. - for (unsigned i = validScopeIndex + 1, e = S.FunctionScopes.size(); + for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size(); i != e; ++i) { BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]); innerBlock->Captures.push_back( - BlockDecl::Capture(capture.getVariable(), capture.isByRef(), - /*nested*/ true, capture.getCopyExpr())); + BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(), + /*nested*/ true, Capture.getCopyExpr())); innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1 } - return capture.isByRef() ? CR_CaptureByRef : CR_Capture; + return Capture.isByRef() ? CR_CaptureByRef : CR_Capture; } /// shouldCaptureValueReference - Determine if a reference to the @@ -1114,9 +1253,9 @@ static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex, /// This also keeps the captures set in the BlockScopeInfo records /// up-to-date. static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, - ValueDecl *value) { + ValueDecl *Value) { // Only variables ever require capture. - VarDecl *var = dyn_cast<VarDecl>(value); + VarDecl *var = dyn_cast<VarDecl>(Value); if (!var) return CR_NoCapture; // Fast path: variables from the current context never require capture. @@ -1225,19 +1364,19 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, blockScope->Captures.back()); } -static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *vd, +static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD, const DeclarationNameInfo &NameInfo, - bool byRef) { - assert(isa<VarDecl>(vd) && "capturing non-variable"); + bool ByRef) { + assert(isa<VarDecl>(VD) && "capturing non-variable"); - VarDecl *var = cast<VarDecl>(vd); + VarDecl *var = cast<VarDecl>(VD); assert(var->hasLocalStorage() && "capturing non-local"); - assert(byRef == var->hasAttr<BlocksAttr>() && "byref set wrong"); + assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong"); QualType exprType = var->getType().getNonReferenceType(); BlockDeclRefExpr *BDRE; - if (!byRef) { + if (!ByRef) { // The variable will be bound by copy; make it const within the // closure, but record that this was done in the expression. bool constAdded = !exprType.isConstQualified(); @@ -1268,6 +1407,20 @@ ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS) { + if (getLangOptions().CUDA) + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) + if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { + CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller), + CalleeTarget = IdentifyCUDATarget(Callee); + if (CheckCUDATarget(CallerTarget, CalleeTarget)) { + Diag(NameInfo.getLoc(), diag::err_ref_bad_target) + << CalleeTarget << D->getIdentifier() << CallerTarget; + Diag(D->getLocation(), diag::note_previous_decl) + << D->getIdentifier(); + return ExprError(); + } + } + MarkDeclarationReferenced(NameInfo.getLoc(), D); Expr *E = DeclRefExpr::Create(Context, @@ -1276,7 +1429,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, D, NameInfo, Ty, VK); // Just in case we're building an illegal pointer-to-member. - if (isa<FieldDecl>(D) && cast<FieldDecl>(D)->getBitWidth()) + FieldDecl *FD = dyn_cast<FieldDecl>(D); + if (FD && FD->isBitField()) E->setObjectKind(OK_BitField); return Owned(E); @@ -1291,10 +1445,11 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, /// This actually loses a lot of source location information for /// non-standard name kinds; we should consider preserving that in /// some way. -void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, - TemplateArgumentListInfo &Buffer, - DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *&TemplateArgs) { +void +Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedId::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); @@ -1319,7 +1474,9 @@ void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, /// /// \return false if new lookup candidates were found bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, - CorrectTypoContext CTC) { + CorrectTypoContext CTC, + TemplateArgumentListInfo *ExplicitTemplateArgs, + Expr **Args, unsigned NumArgs) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -1358,6 +1515,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CXXMethodDecl *DepMethod = cast_or_null<CXXMethodDecl>( CurMethod->getInstantiatedFromMemberFunction()); if (DepMethod) { + if (getLangOptions().MicrosoftExt) + diagnostic = diag::warn_found_via_dependent_bases_lookup; Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); QualType DepThisType = DepMethod->getThisType(Context); @@ -1373,7 +1532,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CXXDependentScopeMemberExpr::Create( Context, DepThis, DepThisType, true, SourceLocation(), SS.getWithLocInContext(Context), NULL, - R.getLookupNameInfo(), &TList); + R.getLookupNameInfo(), + ULE->hasExplicitTemplateArgs() ? &TList : 0); CallsUndergoingInstantiation.back()->setCallee(DepExpr); } else { // FIXME: we should be able to handle this case too. It is correct @@ -1405,6 +1565,30 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, R.setLookupName(Corrected.getCorrection()); if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + if (Corrected.isOverloaded()) { + OverloadCandidateSet OCS(R.getNameLoc()); + OverloadCandidateSet::iterator Best; + for (TypoCorrection::decl_iterator CD = Corrected.begin(), + CDEnd = Corrected.end(); + CD != CDEnd; ++CD) { + if (FunctionTemplateDecl *FTD = + dyn_cast<FunctionTemplateDecl>(*CD)) + AddTemplateOverloadCandidate( + FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs, + Args, NumArgs, OCS); + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD)) + if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0) + AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), + Args, NumArgs, OCS); + } + switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) { + case OR_Success: + ND = Best->Function; + break; + default: + break; + } + } R.addDecl(ND); if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) { if (SS.isEmpty()) @@ -1430,7 +1614,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // correction, but don't make it a fix-it since we're not going // to recover well anyway. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; + Diag(R.getNameLoc(), diagnostic_suggest) + << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr @@ -1467,96 +1652,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } -ObjCPropertyDecl *Sema::canSynthesizeProvisionalIvar(IdentifierInfo *II) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return 0; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return 0; - ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); - if (!property) - return 0; - if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || - PIDecl->getPropertyIvarDecl()) - return 0; - return property; -} - -bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return false; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return false; - if (ObjCPropertyImplDecl *PIDecl - = ClassImpDecl->FindPropertyImplDecl(Property->getIdentifier())) - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || - PIDecl->getPropertyIvarDecl()) - return false; - - return true; -} - -ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup, - IdentifierInfo *II, - SourceLocation NameLoc) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - bool LookForIvars; - if (Lookup.empty()) - LookForIvars = true; - else if (CurMeth->isClassMethod()) - LookForIvars = false; - else - LookForIvars = (Lookup.isSingleResult() && - Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod() && - (Lookup.getAsSingle<VarDecl>() != 0)); - if (!LookForIvars) - return 0; - - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return 0; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return 0; - bool DynamicImplSeen = false; - ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); - if (!property) - return 0; - if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) { - DynamicImplSeen = - (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); - // property implementation has a designated ivar. No need to assume a new - // one. - if (!DynamicImplSeen && PIDecl->getPropertyIvarDecl()) - return 0; - } - if (!DynamicImplSeen) { - QualType PropType = Context.getCanonicalType(property->getType()); - ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, - NameLoc, NameLoc, - II, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Private, - (Expr *)0, true); - ClassImpDecl->addDecl(Ivar); - IDecl->makeDeclVisibleInContext(Ivar, false); - property->setPropertyIvarDecl(Ivar); - return Ivar; - } - return 0; -} - ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id, bool HasTrailingLParen, - bool isAddressOfOperand) { - assert(!(isAddressOfOperand && HasTrailingLParen) && + bool IsAddressOfOperand) { + assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) @@ -1598,7 +1699,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, } if (DependentID) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); bool IvarLookupFollowUp = false; @@ -1618,7 +1719,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); } else { IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); @@ -1627,7 +1728,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If the result might be in a dependent base class, this is a dependent // id-expression. if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); // If this reference is in an Objective-C method, then we need to do @@ -1640,19 +1741,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (Expr *Ex = E.takeAs<Expr>()) return Owned(Ex); - // Synthesize ivars lazily. - if (getLangOptions().ObjCDefaultSynthProperties && - getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(R, II, NameLoc)) { - if (const ObjCPropertyDecl *Property = - canSynthesizeProvisionalIvar(II)) { - Diag(NameLoc, diag::warn_synthesized_ivar_access) << II; - Diag(Property->getLocation(), diag::note_property_declare); - } - return ActOnIdExpression(S, SS, Id, HasTrailingLParen, - isAddressOfOperand); - } - } // for further use, this must be set to false if in class method. IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod(); } @@ -1676,6 +1764,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { + + // In Microsoft mode, if we are inside a template class member function + // and we can't resolve an identifier then assume the identifier is type + // dependent. The goal is to postpone name lookup to instantiation time + // to be able to search into type dependent base classes. + if (getLangOptions().MicrosoftMode && CurContext->isDependentContext() && + isa<CXXMethodDecl>(CurContext)) + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, + TemplateArgs); + if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown)) return ExprError(); @@ -1688,7 +1786,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { R.clear(); ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); - assert(E.isInvalid() || E.get()); + // In a hopelessly buggy code, Objective-C instance variable + // lookup fails and no expression will be built to reference it. + if (!E.isInvalid() && !E.get()) + return ExprError(); return move(E); } } @@ -1723,7 +1824,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // instance method. if (!R.empty() && (*R.begin())->isCXXClassMember()) { bool MightBeImplicitMember; - if (!isAddressOfOperand) + if (!IsAddressOfOperand) MightBeImplicitMember = true; else if (!SS.isEmpty()) MightBeImplicitMember = false; @@ -1950,7 +2051,7 @@ Sema::PerformObjectMemberConversion(Expr *From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); - ExprValueKind VK = CastCategory(From); + ExprValueKind VK = From->getValueKind(); // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its @@ -2341,7 +2442,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. // This should only be possible with a type written directly. - if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType())) + if (const FunctionProtoType *proto + = dyn_cast<FunctionProtoType>(VD->getType())) if (proto->getResultType() == Context.UnknownAnyTy) { type = Context.UnknownAnyTy; valueKind = VK_RValue; @@ -2375,7 +2477,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentType IT; switch (Kind) { - default: assert(0 && "Unknown simple primary expr!"); + default: llvm_unreachable("Unknown simple primary expr!"); case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2] case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break; case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break; @@ -2408,12 +2510,12 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; bool Invalid = false; - llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); + StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); if (Invalid) return ExprError(); CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), - PP); + PP, Tok.getKind()); if (Literal.hadError()) return ExprError(); @@ -2422,14 +2524,25 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { Ty = Context.IntTy; // 'x' and L'x' -> int in C. else if (Literal.isWide()) Ty = Context.WCharTy; // L'x' -> wchar_t in C++. + else if (Literal.isUTF16()) + Ty = Context.Char16Ty; // u'x' -> char16_t in C++0x. + else if (Literal.isUTF32()) + Ty = Context.Char32Ty; // U'x' -> char32_t in C++0x. else if (Literal.isMultiChar()) Ty = Context.IntTy; // 'wxyz' -> int in C++. else Ty = Context.CharTy; // 'x' -> char in C++ - return Owned(new (Context) CharacterLiteral(Literal.getValue(), - Literal.isWide(), - Ty, Tok.getLocation())); + CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii; + if (Literal.isWide()) + Kind = CharacterLiteral::Wide; + else if (Literal.isUTF16()) + Kind = CharacterLiteral::UTF16; + else if (Literal.isUTF32()) + Kind = CharacterLiteral::UTF32; + + return Owned(new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty, + Tok.getLocation())); } ExprResult Sema::ActOnNumericConstant(const Token &Tok) { @@ -2437,7 +2550,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // cannot have a trigraph, escaped newline, radix prefix, or type suffix. if (Tok.getLength() == 1) { const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok); - unsigned IntSize = Context.Target.getIntWidth(); + unsigned IntSize = Context.getTargetInfo().getIntWidth(); return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'), Context.IntTy, Tok.getLocation())); } @@ -2492,7 +2605,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { Diag(Tok.getLocation(), diagnostic) << Ty - << llvm::StringRef(buffer.data(), buffer.size()); + << StringRef(buffer.data(), buffer.size()); } bool isExact = (result == APFloat::opOK); @@ -2517,7 +2630,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { Diag(Tok.getLocation(), diag::ext_longlong); // Get the value in the widest-possible width. - llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0); + llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0); if (Literal.GetIntegerValue(ResultVal)) { // If this value didn't fit into uintmax_t, warn and force to ull. @@ -2537,7 +2650,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { unsigned Width = 0; if (!Literal.isLong && !Literal.isLongLong) { // Are int/unsigned possibilities? - unsigned IntSize = Context.Target.getIntWidth(); + unsigned IntSize = Context.getTargetInfo().getIntWidth(); // Does it fit in a unsigned int? if (ResultVal.isIntN(IntSize)) { @@ -2552,7 +2665,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Are long/unsigned long possibilities? if (Ty.isNull() && !Literal.isLongLong) { - unsigned LongSize = Context.Target.getLongWidth(); + unsigned LongSize = Context.getTargetInfo().getLongWidth(); // Does it fit in a unsigned long? if (ResultVal.isIntN(LongSize)) { @@ -2567,7 +2680,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Finally, check long long if needed. if (Ty.isNull()) { - unsigned LongLongSize = Context.Target.getLongLongWidth(); + unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth(); // Does it fit in a unsigned long long? if (ResultVal.isIntN(LongLongSize)) { @@ -2575,7 +2688,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // To be compatible with MSVC, hex integer literals ending with the // LL or i64 suffix are always signed in Microsoft mode. if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 || - (getLangOptions().Microsoft && Literal.isLongLong))) + (getLangOptions().MicrosoftExt && Literal.isLongLong))) Ty = Context.LongLongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; @@ -2588,7 +2701,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { if (Ty.isNull()) { Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed); Ty = Context.UnsignedLongLongTy; - Width = Context.Target.getLongLongWidth(); + Width = Context.getTargetInfo().getLongLongWidth(); } if (ResultVal.getBitWidth() != Width) @@ -2605,8 +2718,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { return Owned(Res); } -ExprResult Sema::ActOnParenExpr(SourceLocation L, - SourceLocation R, Expr *E) { +ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) { assert((E != 0) && "ActOnParenExpr() missing expr"); return Owned(new (Context) ParenExpr(L, R, E)); } @@ -2672,9 +2784,9 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, /// expression. The logic mostly mirrors the type-based overload, but may modify /// the expression as it completes the type for that expression through template /// instantiation, etc. -bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, +bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind) { - QualType ExprTy = Op->getType(); + QualType ExprTy = E->getType(); // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." @@ -2684,36 +2796,36 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, ExprTy = Ref->getPointeeType(); if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange()); + return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), + E->getSourceRange()); // Whitelist some types as extensions - if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange(), ExprKind)) + if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(), + E->getSourceRange(), ExprKind)) return false; - if (RequireCompleteExprType(Op, + if (RequireCompleteExprType(E, PDiag(diag::err_sizeof_alignof_incomplete_type) - << ExprKind << Op->getSourceRange(), + << ExprKind << E->getSourceRange(), std::make_pair(SourceLocation(), PDiag(0)))) return true; // Completeing the expression's type may have changed it. - ExprTy = Op->getType(); + ExprTy = E->getType(); if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) ExprTy = Ref->getPointeeType(); - if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange(), ExprKind)) + if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), + E->getSourceRange(), ExprKind)) return true; if (ExprKind == UETT_SizeOf) { - if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) { + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { QualType OType = PVD->getOriginalType(); QualType Type = PVD->getType(); if (Type->isPointerType() && OType->isArrayType()) { - Diag(Op->getExprLoc(), diag::warn_sizeof_array_param) + Diag(E->getExprLoc(), diag::warn_sizeof_array_param) << Type << OType; Diag(PVD->getLocation(), diag::note_declared_at); } @@ -2739,34 +2851,34 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, /// standard conversions are not applied to the operand of sizeof. /// /// This policy is followed for all of the unary trait expressions. -bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind) { - if (exprType->isDependentType()) + if (ExprType->isDependentType()) return false; // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = exprType->getAs<ReferenceType>()) - exprType = Ref->getPointeeType(); + if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) + ExprType = Ref->getPointeeType(); if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange); + return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); // Whitelist some types as extensions - if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange, + if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, ExprKind)) return false; - if (RequireCompleteType(OpLoc, exprType, + if (RequireCompleteType(OpLoc, ExprType, PDiag(diag::err_sizeof_alignof_incomplete_type) << ExprKind << ExprRange)) return true; - if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange, + if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, ExprKind)) return true; @@ -2870,12 +2982,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, /// Note that the ArgRange is invalid if isType is false. ExprResult Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, bool isType, + UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, const SourceRange &ArgRange) { // If error parsing type, ignore. if (TyOrEx == 0) return ExprError(); - if (isType) { + if (IsType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); @@ -2887,7 +2999,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, } static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, - bool isReal) { + bool IsReal) { if (V.get()->isTypeDependent()) return S.Context.DependentTy; @@ -2911,12 +3023,12 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, if (PR.isInvalid()) return QualType(); if (PR.get() != V.get()) { V = move(PR); - return CheckRealImagOperand(S, V, Loc, isReal); + return CheckRealImagOperand(S, V, Loc, IsReal); } // Reject anything else. S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType() - << (isReal ? "__real" : "__imag"); + << (IsReal ? "__real" : "__imag"); return QualType(); } @@ -2927,7 +3039,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input) { UnaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown unary op!"); + default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PostInc; break; case tok::minusminus: Opc = UO_PostDec; break; } @@ -2967,7 +3079,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, - Expr *Idx, SourceLocation RLoc) { + Expr *Idx, SourceLocation RLoc) { Expr *LHSExp = Base; Expr *RHSExp = Idx; @@ -3190,7 +3302,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool IsExecConfig) { // Bail out early if calling a builtin with custom typechecking. // We don't need to do this in the if (FDecl) @@ -3202,14 +3315,29 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); bool Invalid = false; + unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumArgsInProto; + unsigned FnKind = Fn->getType()->isBlockPointerType() + ? 1 /* block */ + : (IsExecConfig ? 3 /* kernel function (exec config) */ + : 0 /* function */); // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { - if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) - << Fn->getType()->isBlockPointerType() - << NumArgsInProto << NumArgs << Fn->getSourceRange(); + if (NumArgs < MinArgs) { + Diag(RParenLoc, MinArgs == NumArgsInProto + ? diag::err_typecheck_call_too_few_args + : diag::err_typecheck_call_too_few_args_at_least) + << FnKind + << MinArgs << NumArgs << Fn->getSourceRange(); + + // Emit the location of the prototype. + if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig) + Diag(FDecl->getLocStart(), diag::note_callee_decl) + << FDecl; + + return true; + } Call->setNumArgs(Context, NumArgsInProto); } @@ -3218,24 +3346,25 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (NumArgs > NumArgsInProto) { if (!Proto->isVariadic()) { Diag(Args[NumArgsInProto]->getLocStart(), - diag::err_typecheck_call_too_many_args) - << Fn->getType()->isBlockPointerType() + MinArgs == NumArgsInProto + ? diag::err_typecheck_call_too_many_args + : diag::err_typecheck_call_too_many_args_at_most) + << FnKind << NumArgsInProto << NumArgs << Fn->getSourceRange() << SourceRange(Args[NumArgsInProto]->getLocStart(), Args[NumArgs-1]->getLocEnd()); // Emit the location of the prototype. - if (FDecl && !FDecl->getBuiltinID()) - Diag(FDecl->getLocStart(), - diag::note_typecheck_call_too_many_args) - << FDecl; + if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig) + Diag(FDecl->getLocStart(), diag::note_callee_decl) + << FDecl; // This deletes the extra arguments. Call->setNumArgs(Context, NumArgsInProto); return true; } } - llvm::SmallVector<Expr *, 8> AllArgs; + SmallVector<Expr *, 8> AllArgs; VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; if (Fn->getType()->isBlockPointerType()) @@ -3258,7 +3387,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, const FunctionProtoType *Proto, unsigned FirstProtoArg, Expr **Args, unsigned NumArgs, - llvm::SmallVector<Expr *, 8> &AllArgs, + SmallVector<Expr *, 8> &AllArgs, VariadicCallType CallType) { unsigned NumArgsInProto = Proto->getNumArgs(); unsigned NumArgsToCheck = NumArgs; @@ -3307,6 +3436,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, Arg = ArgExpr.takeAs<Expr>(); } + + // Check for array bounds violations for each argument to the call. This + // check only triggers warnings when the argument isn't a more complex Expr + // with its own checking, such as a BinaryOperator. + CheckArrayAccess(Arg); + AllArgs.push_back(Arg); } @@ -3330,11 +3465,16 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // Otherwise do argument promotion, (C99 6.5.2.2p7). } else { for (unsigned i = ArgIx; i != NumArgs; ++i) { - ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl); + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, + FDecl); Invalid |= Arg.isInvalid(); AllArgs.push_back(Arg.take()); } } + + // Check for array bounds violations. + for (unsigned i = ArgIx; i != NumArgs; ++i) + CheckArrayAccess(Args[i]); } return Invalid; } @@ -3348,16 +3488,16 @@ static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); /// locations. ExprResult Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, - MultiExprArg args, SourceLocation RParenLoc, - Expr *ExecConfig) { - unsigned NumArgs = args.size(); + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig, bool IsExecConfig) { + unsigned NumArgs = ArgExprs.size(); // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn); if (Result.isInvalid()) return ExprError(); Fn = Result.take(); - Expr **Args = args.release(); + Expr **Args = ArgExprs.release(); if (getLangOptions().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. @@ -3419,8 +3559,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic if there's an '&' involved. - if (!find.IsAddressOfOperand) { + // We aren't supposed to apply this logic for if there's an '&' involved. + if (!find.HasFormOfMemberPointer) { OverloadExpr *ovl = find.Expression; if (isa<UnresolvedLookupExpr>(ovl)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl); @@ -3448,12 +3588,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc, - ExecConfig); + ExecConfig, IsExecConfig); } ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, - MultiExprArg execConfig, SourceLocation GGGLoc) { + MultiExprArg ExecConfig, SourceLocation GGGLoc) { FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); if (!ConfigDecl) return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) @@ -3463,27 +3603,29 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, DeclRefExpr *ConfigDR = new (Context) DeclRefExpr( ConfigDecl, ConfigQTy, VK_LValue, LLLLoc); - return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); + return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0, + /*IsExecConfig=*/true); } /// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. /// /// __builtin_astype( value, dst type ) /// -ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty, +ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc) { ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; - QualType DstTy = GetTypeFromParser(destty); - QualType SrcTy = expr->getType(); + QualType DstTy = GetTypeFromParser(ParsedDestTy); + QualType SrcTy = E->getType(); if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) return ExprError(Diag(BuiltinLoc, diag::err_invalid_astype_of_different_size) << DstTy << SrcTy - << expr->getSourceRange()); - return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc)); + << E->getSourceRange()); + return Owned(new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc, + RParenLoc)); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -3497,7 +3639,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, - Expr *Config) { + Expr *Config, bool IsExecConfig) { FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); // Promote the function operand. @@ -3567,6 +3709,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (!FuncT->getResultType()->isVoidType()) return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return) << Fn->getType() << Fn->getSourceRange()); + } else { + // CUDA: Calls to global functions must be configured + if (FDecl && FDecl->hasAttr<CUDAGlobalAttr>()) + return ExprError(Diag(LParenLoc, diag::err_global_call_not_config) + << FDecl->getName() << Fn->getSourceRange()); } } @@ -3582,7 +3729,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs, - RParenLoc)) + RParenLoc, IsExecConfig)) return ExprError(); } else { assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!"); @@ -3682,23 +3829,23 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, ExprResult Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, - SourceLocation RParenLoc, Expr *literalExpr) { + SourceLocation RParenLoc, Expr *LiteralExpr) { QualType literalType = TInfo->getType(); if (literalType->isArrayType()) { if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType), PDiag(diag::err_illegal_decl_array_incomplete_type) << SourceRange(LParenLoc, - literalExpr->getSourceRange().getEnd()))) + LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) - << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())); + << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())); } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, PDiag(diag::err_typecheck_decl_incomplete_type) << SourceRange(LParenLoc, - literalExpr->getSourceRange().getEnd()))) + LiteralExpr->getSourceRange().getEnd()))) return ExprError(); InitializedEntity Entity @@ -3706,17 +3853,17 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializationKind Kind = InitializationKind::CreateCStyleCast(LParenLoc, SourceRange(LParenLoc, RParenLoc)); - InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &literalExpr, 1), + MultiExprArg(*this, &LiteralExpr, 1), &literalType); if (Result.isInvalid()) return ExprError(); - literalExpr = Result.get(); + LiteralExpr = Result.get(); bool isFileScope = getCurFunctionOrMethodDecl() == 0; if (isFileScope) { // 6.5.2.5p3 - if (CheckForConstantInitializer(literalExpr, literalType)) + if (CheckForConstantInitializer(LiteralExpr, literalType)) return ExprError(); } @@ -3725,14 +3872,14 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return MaybeBindToTemporary( new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - VK, literalExpr, isFileScope)); + VK, LiteralExpr, isFileScope)); } ExprResult -Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, +Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { - unsigned NumInit = initlist.size(); - Expr **InitList = initlist.release(); + unsigned NumInit = InitArgList.size(); + Expr **InitList = InitArgList.release(); // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. @@ -3743,27 +3890,68 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } +/// Do an explicit extend of the given block pointer if we're in ARC. +static void maybeExtendBlockObject(Sema &S, ExprResult &E) { + assert(E.get()->getType()->isBlockPointerType()); + assert(E.get()->isRValue()); + + // Only do this in an r-value context. + if (!S.getLangOptions().ObjCAutoRefCount) return; + + E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + CK_ARCExtendBlockObject, E.get(), + /*base path*/ 0, VK_RValue); + S.ExprNeedsCleanups = true; +} + +/// Prepare a conversion of the given expression to an ObjC object +/// pointer type. +CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { + QualType type = E.get()->getType(); + if (type->isObjCObjectPointerType()) { + return CK_BitCast; + } else if (type->isBlockPointerType()) { + maybeExtendBlockObject(*this, E); + return CK_BlockPointerToObjCPointerCast; + } else { + assert(type->isPointerType()); + return CK_CPointerToObjCPointerCast; + } +} + /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. -static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { +CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { // Both Src and Dest are scalar types, i.e. arithmetic or pointer. // Also, callers should have filtered out the invalid cases with // pointers. Everything else should be possible. QualType SrcTy = Src.get()->getType(); - if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy)) + if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; - switch (SrcTy->getScalarTypeKind()) { + switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) { case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_BlockPointer: + case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: - return DestTy->isObjCObjectPointerType() ? - CK_AnyPointerToObjCPointerCast : - CK_BitCast; + case Type::STK_CPointer: + return CK_BitCast; + case Type::STK_BlockPointer: + return (SrcKind == Type::STK_BlockPointer + ? CK_BitCast : CK_AnyPointerToBlockPointerCast); + case Type::STK_ObjCObjectPointer: + if (SrcKind == Type::STK_ObjCObjectPointer) + return CK_BitCast; + else if (SrcKind == Type::STK_CPointer) + return CK_CPointerToObjCPointerCast; + else { + maybeExtendBlockObject(*this, Src); + return CK_BlockPointerToObjCPointerCast; + } case Type::STK_Bool: return CK_PointerToBoolean; case Type::STK_Integral: @@ -3779,8 +3967,11 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: - if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: + if (Src.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) return CK_NullToPointer; return CK_IntegralToPointer; case Type::STK_Bool: @@ -3790,12 +3981,14 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Floating: return CK_IntegralToFloating; case Type::STK_IntegralComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralCast); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_IntegralCast); return CK_IntegralRealToComplex; case Type::STK_FloatingComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralToFloating); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_IntegralToFloating); return CK_FloatingRealToComplex; case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3811,14 +4004,18 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Integral: return CK_FloatingToIntegral; case Type::STK_FloatingComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingCast); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_FloatingCast); return CK_FloatingRealToComplex; case Type::STK_IntegralComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingToIntegral); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_FloatingToIntegral); return CK_IntegralRealToComplex; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3832,19 +4029,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_IntegralComplex: return CK_FloatingComplexToIntegralComplex; case Type::STK_Floating: { - QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); - if (S.Context.hasSameType(ET, DestTy)) + QualType ET = SrcTy->castAs<ComplexType>()->getElementType(); + if (Context.hasSameType(ET, DestTy)) return CK_FloatingComplexToReal; - Src = S.ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal); + Src = ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal); return CK_FloatingCast; } case Type::STK_Bool: return CK_FloatingComplexToBoolean; case Type::STK_Integral: - Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), - CK_FloatingComplexToReal); + Src = ImpCastExprToType(Src.take(), + SrcTy->castAs<ComplexType>()->getElementType(), + CK_FloatingComplexToReal); return CK_FloatingToIntegral; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3858,19 +4058,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_IntegralComplex: return CK_IntegralComplexCast; case Type::STK_Integral: { - QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); - if (S.Context.hasSameType(ET, DestTy)) + QualType ET = SrcTy->castAs<ComplexType>()->getElementType(); + if (Context.hasSameType(ET, DestTy)) return CK_IntegralComplexToReal; - Src = S.ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal); + Src = ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal); return CK_IntegralCast; } case Type::STK_Bool: return CK_IntegralComplexToBoolean; case Type::STK_Floating: - Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), - CK_IntegralComplexToReal); + Src = ImpCastExprToType(Src.take(), + SrcTy->castAs<ComplexType>()->getElementType(), + CK_IntegralComplexToReal); return CK_IntegralToFloating; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex int->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3879,193 +4082,6 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { } llvm_unreachable("Unhandled scalar cast"); - return CK_BitCast; -} - -/// CheckCastTypes - Check type constraints for casting between types. -ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR, - QualType castType, Expr *castExpr, - CastKind& Kind, ExprValueKind &VK, - CXXCastPath &BasePath, bool FunctionalStyle) { - if (castExpr->getType() == Context.UnknownAnyTy) - return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); - - if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(SourceRange(CastStartLoc, - castExpr->getLocEnd()), - castType, VK, castExpr, Kind, BasePath, - FunctionalStyle); - - assert(!castExpr->getType()->isPlaceholderType()); - - // We only support r-value casts in C. - VK = VK_RValue; - - // C99 6.5.4p2: the cast type needs to be void or scalar and the expression - // type needs to be scalar. - if (castType->isVoidType()) { - // We don't necessarily do lvalue-to-rvalue conversions on this. - ExprResult castExprRes = IgnoredValueConversions(castExpr); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - // Cast to void allows any expr type. - Kind = CK_ToVoid; - return Owned(castExpr); - } - - ExprResult castExprRes = DefaultFunctionArrayLvalueConversion(castExpr); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - if (RequireCompleteType(TyR.getBegin(), castType, - diag::err_typecheck_cast_to_incomplete)) - return ExprError(); - - if (!castType->isScalarType() && !castType->isVectorType()) { - if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && - (castType->isStructureType() || castType->isUnionType())) { - // GCC struct/union extension: allow cast to self. - // FIXME: Check that the cast destination type is complete. - Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) - << castType << castExpr->getSourceRange(); - Kind = CK_NoOp; - return Owned(castExpr); - } - - if (castType->isUnionType()) { - // GCC cast to union extension - RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); - RecordDecl::field_iterator Field, FieldEnd; - for (Field = RD->field_begin(), FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Context.hasSameUnqualifiedType(Field->getType(), - castExpr->getType()) && - !Field->isUnnamedBitfield()) { - Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) - << castExpr->getSourceRange(); - break; - } - } - if (Field == FieldEnd) { - Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) - << castExpr->getType() << castExpr->getSourceRange(); - return ExprError(); - } - Kind = CK_ToUnion; - return Owned(castExpr); - } - - // Reject any other conversions to non-scalar types. - Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) - << castType << castExpr->getSourceRange(); - return ExprError(); - } - - // The type we're casting to is known to be a scalar or vector. - - // Require the operand to be a scalar or vector. - if (!castExpr->getType()->isScalarType() && - !castExpr->getType()->isVectorType()) { - Diag(castExpr->getLocStart(), - diag::err_typecheck_expect_scalar_operand) - << castExpr->getType() << castExpr->getSourceRange(); - return ExprError(); - } - - if (castType->isExtVectorType()) - return CheckExtVectorCast(TyR, castType, castExpr, Kind); - - if (castType->isVectorType()) { - if (castType->getAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector && - (castExpr->getType()->isIntegerType() || - castExpr->getType()->isFloatingType())) { - Kind = CK_VectorSplat; - return Owned(castExpr); - } else if (CheckVectorCast(TyR, castType, castExpr->getType(), Kind)) { - return ExprError(); - } else - return Owned(castExpr); - } - if (castExpr->getType()->isVectorType()) { - if (CheckVectorCast(TyR, castExpr->getType(), castType, Kind)) - return ExprError(); - else - return Owned(castExpr); - } - - // The source and target types are both scalars, i.e. - // - arithmetic types (fundamental, enum, and complex) - // - all kinds of pointers - // Note that member pointers were filtered out with C++, above. - - if (isa<ObjCSelectorExpr>(castExpr)) { - Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); - return ExprError(); - } - - // If either type is a pointer, the other type has to be either an - // integer or a pointer. - QualType castExprType = castExpr->getType(); - if (!castType->isArithmeticType()) { - if (!castExprType->isIntegralType(Context) && - castExprType->isArithmeticType()) { - Diag(castExpr->getLocStart(), - diag::err_cast_pointer_from_non_pointer_int) - << castExprType << castExpr->getSourceRange(); - return ExprError(); - } - } else if (!castExpr->getType()->isArithmeticType()) { - if (!castType->isIntegralType(Context) && castType->isArithmeticType()) { - Diag(castExpr->getLocStart(), diag::err_cast_pointer_to_non_pointer_int) - << castType << castExpr->getSourceRange(); - return ExprError(); - } - } - - if (getLangOptions().ObjCAutoRefCount) { - // Diagnose problems with Objective-C casts involving lifetime qualifiers. - CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()), - castType, castExpr, CCK_CStyleCast); - - if (const PointerType *CastPtr = castType->getAs<PointerType>()) { - if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) { - Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); - Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); - if (CastPtr->getPointeeType()->isObjCLifetimeType() && - ExprPtr->getPointeeType()->isObjCLifetimeType() && - !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { - Diag(castExpr->getLocStart(), - diag::err_typecheck_incompatible_ownership) - << castExprType << castType << AA_Casting - << castExpr->getSourceRange(); - - return ExprError(); - } - } - } - else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) { - Diag(castExpr->getLocStart(), - diag::err_arc_convesion_of_weak_unavailable) << 1 - << castExprType << castType - << castExpr->getSourceRange(); - return ExprError(); - } - } - - castExprRes = Owned(castExpr); - Kind = PrepareScalarCast(*this, castExprRes, castType); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - if (Kind == CK_BitCast) - CheckCastAlign(castExpr, castType, TyR); - - return Owned(castExpr); } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, @@ -4096,8 +4112,12 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. + // In OpenCL, casts between vectors of different types are not allowed. + // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) { + if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy) + || (getLangOptions().OpenCL && + (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; return ExprError(); @@ -4116,7 +4136,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); ExprResult CastExprRes = Owned(CastExpr); - CastKind CK = PrepareScalarCast(*this, CastExprRes, DestElemTy); + CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy); if (CastExprRes.isInvalid()) return ExprError(); CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take(); @@ -4128,11 +4148,11 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, ExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, - SourceLocation RParenLoc, Expr *castExpr) { - assert(!D.isInvalidType() && (castExpr != 0) && + SourceLocation RParenLoc, Expr *CastExpr) { + assert(!D.isInvalidType() && (CastExpr != 0) && "ActOnCastExpr(): missing type or expr"); - TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType()); + TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, CastExpr->getType()); if (D.isInvalidType()) return ExprError(); @@ -4141,6 +4161,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, CheckExtraCXXDefaultArguments(D); } + checkUnusedDeclAttributes(D); + QualType castType = castTInfo->getType(); Ty = CreateParsedType(castType, castTInfo); @@ -4148,9 +4170,10 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, // Check for an altivec or OpenCL literal, // i.e. all the elements are integer constants. - ParenExpr *PE = dyn_cast<ParenExpr>(castExpr); - ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr); - if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) { + ParenExpr *PE = dyn_cast<ParenExpr>(CastExpr); + ParenListExpr *PLE = dyn_cast<ParenListExpr>(CastExpr); + if ((getLangOptions().AltiVec || getLangOptions().OpenCL) + && castType->isVectorType() && (PE || PLE)) { if (PLE && PLE->getNumExprs() == 0) { Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer); return ExprError(); @@ -4167,37 +4190,18 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. if (isVectorLiteral) - return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo); + return BuildVectorLiteral(LParenLoc, RParenLoc, CastExpr, castTInfo); // If the Expr being casted is a ParenListExpr, handle it specially. // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. - if (isa<ParenListExpr>(castExpr)) { - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr); + if (isa<ParenListExpr>(CastExpr)) { + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, CastExpr); if (Result.isInvalid()) return ExprError(); - castExpr = Result.take(); + CastExpr = Result.take(); } - return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr); -} - -ExprResult -Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, - SourceLocation RParenLoc, Expr *castExpr) { - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - ExprResult CastResult = - CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(), - castExpr, Kind, VK, BasePath); - if (CastResult.isInvalid()) - return ExprError(); - castExpr = CastResult.take(); - - return Owned(CStyleCastExpr::Create(Context, - Ty->getType().getNonLValueExprType(Context), - VK, Kind, castExpr, &BasePath, Ty, - LParenLoc, RParenLoc)); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, @@ -4221,7 +4225,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType Ty = TInfo->getType(); assert(Ty->isVectorType() && "Expected vector type"); - llvm::SmallVector<Expr *, 8> initExprs; + SmallVector<Expr *, 8> initExprs; const VectorType *VTy = Ty->getAs<VectorType>(); unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); @@ -4237,7 +4241,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); ExprResult Literal = Owned(exprs[0]); Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); + PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); } else if (numExprs < numElems) { @@ -4258,7 +4262,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); ExprResult Literal = Owned(exprs[0]); Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); + PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); } @@ -4277,10 +4281,10 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, /// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence /// of comma binary operators. ExprResult -Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { - ParenListExpr *E = dyn_cast<ParenListExpr>(expr); +Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { + ParenListExpr *E = dyn_cast<ParenListExpr>(OrigExpr); if (!E) - return Owned(expr); + return Owned(OrigExpr); ExprResult Result(E->getExpr(0)); @@ -4294,8 +4298,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { } ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, - SourceLocation R, - MultiExprArg Val) { + SourceLocation R, + MultiExprArg Val) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast<Expr**>(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); @@ -4309,18 +4313,19 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, } /// \brief Emit a specialized diagnostic when one expression is a null pointer -/// constant and the other is not a pointer. -bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, +/// constant and the other is not a pointer. Returns true if a diagnostic is +/// emitted. +bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc) { - Expr *NullExpr = LHS; - Expr *NonPointerExpr = RHS; + Expr *NullExpr = LHSExpr; + Expr *NonPointerExpr = RHSExpr; Expr::NullPointerConstantKind NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); if (NullKind == Expr::NPCK_NotNull) { - NullExpr = RHS; - NonPointerExpr = LHS; + NullExpr = RHSExpr; + NonPointerExpr = LHSExpr; NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); @@ -4345,20 +4350,228 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, return true; } -/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension. -/// In that case, lhs = cond. +/// \brief Return false if the condition expression is valid, true otherwise. +static bool checkCondition(Sema &S, Expr *Cond) { + QualType CondTy = Cond->getType(); + + // C99 6.5.15p2 + if (CondTy->isScalarType()) return false; + + // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. + if (S.getLangOptions().OpenCL && CondTy->isVectorType()) + return false; + + // Emit the proper error message. + S.Diag(Cond->getLocStart(), S.getLangOptions().OpenCL ? + diag::err_typecheck_cond_expect_scalar : + diag::err_typecheck_cond_expect_scalar_or_vector) + << CondTy; + return true; +} + +/// \brief Return false if the two expressions can be converted to a vector, +/// true otherwise +static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS, + ExprResult &RHS, + QualType CondTy) { + // Both operands should be of scalar type. + if (!LHS.get()->getType()->isScalarType()) { + S.Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return true; + } + if (!RHS.get()->getType()->isScalarType()) { + S.Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return true; + } + + // Implicity convert these scalars to the type of the condition. + LHS = S.ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast); + RHS = S.ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast); + return false; +} + +/// \brief Handle when one or both operands are void type. +static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, + ExprResult &RHS) { + Expr *LHSExpr = LHS.get(); + Expr *RHSExpr = RHS.get(); + + if (!LHSExpr->getType()->isVoidType()) + S.Diag(RHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void) + << RHSExpr->getSourceRange(); + if (!RHSExpr->getType()->isVoidType()) + S.Diag(LHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void) + << LHSExpr->getSourceRange(); + LHS = S.ImpCastExprToType(LHS.take(), S.Context.VoidTy, CK_ToVoid); + RHS = S.ImpCastExprToType(RHS.take(), S.Context.VoidTy, CK_ToVoid); + return S.Context.VoidTy; +} + +/// \brief Return false if the NullExpr can be promoted to PointerTy, +/// true otherwise. +static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, + QualType PointerTy) { + if ((!PointerTy->isAnyPointerType() && !PointerTy->isBlockPointerType()) || + !NullExpr.get()->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNull)) + return true; + + NullExpr = S.ImpCastExprToType(NullExpr.take(), PointerTy, CK_NullToPointer); + return false; +} + +/// \brief Checks compatibility between two pointers and return the resulting +/// type. +static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + if (S.Context.hasSameType(LHSTy, RHSTy)) { + // Two identical pointers types are always compatible. + return LHSTy; + } + + QualType lhptee, rhptee; + + // Get the pointee types. + if (const BlockPointerType *LHSBTy = LHSTy->getAs<BlockPointerType>()) { + lhptee = LHSBTy->getPointeeType(); + rhptee = RHSTy->castAs<BlockPointerType>()->getPointeeType(); + } else { + lhptee = LHSTy->castAs<PointerType>()->getPointeeType(); + rhptee = RHSTy->castAs<PointerType>()->getPointeeType(); + } + + if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) { + S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + // In this situation, we assume void* type. No especially good + // reason, but this is what gcc does, and we do have to pick + // to get a consistent AST. + QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy); + LHS = S.ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); + return incompatTy; + } + + // The pointer types are compatible. + // C99 6.5.15p6: If both operands are pointers to compatible types *or* to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the *composite* + // type. + // FIXME: Need to calculate the composite type. + // FIXME: Need to add qualifiers + + LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + return LHSTy; +} + +/// \brief Return the resulting type when the operands are both block pointers. +static QualType checkConditionalBlockPointerCompatibility(Sema &S, + ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { + if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { + QualType destType = S.Context.getPointerType(S.Context.VoidTy); + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast); + return destType; + } + S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + // We have 2 block pointer types. + return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); +} + +/// \brief Return the resulting type when the operands are both pointers. +static QualType +checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + // get the pointer types + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + // get the "pointed to" types + QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + + // ignore qualifiers on void (C99 6.5.15p3, clause 6) + if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { + // Figure out necessary qualifiers (C99 6.5.15p6) + QualType destPointee + = S.Context.getQualifiedType(lhptee, rhptee.getQualifiers()); + QualType destType = S.Context.getPointerType(destPointee); + // Add qualifiers if necessary. + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_NoOp); + // Promote to void*. + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast); + return destType; + } + if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { + QualType destPointee + = S.Context.getQualifiedType(rhptee, lhptee.getQualifiers()); + QualType destType = S.Context.getPointerType(destPointee); + // Add qualifiers if necessary. + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_NoOp); + // Promote to void*. + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast); + return destType; + } + + return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); +} + +/// \brief Return false if the first expression is not an integer and the second +/// expression is not a pointer, true otherwise. +static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, + Expr* PointerExpr, SourceLocation Loc, + bool IsIntFirstExpr) { + if (!PointerExpr->getType()->isPointerType() || + !Int.get()->getType()->isIntegerType()) + return false; + + Expr *Expr1 = IsIntFirstExpr ? Int.get() : PointerExpr; + Expr *Expr2 = IsIntFirstExpr ? PointerExpr : Int.get(); + + S.Diag(Loc, diag::warn_typecheck_cond_pointer_integer_mismatch) + << Expr1->getType() << Expr2->getType() + << Expr1->getSourceRange() << Expr2->getSourceRange(); + Int = S.ImpCastExprToType(Int.take(), PointerExpr->getType(), + CK_IntegralToPointer); + return true; +} + +/// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. +/// In that case, LHS = cond. /// C99 6.5.15 -QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, - ExprValueKind &VK, ExprObjectKind &OK, +QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation QuestionLoc) { - ExprResult lhsResult = CheckPlaceholderExpr(LHS.get()); - if (!lhsResult.isUsable()) return QualType(); - LHS = move(lhsResult); + ExprResult LHSResult = CheckPlaceholderExpr(LHS.get()); + if (!LHSResult.isUsable()) return QualType(); + LHS = move(LHSResult); - ExprResult rhsResult = CheckPlaceholderExpr(RHS.get()); - if (!rhsResult.isUsable()) return QualType(); - RHS = move(rhsResult); + ExprResult RHSResult = CheckPlaceholderExpr(RHS.get()); + if (!RHSResult.isUsable()) return QualType(); + RHS = move(RHSResult); // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) @@ -4382,23 +4595,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR QualType RHSTy = RHS.get()->getType(); // first, check the condition. - if (!CondTy->isScalarType()) { // C99 6.5.15p2 - // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. - // Throw an error if its not either. - if (getLangOptions().OpenCL) { - if (!CondTy->isVectorType()) { - Diag(Cond.get()->getLocStart(), - diag::err_typecheck_cond_expect_scalar_or_vector) - << CondTy; - return QualType(); - } - } - else { - Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return QualType(); - } - } + if (checkCondition(*this, Cond.get())) + return QualType(); // Now check the two expressions. if (LHSTy->isVectorType() || RHSTy->isVectorType()) @@ -4407,22 +4605,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // OpenCL: If the condition is a vector, and both operands are scalar, // attempt to implicity convert them to the vector type to act like the // built in select. - if (getLangOptions().OpenCL && CondTy->isVectorType()) { - // Both operands should be of scalar type. - if (!LHSTy->isScalarType()) { - Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return QualType(); - } - if (!RHSTy->isScalarType()) { - Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; + if (getLangOptions().OpenCL && CondTy->isVectorType()) + if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy)) return QualType(); - } - // Implicity convert these scalars to the type of the condition. - LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast); - RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast); - } // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. @@ -4447,29 +4632,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { - if (!LHSTy->isVoidType()) - Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) - << RHS.get()->getSourceRange(); - if (!RHSTy->isVoidType()) - Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) - << LHS.get()->getSourceRange(); - LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid); - RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid); - return Context.VoidTy; + return checkConditionalVoidType(*this, LHS, RHS); } + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." - if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && - RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - // promote the null to a pointer. - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer); - return LHSTy; - } - if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && - LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer); - return RHSTy; - } + if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy; + if (!checkConditionalNullPointer(*this, LHS, RHSTy)) return RHSTy; // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, @@ -4481,116 +4650,23 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Handle block pointer types. - if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { - if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { - if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { - QualType destType = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); - return destType; - } - Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - return QualType(); - } - // We have 2 block pointer types. - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical block pointer types are always compatible. - return LHSTy; - } - // The block pointer types aren't identical, continue checking. - QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); - - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { - Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - // In this situation, we assume void* type. No especially good - // reason, but this is what gcc does, and we do have to pick - // to get a consistent AST. - QualType incompatTy = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); - return incompatTy; - } - // The block pointer types are compatible. - LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); - return LHSTy; - } + if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) + return checkConditionalBlockPointerCompatibility(*this, LHS, RHS, + QuestionLoc); // Check constraints for C object pointers types (C99 6.5.15p3,6). - if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - // get the "pointed to" types - QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); - - // ignore qualifiers on void (C99 6.5.15p3, clause 6) - if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { - // Figure out necessary qualifiers (C99 6.5.15p6) - QualType destPointee - = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp); - // Promote to void*. - RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); - return destType; - } - if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { - QualType destPointee - = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp); - // Promote to void*. - LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); - return destType; - } - - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical pointer types are always compatible. - return LHSTy; - } - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { - Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - // In this situation, we assume void* type. No especially good - // reason, but this is what gcc does, and we do have to pick - // to get a consistent AST. - QualType incompatTy = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); - return incompatTy; - } - // The pointer types are compatible. - // C99 6.5.15p6: If both operands are pointers to compatible types *or* to - // differently qualified versions of compatible types, the result type is - // a pointer to an appropriately qualified version of the *composite* - // type. - // FIXME: Need to calculate the composite type. - // FIXME: Need to add qualifiers - LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); - return LHSTy; - } + if (LHSTy->isPointerType() && RHSTy->isPointerType()) + return checkConditionalObjectPointersCompatibility(*this, LHS, RHS, + QuestionLoc); // GCC compatibility: soften pointer/integer mismatch. Note that // null pointers have been filtered out by this point. - if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { - Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer); + if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc, + /*isIntFirstExpr=*/true)) return RHSTy; - } - if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { - Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer); + if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc, + /*isIntFirstExpr=*/false)) return LHSTy; - } // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most @@ -4600,14 +4676,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); return QualType(); } /// FindCompositeObjCPointerType - Helper method to find composite type of /// two objective-c pointer types of the two input expressions. QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, - SourceLocation QuestionLoc) { + SourceLocation QuestionLoc) { QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); @@ -4615,34 +4692,34 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && - (Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + (Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) { + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCClassType() && - (Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + (Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) { + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && - (Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + (Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) { + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCIdType() && - (Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + (Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) { + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && - (Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) { + (Context.hasSameType(RHSTy, Context.getObjCSelRedefinitionType()))) { RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && - (Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) { + (Context.hasSameType(LHSTy, Context.getObjCSelRedefinitionType()))) { LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); return RHSTy; } @@ -4653,8 +4730,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // Two identical object pointer types are always compatible. return LHSTy; } - const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *LHSOPT = LHSTy->castAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHSTy->castAs<ObjCObjectPointerType>(); QualType compositeType = LHSTy; // If both operands are interfaces and either operand can be @@ -4752,18 +4829,20 @@ static bool IsArithmeticOp(BinaryOperatorKind Opc) { /// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary /// expression, either using a built-in or overloaded operator, -/// and sets *OpCode to the opcode and *RHS to the right-hand side expression. +/// and sets *OpCode to the opcode and *RHSExprs to the right-hand side +/// expression. static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, - Expr **RHS) { - E = E->IgnoreParenImpCasts(); + Expr **RHSExprs) { + // Don't strip parenthesis: we should not warn if E is in parenthesis. + E = E->IgnoreImpCasts(); E = E->IgnoreConversionOperator(); - E = E->IgnoreParenImpCasts(); + E = E->IgnoreImpCasts(); // Built-in binary operator. if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { if (IsArithmeticOp(OP->getOpcode())) { *Opcode = OP->getOpcode(); - *RHS = OP->getRHS(); + *RHSExprs = OP->getRHS(); return true; } } @@ -4782,7 +4861,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); if (IsArithmeticOp(OpKind)) { *Opcode = OpKind; - *RHS = Call->getArg(1); + *RHSExprs = Call->getArg(1); return true; } } @@ -4817,8 +4896,8 @@ static bool ExprLooksBoolean(Expr *E) { static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, Expr *Condition, - Expr *LHS, - Expr *RHS) { + Expr *LHSExpr, + Expr *RHSExpr) { BinaryOperatorKind CondOpcode; Expr *CondRHS; @@ -4841,7 +4920,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self, SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_conditional_first), - SourceRange(CondRHS->getLocStart(), RHS->getLocEnd())); + SourceRange(CondRHS->getLocStart(), RHSExpr->getLocEnd())); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null @@ -4898,7 +4977,8 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, return Owned(new (Context) BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(), - RHS.take(), QuestionLoc, ColonLoc, result, VK, OK)); + RHS.take(), QuestionLoc, ColonLoc, result, VK, + OK)); } // checkPointerTypesForAssignment - This is a very tricky routine (despite @@ -4907,15 +4987,15 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. static Sema::AssignConvertType -checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { - assert(lhsType.isCanonical() && "LHS not canonicalized!"); - assert(rhsType.isCanonical() && "RHS not canonicalized!"); +checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { + assert(LHSType.isCanonical() && "LHS not canonicalized!"); + assert(RHSType.isCanonical() && "RHS not canonicalized!"); // get the "pointed to" type (ignoring qualifiers at the top level) const Type *lhptee, *rhptee; Qualifiers lhq, rhq; - llvm::tie(lhptee, lhq) = cast<PointerType>(lhsType)->getPointeeType().split(); - llvm::tie(rhptee, rhq) = cast<PointerType>(rhsType)->getPointeeType().split(); + llvm::tie(lhptee, lhq) = cast<PointerType>(LHSType)->getPointeeType().split(); + llvm::tie(rhptee, rhq) = cast<PointerType>(RHSType)->getPointeeType().split(); Sema::AssignConvertType ConvTy = Sema::Compatible; @@ -5019,6 +5099,9 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { // General pointer incompatibility takes priority over qualifiers. return Sema::IncompatiblePointer; } + if (!S.getLangOptions().CPlusPlus && + S.IsNoReturnConversion(ltrans, rtrans, ltrans)) + return Sema::IncompatiblePointer; return ConvTy; } @@ -5027,16 +5110,16 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { /// are compatible. It is more restrict than comparing two function pointer // types. static Sema::AssignConvertType -checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, - QualType rhsType) { - assert(lhsType.isCanonical() && "LHS not canonicalized!"); - assert(rhsType.isCanonical() && "RHS not canonicalized!"); +checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, + QualType RHSType) { + assert(LHSType.isCanonical() && "LHS not canonicalized!"); + assert(RHSType.isCanonical() && "RHS not canonicalized!"); QualType lhptee, rhptee; // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = cast<BlockPointerType>(lhsType)->getPointeeType(); - rhptee = cast<BlockPointerType>(rhsType)->getPointeeType(); + lhptee = cast<BlockPointerType>(LHSType)->getPointeeType(); + rhptee = cast<BlockPointerType>(RHSType)->getPointeeType(); // In C++, the types have to match exactly. if (S.getLangOptions().CPlusPlus) @@ -5048,7 +5131,7 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers()) ConvTy = Sema::CompatiblePointerDiscardsQualifiers; - if (!S.Context.typesAreBlockPointerCompatible(lhsType, rhsType)) + if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) return Sema::IncompatibleBlockPointer; return ConvTy; @@ -5057,51 +5140,49 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, /// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types /// for assignment compatibility. static Sema::AssignConvertType -checkObjCPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { - assert(lhsType.isCanonical() && "LHS was not canonicalized!"); - assert(rhsType.isCanonical() && "RHS was not canonicalized!"); +checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType, + QualType RHSType) { + assert(LHSType.isCanonical() && "LHS was not canonicalized!"); + assert(RHSType.isCanonical() && "RHS was not canonicalized!"); - if (lhsType->isObjCBuiltinType()) { + if (LHSType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() && - !rhsType->isObjCQualifiedClassType()) + if (LHSType->isObjCClassType() && !RHSType->isObjCBuiltinType() && + !RHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } - if (rhsType->isObjCBuiltinType()) { - // Class is not compatible with ObjC object pointers. - if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() && - !lhsType->isObjCQualifiedClassType()) + if (RHSType->isObjCBuiltinType()) { + if (RHSType->isObjCClassType() && !LHSType->isObjCBuiltinType() && + !LHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } - QualType lhptee = - lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = - rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) return Sema::CompatiblePointerDiscardsQualifiers; - if (S.Context.typesAreCompatible(lhsType, rhsType)) + if (S.Context.typesAreCompatible(LHSType, RHSType)) return Sema::Compatible; - if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) + if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType()) return Sema::IncompatibleObjCQualifiedId; return Sema::IncompatiblePointer; } Sema::AssignConvertType Sema::CheckAssignmentConstraints(SourceLocation Loc, - QualType lhsType, QualType rhsType) { + QualType LHSType, QualType RHSType) { // Fake up an opaque expression. We don't actually care about what // cast operations are required, so if CheckAssignmentConstraints // adds casts to this they'll be wasted, but fortunately that doesn't // usually happen on valid code. - OpaqueValueExpr rhs(Loc, rhsType, VK_RValue); - ExprResult rhsPtr = &rhs; + OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue); + ExprResult RHSPtr = &RHSExpr; CastKind K = CK_Invalid; - return CheckAssignmentConstraints(lhsType, rhsPtr, K); + return CheckAssignmentConstraints(LHSType, RHSPtr, K); } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -5122,18 +5203,22 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// /// Sets 'Kind' for any result kind except Incompatible. Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, +Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind) { - QualType rhsType = rhs.get()->getType(); - QualType origLhsType = lhsType; + QualType RHSType = RHS.get()->getType(); + QualType OrigLHSType = LHSType; // Get canonical types. We're not formatting these types, just comparing // them. - lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType(); - rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType(); + LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType(); + RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType(); + + // We can't do assignment from/to atomics yet. + if (LHSType->isAtomicType()) + return Incompatible; // Common case: no conversion required. - if (lhsType == rhsType) { + if (LHSType == RHSType) { Kind = CK_NoOp; return Compatible; } @@ -5143,10 +5228,10 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // e.g., as a parameter type in a built-in function. In this case, // just make sure that the type referenced is compatible with the // right-hand side type. The caller is responsible for adjusting - // lhsType so that the resulting expression does not have reference + // LHSType so that the resulting expression does not have reference // type. - if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) { - if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) { + if (const ReferenceType *LHSTypeRef = LHSType->getAs<ReferenceType>()) { + if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) { Kind = CK_LValueBitCast; return Compatible; } @@ -5155,16 +5240,16 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. - if (lhsType->isExtVectorType()) { - if (rhsType->isExtVectorType()) + if (LHSType->isExtVectorType()) { + if (RHSType->isExtVectorType()) return Incompatible; - if (rhsType->isArithmeticType()) { + if (RHSType->isArithmeticType()) { // CK_VectorSplat does T -> vector T, so first cast to the // element type. - QualType elType = cast<ExtVectorType>(lhsType)->getElementType(); - if (elType != rhsType) { - Kind = PrepareScalarCast(*this, rhs, elType); - rhs = ImpCastExprToType(rhs.take(), elType, Kind); + QualType elType = cast<ExtVectorType>(LHSType)->getElementType(); + if (elType != RHSType) { + Kind = PrepareScalarCast(RHS, elType); + RHS = ImpCastExprToType(RHS.take(), elType, Kind); } Kind = CK_VectorSplat; return Compatible; @@ -5172,11 +5257,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to or from vector type. - if (lhsType->isVectorType() || rhsType->isVectorType()) { - if (lhsType->isVectorType() && rhsType->isVectorType()) { + if (LHSType->isVectorType() || RHSType->isVectorType()) { + if (LHSType->isVectorType() && RHSType->isVectorType()) { // Allow assignments of an AltiVec vector type to an equivalent GCC // vector type and vice versa - if (Context.areCompatibleVectorTypes(lhsType, rhsType)) { + if (Context.areCompatibleVectorTypes(LHSType, RHSType)) { Kind = CK_BitCast; return Compatible; } @@ -5185,7 +5270,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // vectors, the total size only needs to be the same. This is a bitcast; // no bits are changed but the result type is different. if (getLangOptions().LaxVectorConversions && - (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) { + (Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) { Kind = CK_BitCast; return IncompatibleVectors; } @@ -5194,38 +5279,39 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Arithmetic conversions. - if (lhsType->isArithmeticType() && rhsType->isArithmeticType() && - !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) { - Kind = PrepareScalarCast(*this, rhs, lhsType); + if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && + !(getLangOptions().CPlusPlus && LHSType->isEnumeralType())) { + Kind = PrepareScalarCast(RHS, LHSType); return Compatible; } // Conversions to normal pointers. - if (const PointerType *lhsPointer = dyn_cast<PointerType>(lhsType)) { + if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { Kind = CK_BitCast; - return checkPointerTypesForAssignment(*this, lhsType, rhsType); + return checkPointerTypesForAssignment(*this, LHSType, RHSType); } // int -> T* - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null? return IntToPointer; } // C pointers are not compatible with ObjC object pointers, // with two exceptions: - if (isa<ObjCObjectPointerType>(rhsType)) { + if (isa<ObjCObjectPointerType>(RHSType)) { // - conversions to void* - if (lhsPointer->getPointeeType()->isVoidType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (LHSPointer->getPointeeType()->isVoidType()) { + Kind = CK_BitCast; return Compatible; } // - conversions from 'Class' to the redefinition type - if (rhsType->isObjCClassType() && - Context.hasSameType(lhsType, Context.ObjCClassRedefinitionType)) { + if (RHSType->isObjCClassType() && + Context.hasSameType(LHSType, + Context.getObjCClassRedefinitionType())) { Kind = CK_BitCast; return Compatible; } @@ -5235,8 +5321,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // U^ -> void* - if (rhsType->getAs<BlockPointerType>()) { - if (lhsPointer->getPointeeType()->isVoidType()) { + if (RHSType->getAs<BlockPointerType>()) { + if (LHSPointer->getPointeeType()->isVoidType()) { Kind = CK_BitCast; return Compatible; } @@ -5246,27 +5332,27 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to block pointers. - if (isa<BlockPointerType>(lhsType)) { + if (isa<BlockPointerType>(LHSType)) { // U^ -> T^ - if (rhsType->isBlockPointerType()) { - Kind = CK_AnyPointerToBlockPointerCast; - return checkBlockPointerTypesForAssignment(*this, lhsType, rhsType); + if (RHSType->isBlockPointerType()) { + Kind = CK_BitCast; + return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } // int or null -> T^ - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToBlockPointer; } // id -> T^ - if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) { + if (getLangOptions().ObjC1 && RHSType->isObjCIdType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } // void* -> T^ - if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) + if (const PointerType *RHSPT = RHSType->getAs<PointerType>()) if (RHSPT->getPointeeType()->isVoidType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; @@ -5276,48 +5362,49 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to Objective-C pointers. - if (isa<ObjCObjectPointerType>(lhsType)) { + if (isa<ObjCObjectPointerType>(LHSType)) { // A* -> B* - if (rhsType->isObjCObjectPointerType()) { + if (RHSType->isObjCObjectPointerType()) { Kind = CK_BitCast; Sema::AssignConvertType result = - checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + checkObjCPointerTypesForAssignment(*this, LHSType, RHSType); if (getLangOptions().ObjCAutoRefCount && result == Compatible && - !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType)) + !CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType)) result = IncompatibleObjCWeakRef; return result; } // int or null -> A* - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToPointer; } // In general, C pointers are not compatible with ObjC object pointers, // with two exceptions: - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { + Kind = CK_CPointerToObjCPointerCast; + // - conversions from 'void*' - if (rhsType->isVoidPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (RHSType->isVoidPointerType()) { return Compatible; } // - conversions to 'Class' from its redefinition type - if (lhsType->isObjCClassType() && - Context.hasSameType(rhsType, Context.ObjCClassRedefinitionType)) { - Kind = CK_BitCast; + if (LHSType->isObjCClassType() && + Context.hasSameType(RHSType, + Context.getObjCClassRedefinitionType())) { return Compatible; } - Kind = CK_AnyPointerToObjCPointerCast; return IncompatiblePointer; } // T^ -> A* - if (rhsType->isBlockPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (RHSType->isBlockPointerType()) { + maybeExtendBlockObject(*this, RHS); + Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -5325,15 +5412,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions from pointers that are not covered by the above. - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { // T* -> _Bool - if (lhsType == Context.BoolTy) { + if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int - if (lhsType->isIntegerType()) { + if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } @@ -5342,15 +5429,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions from Objective-C pointers that are not covered by the above. - if (isa<ObjCObjectPointerType>(rhsType)) { + if (isa<ObjCObjectPointerType>(RHSType)) { // T* -> _Bool - if (lhsType == Context.BoolTy) { + if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int - if (lhsType->isIntegerType()) { + if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } @@ -5359,8 +5446,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // struct A -> struct B - if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) { - if (Context.typesAreCompatible(lhsType, rhsType)) { + if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) { + if (Context.typesAreCompatible(LHSType, RHSType)) { Kind = CK_NoOp; return Compatible; } @@ -5371,8 +5458,9 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, /// \brief Constructs a transparent union from an expression that is /// used to initialize the transparent union. -static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult, - QualType UnionType, FieldDecl *Field) { +static void ConstructTransparentUnion(Sema &S, ASTContext &C, + ExprResult &EResult, QualType UnionType, + FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. Expr *E = EResult.take(); @@ -5391,8 +5479,9 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResul } Sema::AssignConvertType -Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rExpr) { - QualType FromType = rExpr.get()->getType(); +Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, + ExprResult &RHS) { + QualType RHSType = RHS.get()->getType(); // If the ArgType is a Union type, we want to handle a potential // transparent_union GCC extension. @@ -5411,25 +5500,26 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx // If the transparent union contains a pointer type, we allow: // 1) void pointer // 2) null pointer constant - if (FromType->isPointerType()) - if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_BitCast); + if (RHSType->isPointerType()) + if (RHSType->castAs<PointerType>()->getPointeeType()->isVoidType()) { + RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast); InitField = *it; break; } - if (rExpr.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_NullToPointer); + if (RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + RHS = ImpCastExprToType(RHS.take(), it->getType(), + CK_NullToPointer); InitField = *it; break; } } CastKind Kind = CK_Invalid; - if (CheckAssignmentConstraints(it->getType(), rExpr, Kind) + if (CheckAssignmentConstraints(it->getType(), RHS, Kind) == Compatible) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), Kind); + RHS = ImpCastExprToType(RHS.take(), it->getType(), Kind); InitField = *it; break; } @@ -5438,42 +5528,46 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx if (!InitField) return Incompatible; - ConstructTransparentUnion(*this, Context, rExpr, ArgType, InitField); + ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField); return Compatible; } Sema::AssignConvertType -Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { +Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, + bool Diagnose) { if (getLangOptions().CPlusPlus) { - if (!lhsType->isRecordType()) { + if (!LHSType->isRecordType() && !LHSType->isAtomicType()) { // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. - ExprResult Res = PerformImplicitConversion(rExpr.get(), - lhsType.getUnqualifiedType(), - AA_Assigning); + ExprResult Res = PerformImplicitConversion(RHS.get(), + LHSType.getUnqualifiedType(), + AA_Assigning, Diagnose); if (Res.isInvalid()) return Incompatible; Sema::AssignConvertType result = Compatible; if (getLangOptions().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType())) + !CheckObjCARCUnavailableWeakConversion(LHSType, + RHS.get()->getType())) result = IncompatibleObjCWeakRef; - rExpr = move(Res); + RHS = move(Res); return result; } // FIXME: Currently, we fall through and treat C++ classes like C // structures. - } + // FIXME: We also fall through for atomics; not sure what should + // happen there, though. + } // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. - if ((lhsType->isPointerType() || - lhsType->isObjCObjectPointerType() || - lhsType->isBlockPointerType()) - && rExpr.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - rExpr = ImpCastExprToType(rExpr.take(), lhsType, CK_NullToPointer); + if ((LHSType->isPointerType() || + LHSType->isObjCObjectPointerType() || + LHSType->isBlockPointerType()) + && RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer); return Compatible; } @@ -5483,15 +5577,15 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { // expressions that suppress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. - if (!lhsType->isReferenceType()) { - rExpr = DefaultFunctionArrayLvalueConversion(rExpr.take()); - if (rExpr.isInvalid()) + if (!LHSType->isReferenceType()) { + RHS = DefaultFunctionArrayLvalueConversion(RHS.take()); + if (RHS.isInvalid()) return Incompatible; } CastKind Kind = CK_Invalid; Sema::AssignConvertType result = - CheckAssignmentConstraints(lhsType, rExpr, Kind); + CheckAssignmentConstraints(LHSType, RHS, Kind); // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. @@ -5499,150 +5593,202 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { // so that we can use references in built-in functions even in C. // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. - if (result != Incompatible && rExpr.get()->getType() != lhsType) - rExpr = ImpCastExprToType(rExpr.take(), lhsType.getNonLValueExprType(Context), Kind); + if (result != Incompatible && RHS.get()->getType() != LHSType) + RHS = ImpCastExprToType(RHS.take(), + LHSType.getNonLValueExprType(Context), Kind); return result; } -QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { +QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { Diag(Loc, diag::err_typecheck_invalid_operands) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } -QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex, - SourceLocation Loc, bool isCompAssign) { +QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. - QualType lhsType = - Context.getCanonicalType(lex.get()->getType()).getUnqualifiedType(); - QualType rhsType = - Context.getCanonicalType(rex.get()->getType()).getUnqualifiedType(); + QualType LHSType = + Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); + QualType RHSType = + Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); // If the vector types are identical, return. - if (lhsType == rhsType) - return lhsType; + if (LHSType == RHSType) + return LHSType; // Handle the case of equivalent AltiVec and GCC vector types - if (lhsType->isVectorType() && rhsType->isVectorType() && - Context.areCompatibleVectorTypes(lhsType, rhsType)) { - if (lhsType->isExtVectorType()) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; + if (LHSType->isVectorType() && RHSType->isVectorType() && + Context.areCompatibleVectorTypes(LHSType, RHSType)) { + if (LHSType->isExtVectorType()) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + return LHSType; } - if (!isCompAssign) - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); - return rhsType; + if (!IsCompAssign) + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); + return RHSType; } if (getLangOptions().LaxVectorConversions && - Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) { + Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType)) { // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a // bitcast; no bits are changed but the result type is different. // FIXME: Should we really be allowing this? - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + return LHSType; } // Canonicalize the ExtVector to the LHS, remember if we swapped so we can // swap back (so that we don't reverse the inputs to a subtract, for instance. bool swapped = false; - if (rhsType->isExtVectorType() && !isCompAssign) { + if (RHSType->isExtVectorType() && !IsCompAssign) { swapped = true; - std::swap(rex, lex); - std::swap(rhsType, lhsType); + std::swap(RHS, LHS); + std::swap(RHSType, LHSType); } // Handle the case of an ext vector and scalar. - if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) { + if (const ExtVectorType *LV = LHSType->getAs<ExtVectorType>()) { QualType EltTy = LV->getElementType(); - if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) { - int order = Context.getIntegerTypeOrder(EltTy, rhsType); + if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) { + int order = Context.getIntegerTypeOrder(EltTy, RHSType); if (order > 0) - rex = ImpCastExprToType(rex.take(), EltTy, CK_IntegralCast); + RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast); if (order >= 0) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); - if (swapped) std::swap(rex, lex); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat); + if (swapped) std::swap(RHS, LHS); + return LHSType; } } - if (EltTy->isRealFloatingType() && rhsType->isScalarType() && - rhsType->isRealFloatingType()) { - int order = Context.getFloatingTypeOrder(EltTy, rhsType); + if (EltTy->isRealFloatingType() && RHSType->isScalarType() && + RHSType->isRealFloatingType()) { + int order = Context.getFloatingTypeOrder(EltTy, RHSType); if (order > 0) - rex = ImpCastExprToType(rex.take(), EltTy, CK_FloatingCast); + RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast); if (order >= 0) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); - if (swapped) std::swap(rex, lex); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat); + if (swapped) std::swap(RHS, LHS); + return LHSType; } } } // Vectors of different size or scalar and non-ext-vector are errors. - if (swapped) std::swap(rex, lex); + if (swapped) std::swap(RHS, LHS); Diag(Loc, diag::err_typecheck_vector_not_convertable) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } -QualType Sema::CheckMultiplyDivideOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); +// checkArithmeticNull - Detect when a NULL constant is used improperly in an +// expression. These are mainly cases where the null pointer is used as an +// integer instead of a pointer. +static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompare) { + // The canonical way to check for a GNU null is with isNullPointerConstant, + // but we use a bit of a hack here for speed; this is a relatively + // hot path, and isNullPointerConstant is slow. + bool LHSNull = isa<GNUNullExpr>(LHS.get()->IgnoreParenImpCasts()); + bool RHSNull = isa<GNUNullExpr>(RHS.get()->IgnoreParenImpCasts()); + + QualType NonNullType = LHSNull ? RHS.get()->getType() : LHS.get()->getType(); + + // Avoid analyzing cases where the result will either be invalid (and + // diagnosed as such) or entirely valid and not something to warn about. + if ((!LHSNull && !RHSNull) || NonNullType->isBlockPointerType() || + NonNullType->isMemberPointerType() || NonNullType->isFunctionType()) + return; + + // Comparison operations would not make sense with a null pointer no matter + // what the other expression is. + if (!IsCompare) { + S.Diag(Loc, diag::warn_null_in_arithmetic_operation) + << (LHSNull ? LHS.get()->getSourceRange() : SourceRange()) + << (RHSNull ? RHS.get()->getSourceRange() : SourceRange()); + return; + } + + // The rest of the operations only make sense with a null pointer + // if the other expression is a pointer. + if (LHSNull == RHSNull || NonNullType->isAnyPointerType() || + NonNullType->canDecayToPointerType()) + return; + + S.Diag(Loc, diag::warn_null_in_comparison_operation) + << LHSNull /* LHS is NULL */ << NonNullType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign, bool IsDiv) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isArithmeticType() || - !rex.get()->getType()->isArithmeticType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isArithmeticType() || + !RHS.get()->getType()->isArithmeticType()) + return InvalidOperands(Loc, LHS, RHS); // Check for division by zero. - if (isDiv && - rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_division_by_zero) - << rex.get()->getSourceRange()); + if (IsDiv && + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_division_by_zero) + << RHS.get()->getSourceRange()); return compType; } QualType Sema::CheckRemainderOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - if (lex.get()->getType()->hasIntegerRepresentation() && - rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); - return InvalidOperands(Loc, lex, rex); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); + return InvalidOperands(Loc, LHS, RHS); } - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isIntegerType() || !rex.get()->getType()->isIntegerType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isIntegerType() || + !RHS.get()->getType()->isIntegerType()) + return InvalidOperands(Loc, LHS, RHS); // Check for remainder by zero. - if (rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_remainder_by_zero) - << rex.get()->getSourceRange()); + if (RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_remainder_by_zero) + << RHS.get()->getSourceRange()); return compType; } /// \brief Diagnose invalid arithmetic on two void pointers. static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, - Expr *LHS, Expr *RHS) { + Expr *LHSExpr, Expr *RHSExpr) { S.Diag(Loc, S.getLangOptions().CPlusPlus ? diag::err_typecheck_pointer_arith_void_type : diag::ext_gnu_void_ptr) - << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange(); + << 1 /* two pointers */ << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); } /// \brief Diagnose invalid arithmetic on a void pointer. @@ -5682,6 +5828,24 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, << Pointer->getSourceRange(); } +/// \brief Emit error if Operand is incomplete pointer type +/// +/// \returns True if pointer has incomplete type +static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, + Expr *Operand) { + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return true; + } + return false; +} + /// \brief Check the validity of an arithmetic pointer operand. /// /// If the operand has pointer type, this code will check for pointer types @@ -5704,16 +5868,7 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, return !S.getLangOptions().CPlusPlus; } - if ((Operand->getType()->isPointerType() && - !Operand->getType()->isDependentType()) || - Operand->getType()->isObjCObjectPointerType()) { - QualType PointeeTy = Operand->getType()->getPointeeType(); - if (S.RequireCompleteType( - Loc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PointeeTy << Operand->getSourceRange())) - return false; - } + if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false; return true; } @@ -5728,22 +5883,22 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, /// /// \returns True when the operand is valid to use (even if as an extension). static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, - Expr *LHS, Expr *RHS) { - bool isLHSPointer = LHS->getType()->isAnyPointerType(); - bool isRHSPointer = RHS->getType()->isAnyPointerType(); + Expr *LHSExpr, Expr *RHSExpr) { + bool isLHSPointer = LHSExpr->getType()->isAnyPointerType(); + bool isRHSPointer = RHSExpr->getType()->isAnyPointerType(); if (!isLHSPointer && !isRHSPointer) return true; QualType LHSPointeeTy, RHSPointeeTy; - if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType(); - if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType(); + if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType(); + if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // Check for arithmetic on pointers to incomplete types. bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); if (isLHSVoidPtr || isRHSVoidPtr) { - if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS); - else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS); - else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS); + if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHSExpr); + else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr); + else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOptions().CPlusPlus; } @@ -5751,160 +5906,179 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType(); bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType(); if (isLHSFuncPtr || isRHSFuncPtr) { - if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS); - else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS); - else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS); + if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHSExpr); + else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, + RHSExpr); + else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOptions().CPlusPlus; } - Expr *Operands[] = { LHS, RHS }; - for (unsigned i = 0; i < 2; ++i) { - Expr *Operand = Operands[i]; - if ((Operand->getType()->isPointerType() && - !Operand->getType()->isDependentType()) || - Operand->getType()->isObjCObjectPointerType()) { - QualType PointeeTy = Operand->getType()->getPointeeType(); - if (S.RequireCompleteType( - Loc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PointeeTy << Operand->getSourceRange())) - return false; - } - } + if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false; + if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false; + return true; } +/// \brief Check bad cases where we step over interface counts. +static bool checkArithmethicPointerOnNonFragileABI(Sema &S, + SourceLocation OpLoc, + Expr *Op) { + assert(Op->getType()->isAnyPointerType()); + QualType PointeeTy = Op->getType()->getPointeeType(); + if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI) + return true; + + S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) + << PointeeTy << Op->getSourceRange(); + return false; +} + +/// \brief Emit error when two pointers are incompatible. +static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc, + Expr *LHSExpr, Expr *RHSExpr) { + assert(LHSExpr->getType()->isAnyPointerType()); + assert(RHSExpr->getType()->isAnyPointerType()); + S.Diag(Loc, diag::err_typecheck_sub_ptr_compatible) + << LHSExpr->getType() << RHSExpr->getType() << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); +} + QualType Sema::CheckAdditionOperands( // C99 6.5.6 - ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } - QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // handle the common case first (both operands are arithmetic). - if (lex.get()->getType()->isArithmeticType() && - rex.get()->getType()->isArithmeticType()) { + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Put any potential pointer into PExp - Expr* PExp = lex.get(), *IExp = rex.get(); + Expr* PExp = LHS.get(), *IExp = RHS.get(); if (IExp->getType()->isAnyPointerType()) std::swap(PExp, IExp); - if (PExp->getType()->isAnyPointerType()) { - if (IExp->getType()->isIntegerType()) { - if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) - return QualType(); + if (!PExp->getType()->isAnyPointerType()) + return InvalidOperands(Loc, LHS, RHS); - QualType PointeeTy = PExp->getType()->getPointeeType(); + if (!IExp->getType()->isIntegerType()) + return InvalidOperands(Loc, LHS, RHS); - // Diagnose bad cases where we step over interface counts. - if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(Loc, diag::err_arithmetic_nonfragile_interface) - << PointeeTy << PExp->getSourceRange(); - return QualType(); - } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) + return QualType(); - if (CompLHSTy) { - QualType LHSTy = Context.isPromotableBitField(lex.get()); - if (LHSTy.isNull()) { - LHSTy = lex.get()->getType(); - if (LHSTy->isPromotableIntegerType()) - LHSTy = Context.getPromotedIntegerType(LHSTy); - } - *CompLHSTy = LHSTy; - } - return PExp->getType(); + // Diagnose bad cases where we step over interface counts. + if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp)) + return QualType(); + + // Check array bounds for pointer arithemtic + CheckArrayAccess(PExp, IExp); + + if (CompLHSTy) { + QualType LHSTy = Context.isPromotableBitField(LHS.get()); + if (LHSTy.isNull()) { + LHSTy = LHS.get()->getType(); + if (LHSTy->isPromotableIntegerType()) + LHSTy = Context.getPromotedIntegerType(LHSTy); } + *CompLHSTy = LHSTy; } - return InvalidOperands(Loc, lex, rex); + return PExp->getType(); } // C99 6.5.6 -QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, - SourceLocation Loc, QualType* CompLHSTy) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); +QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + QualType* CompLHSTy) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } - QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // Enforce type constraints: C99 6.5.6p3. // Handle the common case first (both operands are arithmetic). - if (lex.get()->getType()->isArithmeticType() && - rex.get()->getType()->isArithmeticType()) { + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Either ptr - int or ptr - ptr. - if (lex.get()->getType()->isAnyPointerType()) { - QualType lpointee = lex.get()->getType()->getPointeeType(); + if (LHS.get()->getType()->isAnyPointerType()) { + QualType lpointee = LHS.get()->getType()->getPointeeType(); // Diagnose bad cases where we step over interface counts. - if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(Loc, diag::err_arithmetic_nonfragile_interface) - << lpointee << lex.get()->getSourceRange(); + if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get())) return QualType(); - } // The result type of a pointer-int computation is the pointer type. - if (rex.get()->getType()->isIntegerType()) { - if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get())) + if (RHS.get()->getType()->isIntegerType()) { + if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get())) return QualType(); - if (CompLHSTy) *CompLHSTy = lex.get()->getType(); - return lex.get()->getType(); + Expr *IExpr = RHS.get()->IgnoreParenCasts(); + UnaryOperator negRex(IExpr, UO_Minus, IExpr->getType(), VK_RValue, + OK_Ordinary, IExpr->getExprLoc()); + // Check array bounds for pointer arithemtic + CheckArrayAccess(LHS.get()->IgnoreParenCasts(), &negRex); + + if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); + return LHS.get()->getType(); } // Handle pointer-pointer subtractions. - if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) { + if (const PointerType *RHSPTy + = RHS.get()->getType()->getAs<PointerType>()) { QualType rpointee = RHSPTy->getPointeeType(); if (getLangOptions().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { - Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); + diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); } } else { // Pointee types must be compatible C99 6.5.6p3 if (!Context.typesAreCompatible( Context.getCanonicalType(lpointee).getUnqualifiedType(), Context.getCanonicalType(rpointee).getUnqualifiedType())) { - Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); return QualType(); } } if (!checkArithmeticBinOpPointerOperands(*this, Loc, - lex.get(), rex.get())) + LHS.get(), RHS.get())) return QualType(); - if (CompLHSTy) *CompLHSTy = lex.get()->getType(); + if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); return Context.getPointerDiffType(); } } - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } static bool isScopedEnumerationType(QualType T) { @@ -5913,26 +6087,27 @@ static bool isScopedEnumerationType(QualType T) { return false; } -static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, +static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, - QualType LHSTy) { + QualType LHSType) { llvm::APSInt Right; // Check right/shifter operand - if (rex.get()->isValueDependent() || !rex.get()->isIntegerConstantExpr(Right, S.Context)) + if (RHS.get()->isValueDependent() || + !RHS.get()->isIntegerConstantExpr(Right, S.Context)) return; if (Right.isNegative()) { - S.DiagRuntimeBehavior(Loc, rex.get(), + S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_negative) - << rex.get()->getSourceRange()); + << RHS.get()->getSourceRange()); return; } llvm::APInt LeftBits(Right.getBitWidth(), - S.Context.getTypeSize(lex.get()->getType())); + S.Context.getTypeSize(LHS.get()->getType())); if (Right.uge(LeftBits)) { - S.DiagRuntimeBehavior(Loc, rex.get(), + S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_gt_typewidth) - << rex.get()->getSourceRange()); + << RHS.get()->getSourceRange()); return; } if (Opc != BO_Shl) @@ -5943,8 +6118,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, // integers have defined behavior modulo one more than the maximum value // representable in the result type, so never warn for those. llvm::APSInt Left; - if (lex.get()->isValueDependent() || !lex.get()->isIntegerConstantExpr(Left, S.Context) || - LHSTy->hasUnsignedIntegerRepresentation()) + if (LHS.get()->isValueDependent() || + !LHS.get()->isIntegerConstantExpr(Left, S.Context) || + LHSType->hasUnsignedIntegerRepresentation()) return; llvm::APInt ResultBits = static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); @@ -5964,57 +6140,62 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, // turned off separately if needed. if (LeftBits == ResultBits - 1) { S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) - << HexResult.str() << LHSTy - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << HexResult.str() << LHSType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << HexResult.str() << Result.getMinSignedBits() << LHSTy - << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << HexResult.str() << Result.getMinSignedBits() << LHSType + << Left.getBitWidth() << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } // C99 6.5.7 -QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, - unsigned Opc, bool isCompAssign) { +QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, unsigned Opc, + bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex.get()->getType()->hasIntegerRepresentation() || - !rex.get()->getType()->hasIntegerRepresentation()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->hasIntegerRepresentation() || + !RHS.get()->getType()->hasIntegerRepresentation()) + return InvalidOperands(Loc, LHS, RHS); // C++0x: Don't allow scoped enums. FIXME: Use something better than // hasIntegerRepresentation() above instead of this. - if (isScopedEnumerationType(lex.get()->getType()) || - isScopedEnumerationType(rex.get()->getType())) { - return InvalidOperands(Loc, lex, rex); + if (isScopedEnumerationType(LHS.get()->getType()) || + isScopedEnumerationType(RHS.get()->getType())) { + return InvalidOperands(Loc, LHS, RHS); } // Vector shifts promote their scalar inputs to vector type. - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 // For the LHS, do usual unary conversions, but then reset them away // if this is a compound assignment. - ExprResult old_lex = lex; - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + ExprResult OldLHS = LHS; + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - QualType LHSTy = lex.get()->getType(); - if (isCompAssign) lex = old_lex; + QualType LHSType = LHS.get()->getType(); + if (IsCompAssign) LHS = OldLHS; // The RHS is simpler. - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); // Sanity-check shift operands - DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy); + DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); // "The type of the result is that of the promoted left operand." - return LHSTy; + return LHSType; } static bool IsWithinTemplateSpecialization(Decl *D) { @@ -6027,42 +6208,125 @@ static bool IsWithinTemplateSpecialization(Decl *D) { return false; } +/// If two different enums are compared, raise a warning. +static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { + QualType LHSStrippedType = LHS.get()->IgnoreParenImpCasts()->getType(); + QualType RHSStrippedType = RHS.get()->IgnoreParenImpCasts()->getType(); + + const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>(); + if (!LHSEnumType) + return; + const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>(); + if (!RHSEnumType) + return; + + // Ignore anonymous enums. + if (!LHSEnumType->getDecl()->getIdentifier()) + return; + if (!RHSEnumType->getDecl()->getIdentifier()) + return; + + if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) + return; + + S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) + << LHSStrippedType << RHSStrippedType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +/// \brief Diagnose bad pointer comparisons. +static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, + ExprResult &LHS, ExprResult &RHS, + bool IsError) { + S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_distinct_pointers + : diag::ext_typecheck_comparison_of_distinct_pointers) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +/// \brief Returns false if the pointers are converted to a composite type, +/// true otherwise. +static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, + ExprResult &LHS, ExprResult &RHS) { + // C++ [expr.rel]p2: + // [...] Pointer conversions (4.10) and qualification + // conversions (4.4) are performed on pointer operands (or on + // a pointer operand and a null pointer constant) to bring + // them to their composite pointer type. [...] + // + // C++ [expr.eq]p1 uses the same notion for (in)equality + // comparisons of pointers. + + // C++ [expr.eq]p2: + // In addition, pointers to members can be compared, or a pointer to + // member and a null pointer constant. Pointer to member conversions + // (4.11) and qualification conversions (4.4) are performed to bring + // them to a common type. If one operand is a null pointer constant, + // the common type is the type of the other operand. Otherwise, the + // common type is a pointer to member type similar (4.4) to the type + // of one of the operands, with a cv-qualification signature (4.4) + // that is the union of the cv-qualification signatures of the operand + // types. + + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); + assert((LHSType->isPointerType() && RHSType->isPointerType()) || + (LHSType->isMemberPointerType() && RHSType->isMemberPointerType())); + + bool NonStandardCompositeType = false; + bool *BoolPtr = S.isSFINAEContext() ? 0 : &NonStandardCompositeType; + QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr); + if (T.isNull()) { + diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); + return true; + } + + if (NonStandardCompositeType) + S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << LHSType << RHSType << T << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + + LHS = S.ImpCastExprToType(LHS.take(), T, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), T, CK_BitCast); + return false; +} + +static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc, + ExprResult &LHS, + ExprResult &RHS, + bool IsError) { + S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_fptr_to_void + : diag::ext_typecheck_comparison_of_fptr_to_void) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + // C99 6.5.8, C++ [expr.rel] -QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, - unsigned OpaqueOpc, bool isRelational) { +QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, unsigned OpaqueOpc, + bool IsRelational) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true); + BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc; // Handle vector comparisons separately. - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorCompareOperands(lex, rex, Loc, isRelational); + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational); - QualType lType = lex.get()->getType(); - QualType rType = rex.get()->getType(); - - Expr *LHSStripped = lex.get()->IgnoreParenImpCasts(); - Expr *RHSStripped = rex.get()->IgnoreParenImpCasts(); - QualType LHSStrippedType = LHSStripped->getType(); - QualType RHSStrippedType = RHSStripped->getType(); + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); - + Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts(); + Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts(); - // Two different enums will raise a warning when compared. - if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) { - if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) { - if (LHSEnumType->getDecl()->getIdentifier() && - RHSEnumType->getDecl()->getIdentifier() && - !Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { - Diag(Loc, diag::warn_comparison_of_mixed_enum_types) - << LHSStrippedType << RHSStrippedType - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - } - } + checkEnumComparison(*this, Loc, LHS, RHS); - if (!lType->hasFloatingRepresentation() && - !(lType->isBlockPointerType() && isRelational) && - !lex.get()->getLocStart().isMacroID() && - !rex.get()->getLocStart().isMacroID()) { + if (!LHSType->hasFloatingRepresentation() && + !(LHSType->isBlockPointerType() && IsRelational) && + !LHS.get()->getLocStart().isMacroID() && + !RHS.get()->getLocStart().isMacroID()) { // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. @@ -6082,7 +6346,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca << (Opc == BO_EQ || Opc == BO_LE || Opc == BO_GE)); - } else if (lType->isArrayType() && rType->isArrayType() && + } else if (LHSType->isArrayType() && RHSType->isArrayType() && !DRL->getDecl()->getType()->isReferenceType() && !DRR->getDecl()->getType()->isReferenceType()) { // what is it always going to eval to? @@ -6118,13 +6382,13 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && !RHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = lex.get(); + literalString = LHS.get(); literalStringStripped = LHSStripped; } else if ((isa<StringLiteral>(RHSStripped) || isa<ObjCEncodeExpr>(RHSStripped)) && !LHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = rex.get(); + literalString = RHS.get(); literalStringStripped = RHSStripped; } @@ -6137,7 +6401,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca case BO_GE: resultComparison = ") >= 0"; break; case BO_EQ: resultComparison = ") == 0"; break; case BO_NE: resultComparison = ") != 0"; break; - default: assert(false && "Invalid comparison operator"); + default: llvm_unreachable("Invalid comparison operator"); } DiagRuntimeBehavior(Loc, 0, @@ -6148,56 +6412,57 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca } // C99 6.5.8p3 / C99 6.5.9p4 - if (lex.get()->getType()->isArithmeticType() && rex.get()->getType()->isArithmeticType()) { - UsualArithmeticConversions(lex, rex); - if (lex.isInvalid() || rex.isInvalid()) + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { + UsualArithmeticConversions(LHS, RHS); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); } else { - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); } - lType = lex.get()->getType(); - rType = rex.get()->getType(); + LHSType = LHS.get()->getType(); + RHSType = RHS.get()->getType(); // The result of comparisons is 'bool' in C++, 'int' in C. QualType ResultTy = Context.getLogicalOperationType(); - if (isRelational) { - if (lType->isRealType() && rType->isRealType()) + if (IsRelational) { + if (LHSType->isRealType() && RHSType->isRealType()) return ResultTy; } else { // Check for comparisons of floating point operands using != and ==. - if (lType->hasFloatingRepresentation()) - CheckFloatComparison(Loc, lex.get(), rex.get()); + if (LHSType->hasFloatingRepresentation()) + CheckFloatComparison(Loc, LHS.get(), RHS.get()); - if (lType->isArithmeticType() && rType->isArithmeticType()) + if (LHSType->isArithmeticType() && RHSType->isArithmeticType()) return ResultTy; } - bool LHSIsNull = lex.get()->isNullPointerConstant(Context, + bool LHSIsNull = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - bool RHSIsNull = rex.get()->isNullPointerConstant(Context, + bool RHSIsNull = RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); // All of the following pointer-related warnings are GCC extensions, except // when handling null pointer constants. - if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 + if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 QualType LCanPointeeTy = - Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType()); + LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); QualType RCanPointeeTy = - Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType()); + RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); if (getLangOptions().CPlusPlus) { if (LCanPointeeTy == RCanPointeeTy) return ResultTy; - if (!isRelational && + if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { // Valid unless comparison between non-null pointer and function pointer // This is a gcc extension compatibility comparison. @@ -6205,214 +6470,178 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // conformance with the C++ standard. if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) && !LHSIsNull && !RHSIsNull) { - Diag(Loc, - isSFINAEContext()? - diag::err_typecheck_comparison_of_fptr_to_void - : diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnoseFunctionPointerToVoidComparison( + *this, Loc, LHS, RHS, /*isError*/ isSFINAEContext()); if (isSFINAEContext()) return QualType(); - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } } - // C++ [expr.rel]p2: - // [...] Pointer conversions (4.10) and qualification - // conversions (4.4) are performed on pointer operands (or on - // a pointer operand and a null pointer constant) to bring - // them to their composite pointer type. [...] - // - // C++ [expr.eq]p1 uses the same notion for (in)equality - // comparisons of pointers. - bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(Loc, lex, rex, - isSFINAEContext()? 0 : &NonStandardCompositeType); - if (T.isNull()) { - Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); - } else if (NonStandardCompositeType) { - Diag(Loc, - diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - - lex = ImpCastExprToType(lex.take(), T, CK_BitCast); - rex = ImpCastExprToType(rex.take(), T, CK_BitCast); - return ResultTy; + else + return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), RCanPointeeTy.getUnqualifiedType())) { // Valid unless a relational comparison of function pointers - if (isRelational && LCanPointeeTy->isFunctionType()) { + if (IsRelational && LCanPointeeTy->isFunctionType()) { Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } - } else if (!isRelational && + } else if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { // Valid unless comparison between non-null pointer and function pointer if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) - && !LHSIsNull && !RHSIsNull) { - Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } + && !LHSIsNull && !RHSIsNull) + diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS, + /*isError*/false); } else { // Invalid - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } if (LCanPointeeTy != RCanPointeeTy) { if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); } return ResultTy; } if (getLangOptions().CPlusPlus) { // Comparison of nullptr_t with itself. - if (lType->isNullPtrType() && rType->isNullPtrType()) + if (LHSType->isNullPtrType() && RHSType->isNullPtrType()) return ResultTy; // Comparison of pointers with null pointer constants and equality // comparisons of member pointers to null pointer constants. if (RHSIsNull && - ((lType->isAnyPointerType() || lType->isNullPtrType()) || - (!isRelational && - (lType->isMemberPointerType() || lType->isBlockPointerType())))) { - rex = ImpCastExprToType(rex.take(), lType, - lType->isMemberPointerType() + ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) || + (!IsRelational && + (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) { + RHS = ImpCastExprToType(RHS.take(), LHSType, + LHSType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); return ResultTy; } if (LHSIsNull && - ((rType->isAnyPointerType() || rType->isNullPtrType()) || - (!isRelational && - (rType->isMemberPointerType() || rType->isBlockPointerType())))) { - lex = ImpCastExprToType(lex.take(), rType, - rType->isMemberPointerType() + ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) || + (!IsRelational && + (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) { + LHS = ImpCastExprToType(LHS.take(), RHSType, + RHSType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); return ResultTy; } // Comparison of member pointers. - if (!isRelational && - lType->isMemberPointerType() && rType->isMemberPointerType()) { - // C++ [expr.eq]p2: - // In addition, pointers to members can be compared, or a pointer to - // member and a null pointer constant. Pointer to member conversions - // (4.11) and qualification conversions (4.4) are performed to bring - // them to a common type. If one operand is a null pointer constant, - // the common type is the type of the other operand. Otherwise, the - // common type is a pointer to member type similar (4.4) to the type - // of one of the operands, with a cv-qualification signature (4.4) - // that is the union of the cv-qualification signatures of the operand - // types. - bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(Loc, lex, rex, - isSFINAEContext()? 0 : &NonStandardCompositeType); - if (T.isNull()) { - Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (!IsRelational && + LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) { + if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); - } else if (NonStandardCompositeType) { - Diag(Loc, - diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - - lex = ImpCastExprToType(lex.take(), T, CK_BitCast); - rex = ImpCastExprToType(rex.take(), T, CK_BitCast); - return ResultTy; + else + return ResultTy; } // Handle scoped enumeration types specifically, since they don't promote // to integers. - if (lex.get()->getType()->isEnumeralType() && - Context.hasSameUnqualifiedType(lex.get()->getType(), rex.get()->getType())) + if (LHS.get()->getType()->isEnumeralType() && + Context.hasSameUnqualifiedType(LHS.get()->getType(), + RHS.get()->getType())) return ResultTy; } // Handle block pointer types. - if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) { - QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType(); - QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType(); + if (!IsRelational && LHSType->isBlockPointerType() && + RHSType->isBlockPointerType()) { + QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType(); + QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType(); if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } // Allow block pointers to be compared with null pointer constants. - if (!isRelational - && ((lType->isBlockPointerType() && rType->isPointerType()) - || (lType->isPointerType() && rType->isBlockPointerType()))) { + if (!IsRelational + && ((LHSType->isBlockPointerType() && RHSType->isPointerType()) + || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { - if (!((rType->isPointerType() && rType->castAs<PointerType>() + if (!((RHSType->isPointerType() && RHSType->castAs<PointerType>() ->getPointeeType()->isVoidType()) - || (lType->isPointerType() && lType->castAs<PointerType>() + || (LHSType->isPointerType() && LHSType->castAs<PointerType>() ->getPointeeType()->isVoidType()))) Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); return ResultTy; } - if (lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType()) { - const PointerType *LPT = lType->getAs<PointerType>(); - const PointerType *RPT = rType->getAs<PointerType>(); + if (LHSType->isObjCObjectPointerType() || + RHSType->isObjCObjectPointerType()) { + const PointerType *LPT = LHSType->getAs<PointerType>(); + const PointerType *RPT = RHSType->getAs<PointerType>(); if (LPT || RPT) { bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false; bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false; if (!LPtrToVoid && !RPtrToVoid && - !Context.typesAreCompatible(lType, rType)) { - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + !Context.typesAreCompatible(LHSType, RHSType)) { + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, + /*isError*/false); } if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RPT ? CK_BitCast :CK_CPointerToObjCPointerCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); return ResultTy; } - if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { - if (!Context.areComparableObjCPointerTypes(lType, rType)) - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (LHSType->isObjCObjectPointerType() && + RHSType->isObjCObjectPointerType()) { + if (!Context.areComparableObjCPointerTypes(LHSType, RHSType)) + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, + /*isError*/false); if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } } - if ((lType->isAnyPointerType() && rType->isIntegerType()) || - (lType->isIntegerType() && rType->isAnyPointerType())) { + if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || + (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { unsigned DiagID = 0; bool isError = false; - if ((LHSIsNull && lType->isIntegerType()) || - (RHSIsNull && rType->isIntegerType())) { - if (isRelational && !getLangOptions().CPlusPlus) + if ((LHSIsNull && LHSType->isIntegerType()) || + (RHSIsNull && RHSType->isIntegerType())) { + if (IsRelational && !getLangOptions().CPlusPlus) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; - } else if (isRelational && !getLangOptions().CPlusPlus) + } else if (IsRelational && !getLangOptions().CPlusPlus) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; else if (getLangOptions().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; @@ -6422,50 +6651,51 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca if (DiagID) { Diag(Loc, DiagID) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); if (isError) return QualType(); } - if (lType->isIntegerType()) - lex = ImpCastExprToType(lex.take(), rType, + if (LHSType->isIntegerType()) + LHS = ImpCastExprToType(LHS.take(), RHSType, LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); else - rex = ImpCastExprToType(rex.take(), lType, + RHS = ImpCastExprToType(RHS.take(), LHSType, RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); return ResultTy; } // Handle block pointers. - if (!isRelational && RHSIsNull - && lType->isBlockPointerType() && rType->isIntegerType()) { - rex = ImpCastExprToType(rex.take(), lType, CK_NullToPointer); + if (!IsRelational && RHSIsNull + && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer); return ResultTy; } - if (!isRelational && LHSIsNull - && lType->isIntegerType() && rType->isBlockPointerType()) { - lex = ImpCastExprToType(lex.take(), rType, CK_NullToPointer); + if (!IsRelational && LHSIsNull + && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_NullToPointer); return ResultTy; } - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } /// CheckVectorCompareOperands - vector comparisons are a clang extension that /// operates on extended vector types. Instead of producing an IntTy result, /// like a scalar comparison, a vector comparison produces a vector of integer /// types. -QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, +QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, - bool isRelational) { + bool IsRelational) { // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false); + QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false); if (vType.isNull()) return vType; - QualType lType = lex.get()->getType(); - QualType rType = rex.get()->getType(); + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C @@ -6475,9 +6705,9 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. - if (!lType->hasFloatingRepresentation()) { - if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex.get()->IgnoreParens())) - if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex.get()->IgnoreParens())) + if (!LHSType->hasFloatingRepresentation()) { + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens())) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) @@ -6487,18 +6717,18 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, } // Check for comparisons of floating point operands using != and ==. - if (!isRelational && lType->hasFloatingRepresentation()) { - assert (rType->hasFloatingRepresentation()); - CheckFloatComparison(Loc, lex.get(), rex.get()); + if (!IsRelational && LHSType->hasFloatingRepresentation()) { + assert (RHSType->hasFloatingRepresentation()); + CheckFloatComparison(Loc, LHS.get(), RHS.get()); } // Return the type for the comparison, which is the same as vector type for // integer vectors, or an integer type of identical size and number of // elements for floating point vectors. - if (lType->hasIntegerRepresentation()) - return lType; + if (LHSType->hasIntegerRepresentation()) + return LHSType; - const VectorType *VTy = lType->getAs<VectorType>(); + const VectorType *VTy = LHSType->getAs<VectorType>(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); @@ -6511,36 +6741,41 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, } inline QualType Sema::CheckBitwiseOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - if (lex.get()->getType()->hasIntegerRepresentation() && - rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } - ExprResult lexResult = Owned(lex), rexResult = Owned(rex); - QualType compType = UsualArithmeticConversions(lexResult, rexResult, isCompAssign); - if (lexResult.isInvalid() || rexResult.isInvalid()) + ExprResult LHSResult = Owned(LHS), RHSResult = Owned(RHS); + QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, + IsCompAssign); + if (LHSResult.isInvalid() || RHSResult.isInvalid()) return QualType(); - lex = lexResult.take(); - rex = rexResult.take(); + LHS = LHSResult.take(); + RHS = RHSResult.take(); - if (lex.get()->getType()->isIntegralOrUnscopedEnumerationType() && - rex.get()->getType()->isIntegralOrUnscopedEnumerationType()) + if (LHS.get()->getType()->isIntegralOrUnscopedEnumerationType() && + RHS.get()->getType()->isIntegralOrUnscopedEnumerationType()) return compType; - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] - ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc) { + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) { // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. - if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() && - rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() && + if (LHS.get()->getType()->isIntegerType() && + !LHS.get()->getType()->isBooleanType() && + RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) { // If the RHS can be constant folded, and if it constant folds to something @@ -6548,27 +6783,43 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // happened to fold to true/false) then warn. // Parens on the RHS are ignored. Expr::EvalResult Result; - if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects) - if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) || + if (RHS.get()->Evaluate(Result, Context) && !Result.HasSideEffects) + if ((getLangOptions().Bool && !RHS.get()->getType()->isBooleanType()) || (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex.get()->getSourceRange() - << (Opc == BO_LAnd ? "&&" : "||") - << (Opc == BO_LAnd ? "&" : "|"); - } + << RHS.get()->getSourceRange() + << (Opc == BO_LAnd ? "&&" : "||"); + // Suggest replacing the logical operator with the bitwise version + Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator) + << (Opc == BO_LAnd ? "&" : "|") + << FixItHint::CreateReplacement(SourceRange( + Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(), + getLangOptions())), + Opc == BO_LAnd ? "&" : "|"); + if (Opc == BO_LAnd) + // Suggest replacing "Foo() && kNonZero" with "Foo()" + Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant) + << FixItHint::CreateRemoval( + SourceRange( + Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(), + 0, getSourceManager(), + getLangOptions()), + RHS.get()->getLocEnd())); + } } if (!Context.getLangOptions().CPlusPlus) { - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isScalarType() || !rex.get()->getType()->isScalarType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isScalarType() || + !RHS.get()->getType()->isScalarType()) + return InvalidOperands(Loc, LHS, RHS); return Context.IntTy; } @@ -6579,15 +6830,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both contextually converted to type bool. - ExprResult lexRes = PerformContextuallyConvertToBool(lex.get()); - if (lexRes.isInvalid()) - return InvalidOperands(Loc, lex, rex); - lex = move(lexRes); + ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get()); + if (LHSRes.isInvalid()) + return InvalidOperands(Loc, LHS, RHS); + LHS = move(LHSRes); - ExprResult rexRes = PerformContextuallyConvertToBool(rex.get()); - if (rexRes.isInvalid()) - return InvalidOperands(Loc, lex, rex); - rex = move(rexRes); + ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get()); + if (RHSRes.isInvalid()) + return InvalidOperands(Loc, LHS, RHS); + RHS = move(RHSRes); // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 @@ -6758,25 +7009,26 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { // C99 6.5.16.1 -QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, +QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType) { // Verify that LHS is a modifiable lvalue, and emit error if not. - if (CheckForModifiableLvalue(LHS, Loc, *this)) + if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) return QualType(); - QualType LHSType = LHS->getType(); - QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; + QualType LHSType = LHSExpr->getType(); + QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : + CompoundType; AssignConvertType ConvTy; if (CompoundType.isNull()) { QualType LHSTy(LHSType); // Simple assignment "x = y". - if (LHS->getObjectKind() == OK_ObjCProperty) { - ExprResult LHSResult = Owned(LHS); + if (LHSExpr->getObjectKind() == OK_ObjCProperty) { + ExprResult LHSResult = Owned(LHSExpr); ConvertPropertyForLValue(LHSResult, RHS, LHSTy); if (LHSResult.isInvalid()) return QualType(); - LHS = LHSResult.take(); + LHSExpr = LHSResult.take(); } ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); if (RHS.isInvalid()) @@ -6806,10 +7058,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, UO->getOpcode() == UO_Minus) && Loc.isFileID() && UO->getOperatorLoc().isFileID() && // Only if the two operators are exactly adjacent. - Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() && + Loc.getLocWithOffset(1) == UO->getOperatorLoc() && // And there is a space or other character before the subexpr of the // unary +/-. We don't want to warn on "x=-1". - Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() && + Loc.getLocWithOffset(2) != UO->getSubExpr()->getLocStart() && UO->getSubExpr()->getLocStart().isFileID()) { Diag(Loc, diag::warn_not_compound_assign) << (UO->getOpcode() == UO_Plus ? "+" : "-") @@ -6819,9 +7071,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, if (ConvTy == Compatible) { if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) - checkRetainCycles(LHS, RHS.get()); + checkRetainCycles(LHSExpr, RHS.get()); else if (getLangOptions().ObjCAutoRefCount) - checkUnsafeExprAssigns(Loc, LHS, RHS.get()); + checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); } } else { // Compound assignment "x += y" @@ -6832,10 +7084,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, RHS.get(), AA_Assigning)) return QualType(); - CheckForNullPointerDereference(*this, LHS); - // Check for trivial buffer overflows. - CheckArrayAccess(LHS->IgnoreParenCasts()); - + CheckForNullPointerDereference(*this, LHSExpr); + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -6872,7 +7122,8 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, if (RHS.isInvalid()) return QualType(); if (!RHS.get()->getType()->isVoidType()) - S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type); + S.RequireCompleteType(Loc, RHS.get()->getType(), + diag::err_incomplete_type); } return RHS.get()->getType(); @@ -6883,7 +7134,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprValueKind &VK, SourceLocation OpLoc, - bool isInc, bool isPrefix) { + bool IsInc, bool IsPrefix) { if (Op->isTypeDependent()) return S.Context.DependentTy; @@ -6892,7 +7143,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) { // Decrement of bool is not allowed. - if (!isInc) { + if (!IsInc) { S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); return QualType(); } @@ -6901,18 +7152,13 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } else if (ResType->isRealType()) { // OK! } else if (ResType->isAnyPointerType()) { - QualType PointeeTy = ResType->getPointeeType(); - // C99 6.5.2.4p2, 6.5.6p2 if (!checkArithmeticOpPointerOperand(S, OpLoc, Op)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { - S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) - << PointeeTy << Op->getSourceRange(); + else if (!checkArithmethicPointerOnNonFragileABI(S, OpLoc, Op)) return QualType(); - } } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. S.Diag(OpLoc, diag::ext_integer_increment_complex) @@ -6921,12 +7167,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, - isInc, isPrefix); + IsInc, IsPrefix); } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) { // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) - << ResType << int(isInc) << Op->getSourceRange(); + << ResType << int(IsInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. @@ -6936,7 +7182,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. - if (isPrefix && S.getLangOptions().CPlusPlus) { + if (IsPrefix && S.getLangOptions().CPlusPlus) { VK = VK_LValue; return ResType; } else { @@ -6973,7 +7219,13 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { << PRE->getBase()->getType(); } } - + else { + // lvalue-ness of an explicit property is determined by + // getter type. + QualType ResT = PRE->getGetterResultType(); + VK = Expr::getValueKindForType(ResT); + } + E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK); @@ -6984,7 +7236,8 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { return Owned(E); } -void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &LHSTy) { +void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, + QualType &LHSTy) { assert(LHS.get()->getValueKind() == VK_LValue && LHS.get()->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); @@ -6996,7 +7249,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & // setter, RHS expression is being passed to the setter argument. So, // type conversion (and comparison) is RHS to setter's argument type. if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { - ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); + ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin(); LHSTy = (*P)->getType(); Consumed = (getLangOptions().ObjCAutoRefCount && (*P)->hasAttr<NSConsumedAttr>()); @@ -7015,7 +7268,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & const ObjCMethodDecl *setter = PropRef->getExplicitProperty()->getSetterMethodDecl(); if (setter) { - ObjCMethodDecl::param_iterator P = setter->param_begin(); + ObjCMethodDecl::param_const_iterator P = setter->param_begin(); LHSTy = (*P)->getType(); Consumed = (*P)->hasAttr<NSConsumedAttr>(); } @@ -7092,6 +7345,23 @@ static ValueDecl *getPrimaryDecl(Expr *E) { } } +namespace { + enum { + AO_Bit_Field = 0, + AO_Vector_Element = 1, + AO_Property_Expansion = 2, + AO_Register_Variable = 3, + AO_No_Error = 4 + }; +} +/// \brief Diagnose invalid operand for address of operations. +/// +/// \param Type The type of operand which cannot have its address taken. +static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, + Expr *E, unsigned Type) { + S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange(); +} + /// CheckAddressOfOperand - The operand of & must be either a function /// designator or an lvalue designating an object. If it is an lvalue, the /// object cannot be declared with storage class register or be a bit field. @@ -7103,8 +7373,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, SourceLocation OpLoc) { if (OrigOp->isTypeDependent()) return S.Context.DependentTy; - if (OrigOp->getType() == S.Context.OverloadTy) + if (OrigOp->getType() == S.Context.OverloadTy) { + if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) { + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + << OrigOp->getSourceRange(); + return QualType(); + } + return S.Context.OverloadTy; + } if (OrigOp->getType() == S.Context.UnknownAnyTy) return S.Context.UnknownAnyTy; if (OrigOp->getType() == S.Context.BoundMemberTy) { @@ -7131,6 +7408,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, } ValueDecl *dcl = getPrimaryDecl(op); Expr::LValueClassification lval = op->ClassifyLValue(S.Context); + unsigned AddressOfError = AO_No_Error; if (lval == Expr::LV_ClassTemporary) { bool sfinae = S.isSFINAEContext(); @@ -7178,19 +7456,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, } } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1 // The operand cannot be a bit-field - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "bit-field" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Bit_Field; } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "vector element" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Vector_Element; } else if (op->getObjectKind() == OK_ObjCProperty) { // cannot take address of a property expression. - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "property expression" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Property_Expansion; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -7199,9 +7471,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, // variable (c++03 7.1.1P3) if (vd->getStorageClass() == SC_Register && !S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "register variable" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Register_Variable; } } else if (isa<FunctionTemplateDecl>(dcl)) { return S.Context.OverloadTy; @@ -7225,8 +7495,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); } } - } else if (!isa<FunctionDecl>(dcl)) - assert(0 && "Unknown/unexpected decl type"); + } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl)) + llvm_unreachable("Unknown/unexpected decl type"); + } + + if (AddressOfError != AO_No_Error) { + diagnoseAddressOfInvalidType(S, OpLoc, op, AddressOfError); + return QualType(); } if (lval == Expr::LV_IncompleteVoidType) { @@ -7297,7 +7572,7 @@ static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode( tok::TokenKind Kind) { BinaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown binop!"); + default: llvm_unreachable("Unknown binop!"); case tok::periodstar: Opc = BO_PtrMemD; break; case tok::arrowstar: Opc = BO_PtrMemI; break; case tok::star: Opc = BO_Mul; break; @@ -7338,7 +7613,7 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( tok::TokenKind Kind) { UnaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown unary op!"); + default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PreInc; break; case tok::minusminus: Opc = UO_PreDec; break; case tok::amp: Opc = UO_AddrOf; break; @@ -7357,35 +7632,35 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. /// This warning is only emitted for builtin assignment operations. It is also /// suppressed in the event of macro expansions. -static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, +static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, SourceLocation OpLoc) { if (!S.ActiveTemplateInstantiations.empty()) return; if (OpLoc.isInvalid() || OpLoc.isMacroID()) return; - lhs = lhs->IgnoreParenImpCasts(); - rhs = rhs->IgnoreParenImpCasts(); - const DeclRefExpr *LeftDeclRef = dyn_cast<DeclRefExpr>(lhs); - const DeclRefExpr *RightDeclRef = dyn_cast<DeclRefExpr>(rhs); - if (!LeftDeclRef || !RightDeclRef || - LeftDeclRef->getLocation().isMacroID() || - RightDeclRef->getLocation().isMacroID()) + LHSExpr = LHSExpr->IgnoreParenImpCasts(); + RHSExpr = RHSExpr->IgnoreParenImpCasts(); + const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); + const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); + if (!LHSDeclRef || !RHSDeclRef || + LHSDeclRef->getLocation().isMacroID() || + RHSDeclRef->getLocation().isMacroID()) return; - const ValueDecl *LeftDecl = - cast<ValueDecl>(LeftDeclRef->getDecl()->getCanonicalDecl()); - const ValueDecl *RightDecl = - cast<ValueDecl>(RightDeclRef->getDecl()->getCanonicalDecl()); - if (LeftDecl != RightDecl) + const ValueDecl *LHSDecl = + cast<ValueDecl>(LHSDeclRef->getDecl()->getCanonicalDecl()); + const ValueDecl *RHSDecl = + cast<ValueDecl>(RHSDeclRef->getDecl()->getCanonicalDecl()); + if (LHSDecl != RHSDecl) return; - if (LeftDecl->getType().isVolatileQualified()) + if (LHSDecl->getType().isVolatileQualified()) return; - if (const ReferenceType *RefTy = LeftDecl->getType()->getAs<ReferenceType>()) + if (const ReferenceType *RefTy = LHSDecl->getType()->getAs<ReferenceType>()) if (RefTy->getPointeeType().isVolatileQualified()) return; S.Diag(OpLoc, diag::warn_self_assignment) - << LeftDeclRef->getType() - << lhs->getSourceRange() << rhs->getSourceRange(); + << LHSDeclRef->getType() + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with @@ -7393,8 +7668,8 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, /// built-in operations; ActOnBinOp handles overloaded operators. ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, - Expr *lhsExpr, Expr *rhsExpr) { - ExprResult lhs = Owned(lhsExpr), rhs = Owned(rhsExpr); + Expr *LHSExpr, Expr *RHSExpr) { + ExprResult LHS = Owned(LHSExpr), RHS = Owned(RHSExpr); QualType ResultTy; // Result type of the binary operator. // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation @@ -7410,172 +7685,131 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // f<int> == 0; // resolve f<int> blindly // void (*p)(int); p = f<int>; // resolve f<int> using target if (Opc != BO_Assign) { - ExprResult resolvedLHS = CheckPlaceholderExpr(lhs.get()); + ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get()); if (!resolvedLHS.isUsable()) return ExprError(); - lhs = move(resolvedLHS); + LHS = move(resolvedLHS); - ExprResult resolvedRHS = CheckPlaceholderExpr(rhs.get()); + ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get()); if (!resolvedRHS.isUsable()) return ExprError(); - rhs = move(resolvedRHS); - } - - // The canonical way to check for a GNU null is with isNullPointerConstant, - // but we use a bit of a hack here for speed; this is a relatively - // hot path, and isNullPointerConstant is slow. - bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts()); - bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts()); - - // Detect when a NULL constant is used improperly in an expression. These - // are mainly cases where the null pointer is used as an integer instead - // of a pointer. - if (LeftNull || RightNull) { - // Avoid analyzing cases where the result will either be invalid (and - // diagnosed as such) or entirely valid and not something to warn about. - QualType LeftType = lhs.get()->getType(); - QualType RightType = rhs.get()->getType(); - if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() && - !LeftType->isFunctionType() && - !RightType->isBlockPointerType() && - !RightType->isMemberPointerType() && - !RightType->isFunctionType()) { - if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || - Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || - Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || - Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || - Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || - Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { - // These are the operations that would not make sense with a null pointer - // no matter what the other expression is. - Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) - << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); - } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || - Opc == BO_EQ || Opc == BO_NE) { - // These are the operations that would not make sense with a null pointer - // if the other expression the other expression is not a pointer. - if (LeftNull != RightNull && - !LeftType->isAnyPointerType() && - !LeftType->canDecayToPointerType() && - !RightType->isAnyPointerType() && - !RightType->canDecayToPointerType()) { - Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() - : rhs.get()->getSourceRange()); - } - } - } + RHS = move(resolvedRHS); } switch (Opc) { case BO_Assign: - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); if (getLangOptions().CPlusPlus && - lhs.get()->getObjectKind() != OK_ObjCProperty) { - VK = lhs.get()->getValueKind(); - OK = lhs.get()->getObjectKind(); + LHS.get()->getObjectKind() != OK_ObjCProperty) { + VK = LHS.get()->getValueKind(); + OK = LHS.get()->getObjectKind(); } if (!ResultTy.isNull()) - DiagnoseSelfAssignment(*this, lhs.get(), rhs.get(), OpLoc); + DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); break; case BO_PtrMemD: case BO_PtrMemI: - ResultTy = CheckPointerToMemberOperands(lhs, rhs, VK, OpLoc, + ResultTy = CheckPointerToMemberOperands(LHS, RHS, VK, OpLoc, Opc == BO_PtrMemI); break; case BO_Mul: case BO_Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, + ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; case BO_Rem: - ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); + ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: - ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc); + ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc); break; case BO_Sub: - ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc); + ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: case BO_Shr: - ResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc); + ResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc); break; case BO_LE: case BO_LT: case BO_GE: case BO_GT: - ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); break; case BO_EQ: case BO_NE: - ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; case BO_And: case BO_Xor: case BO_Or: - ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc); + ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc); break; case BO_LAnd: case BO_LOr: - ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc); + ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: - CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, + CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_RemAssign: - CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: - CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: - CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_ShlAssign: case BO_ShrAssign: - CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true); + CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: - CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_Comma: - ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc); - if (getLangOptions().CPlusPlus && !rhs.isInvalid()) { - VK = rhs.get()->getValueKind(); - OK = rhs.get()->getObjectKind(); + ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc); + if (getLangOptions().CPlusPlus && !RHS.isInvalid()) { + VK = RHS.get()->getValueKind(); + OK = RHS.get()->getObjectKind(); } break; } - if (ResultTy.isNull() || lhs.isInvalid() || rhs.isInvalid()) + if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + + // Check for array bounds violations for both sides of the BinaryOperator + CheckArrayAccess(LHS.get()); + CheckArrayAccess(RHS.get()); + if (CompResultTy.isNull()) - return Owned(new (Context) BinaryOperator(lhs.take(), rhs.take(), Opc, + return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, OpLoc)); - if (getLangOptions().CPlusPlus && lhs.get()->getObjectKind() != OK_ObjCProperty) { + if (getLangOptions().CPlusPlus && LHS.get()->getObjectKind() != + OK_ObjCProperty) { VK = VK_LValue; - OK = lhs.get()->getObjectKind(); + OK = LHS.get()->getObjectKind(); } - return Owned(new (Context) CompoundAssignOperator(lhs.take(), rhs.take(), Opc, + return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc)); } @@ -7585,51 +7819,49 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// comparison operators have higher precedence. The most typical example of /// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, - SourceLocation OpLoc,Expr *lhs,Expr *rhs){ + SourceLocation OpLoc, Expr *LHSExpr, + Expr *RHSExpr) { typedef BinaryOperator BinOp; - BinOp::Opcode lhsopc = static_cast<BinOp::Opcode>(-1), - rhsopc = static_cast<BinOp::Opcode>(-1); - if (BinOp *BO = dyn_cast<BinOp>(lhs)) - lhsopc = BO->getOpcode(); - if (BinOp *BO = dyn_cast<BinOp>(rhs)) - rhsopc = BO->getOpcode(); + BinOp::Opcode LHSopc = static_cast<BinOp::Opcode>(-1), + RHSopc = static_cast<BinOp::Opcode>(-1); + if (BinOp *BO = dyn_cast<BinOp>(LHSExpr)) + LHSopc = BO->getOpcode(); + if (BinOp *BO = dyn_cast<BinOp>(RHSExpr)) + RHSopc = BO->getOpcode(); // Subs are not binary operators. - if (lhsopc == -1 && rhsopc == -1) + if (LHSopc == -1 && RHSopc == -1) return; // Bitwise operations are sometimes used as eager logical ops. // Don't diagnose this. - if ((BinOp::isComparisonOp(lhsopc) || BinOp::isBitwiseOp(lhsopc)) && - (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) + if ((BinOp::isComparisonOp(LHSopc) || BinOp::isBitwiseOp(LHSopc)) && + (BinOp::isComparisonOp(RHSopc) || BinOp::isBitwiseOp(RHSopc))) return; - if (BinOp::isComparisonOp(lhsopc)) { - Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) - << SourceRange(lhs->getLocStart(), OpLoc) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_silence) - << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange()); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_first) - << BinOp::getOpcodeStr(Opc), - SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); - } else if (BinOp::isComparisonOp(rhsopc)) { - Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) - << SourceRange(OpLoc, rhs->getLocEnd()) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_silence) - << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange()); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_first) - << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocStart(), - cast<BinOp>(rhs)->getLHS()->getLocStart())); - } + bool isLeftComp = BinOp::isComparisonOp(LHSopc); + bool isRightComp = BinOp::isComparisonOp(RHSopc); + if (!isLeftComp && !isRightComp) return; + + SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(), + OpLoc) + : SourceRange(OpLoc, RHSExpr->getLocEnd()); + std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc) + : BinOp::getOpcodeStr(RHSopc); + SourceRange ParensRange = isLeftComp ? + SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(), + RHSExpr->getLocEnd()) + : SourceRange(LHSExpr->getLocStart(), + cast<BinOp>(RHSExpr)->getLHS()->getLocStart()); + + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr; + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr, + RHSExpr->getSourceRange()); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), + ParensRange); } /// \brief It accepts a '&' expr that is inside a '|' one. @@ -7676,11 +7908,11 @@ static bool EvaluatesAsFalse(Sema &S, Expr *E) { /// \brief Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, - Expr *OrLHS, Expr *OrRHS) { - if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrLHS)) { + Expr *LHSExpr, Expr *RHSExpr) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "a && b || 0" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, OrRHS)) + if (EvaluatesAsFalse(S, RHSExpr)) return; // If it's "1 && a || b" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getLHS())) @@ -7698,11 +7930,11 @@ static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, /// \brief Look for '&&' in the right hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, - Expr *OrLHS, Expr *OrRHS) { - if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrRHS)) { + Expr *LHSExpr, Expr *RHSExpr) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "0 || a && b" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, OrLHS)) + if (EvaluatesAsFalse(S, LHSExpr)) return; // If it's "a || b && 1" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getRHS())) @@ -7723,52 +7955,54 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, - SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + SourceLocation OpLoc, Expr *LHSExpr, + Expr *RHSExpr){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, LHSExpr, RHSExpr); // Diagnose "arg1 & arg2 | arg3" if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) { - DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs); - DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, LHSExpr); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, RHSExpr); } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) { - DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, lhs, rhs); - DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, lhs, rhs); + DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr); + DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr); } } // Binary Operators. 'Tok' is the token for the operator. ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, - Expr *lhs, Expr *rhs) { + Expr *LHSExpr, Expr *RHSExpr) { BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind); - assert((lhs != 0) && "ActOnBinOp(): missing left expression"); - assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + assert((LHSExpr != 0) && "ActOnBinOp(): missing left expression"); + assert((RHSExpr != 0) && "ActOnBinOp(): missing right expression"); // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" - DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr); - return BuildBinOp(S, TokLoc, Opc, lhs, rhs); + return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr); } ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, - Expr *lhs, Expr *rhs) { + Expr *LHSExpr, Expr *RHSExpr) { if (getLangOptions().CPlusPlus) { bool UseBuiltinOperator; - if (lhs->isTypeDependent() || rhs->isTypeDependent()) { + if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) { UseBuiltinOperator = false; - } else if (Opc == BO_Assign && lhs->getObjectKind() == OK_ObjCProperty) { + } else if (Opc == BO_Assign && + LHSExpr->getObjectKind() == OK_ObjCProperty) { UseBuiltinOperator = true; } else { - UseBuiltinOperator = !lhs->getType()->isOverloadableType() && - !rhs->getType()->isOverloadableType(); + UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() && + !RHSExpr->getType()->isOverloadableType(); } if (!UseBuiltinOperator) { @@ -7780,17 +8014,17 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); if (S && OverOp != OO_None) - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); + LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(), + RHSExpr->getType(), Functions); // Build the (potentially-overloaded, potentially-dependent) // binary operation. - return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); + return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr); } } // Build a built-in binary operation. - return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); + return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, @@ -7876,6 +8110,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Input = DefaultFunctionArrayLvalueConversion(Input.take()); if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); + + // Though we still have to promote half FP to float... + if (resultType->isHalfType()) { + Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take(); + resultType = Context.FloatTy; + } + if (resultType->isDependentType()) break; if (resultType->isScalarType()) { @@ -7917,13 +8158,19 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (resultType.isNull() || Input.isInvalid()) return ExprError(); + // Check for array bounds violations in the operand of the UnaryOperator, + // except for the '*' and '&' operators that have to be handled specially + // by CheckArrayAccess (as there are special cases like &array[arraysize] + // that are explicitly defined as valid by the standard). + if (Opc != UO_AddrOf && Opc != UO_Deref) + CheckArrayAccess(Input.get()); + return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType, VK, OK, OpLoc)); } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperatorKind Opc, - Expr *Input) { + UnaryOperatorKind Opc, Expr *Input) { if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() && UnaryOperator::getOverloadedOperator(Opc) != OO_None) { // Find all of the overloaded operators visible from this @@ -7962,13 +8209,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, /// ns_returns_retained function) and, if so, rebuild it to hoist the /// release out of the full-expression. Otherwise, return null. /// Cannot fail. -static Expr *maybeRebuildARCConsumingStmt(Stmt *s) { +static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) { // Should always be wrapped with one of these. - ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s); + ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement); if (!cleanups) return 0; ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr()); - if (!cast || cast->getCastKind() != CK_ObjCConsumeObject) + if (!cast || cast->getCastKind() != CK_ARCConsumeObject) return 0; // Splice out the cast. This shouldn't modify any interesting @@ -8091,8 +8338,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, bool DidWarnAboutNonPOD = false; QualType CurrentType = ArgTy; typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; - llvm::SmallVector<OffsetOfNode, 4> Comps; - llvm::SmallVector<Expr*, 4> Exprs; + SmallVector<OffsetOfNode, 4> Comps; + SmallVector<Expr*, 4> Exprs; for (unsigned i = 0; i != NumComponents; ++i) { const OffsetOfComponent &OC = CompPtr[i]; if (OC.isBrackets) { @@ -8174,7 +8421,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, // (If the specified member is a bit-field, the behavior is undefined.) // // We diagnose this as an error. - if (MemberDecl->getBitWidth()) { + if (MemberDecl->isBitField()) { Diag(OC.LocEnd, diag::err_offsetof_bitfield) << MemberDecl->getDeclName() << SourceRange(BuiltinLoc, RParenLoc); @@ -8219,13 +8466,13 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, - ParsedType argty, + ParsedType ParsedArgTy, OffsetOfComponent *CompPtr, unsigned NumComponents, - SourceLocation RPLoc) { + SourceLocation RParenLoc) { TypeSourceInfo *ArgTInfo; - QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo); + QualType ArgTy = GetTypeFromParser(ParsedArgTy, &ArgTInfo); if (ArgTy.isNull()) return ExprError(); @@ -8233,7 +8480,7 @@ ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, - RPLoc); + RParenLoc); } @@ -8279,12 +8526,12 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, //===----------------------------------------------------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is started. -void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { +void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); - PushBlockScope(BlockScope, Block); + PushBlockScope(CurScope, Block); CurContext->addDecl(Block); - if (BlockScope) - PushDeclContext(BlockScope, Block); + if (CurScope) + PushDeclContext(CurScope, Block); else CurContext = Block; } @@ -8351,7 +8598,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->ReturnType = RetTy; // Push block parameters from the declarator if we had them. - llvm::SmallVector<ParmVarDecl*, 8> Params; + SmallVector<ParmVarDecl*, 8> Params; if (ExplicitSignature) { for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) { ParmVarDecl *Param = ExplicitSignature.getArg(I); @@ -8378,7 +8625,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // Set the parameters on the block decl. if (!Params.empty()) { - CurBlock->TheDecl->setParams(Params.data(), Params.size()); + CurBlock->TheDecl->setParams(Params); CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(), CurBlock->TheDecl->param_end(), /*CheckParameterNames=*/false); @@ -8500,6 +8747,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, getCurFunction()->setHasBranchProtectedScope(); } + computeNRVO(Body, getCurBlock()); + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result); @@ -8508,11 +8757,11 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, - Expr *expr, ParsedType type, + Expr *E, ParsedType Ty, SourceLocation RPLoc) { TypeSourceInfo *TInfo; - GetTypeFromParser(type, &TInfo); - return BuildVAArgExpr(BuiltinLoc, expr, TInfo, RPLoc); + GetTypeFromParser(Ty, &TInfo); + return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc); } ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, @@ -8559,11 +8808,14 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << TInfo->getTypeLoc().getSourceRange())) return ExprError(); - if (!TInfo->getType().isPODType(Context)) + if (!TInfo->getType().isPODType(Context)) { Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::warn_second_parameter_to_va_arg_not_pod) + TInfo->getType()->isObjCLifetimeType() + ? diag::warn_second_parameter_to_va_arg_ownership_qualified + : diag::warn_second_parameter_to_va_arg_not_pod) << TInfo->getType() << TInfo->getTypeLoc().getSourceRange(); + } // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). @@ -8591,16 +8843,15 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; - unsigned pw = Context.Target.getPointerWidth(0); - if (pw == Context.Target.getIntWidth()) + unsigned pw = Context.getTargetInfo().getPointerWidth(0); + if (pw == Context.getTargetInfo().getIntWidth()) Ty = Context.IntTy; - else if (pw == Context.Target.getLongWidth()) + else if (pw == Context.getTargetInfo().getLongWidth()) Ty = Context.LongTy; - else if (pw == Context.Target.getLongLongWidth()) + else if (pw == Context.getTargetInfo().getLongLongWidth()) Ty = Context.LongLongTy; else { - assert(!"I don't know size of pointer!"); - Ty = Context.IntTy; + llvm_unreachable("I don't know size of pointer!"); } return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); @@ -8625,7 +8876,7 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, // Strip off any parens and casts. StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts()); - if (!SL || SL->isWide()) + if (!SL || !SL->isAscii()) return; Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@"); @@ -8644,21 +8895,31 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, bool isInvalid = false; unsigned DiagKind; FixItHint Hint; + ConversionFixItGenerator ConvHints; + bool MayHaveConvFixit = false; switch (ConvTy) { - default: assert(0 && "Unknown conversion type"); + default: llvm_unreachable("Unknown conversion type"); case Compatible: return false; case PointerToInt: DiagKind = diag::ext_typecheck_convert_pointer_int; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; break; case IntToPointer: DiagKind = diag::ext_typecheck_convert_int_pointer; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; break; case IncompatiblePointer: MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); + if (Hint.isNull() && !CheckInferredResultType) { + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + } + MayHaveConvFixit = true; break; case IncompatiblePointerSign: DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; @@ -8722,6 +8983,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; case Incompatible: DiagKind = diag::err_typecheck_convert_incompatible; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; isInvalid = true; break; } @@ -8746,8 +9009,23 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; } - Diag(Loc, DiagKind) << FirstType << SecondType << Action - << SrcExpr->getSourceRange() << Hint; + PartialDiagnostic FDiag = PDiag(DiagKind); + FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange(); + + // If we can fix the conversion, suggest the FixIts. + assert(ConvHints.isNull() || Hint.isNull()); + if (!ConvHints.isNull()) { + for (llvm::SmallVector<FixItHint, 1>::iterator + HI = ConvHints.Hints.begin(), HE = ConvHints.Hints.end(); + HI != HE; ++HI) + FDiag << *HI; + } else { + FDiag << Hint; + } + if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); } + + Diag(Loc, FDiag); + if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); @@ -8786,7 +9064,7 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ if (EvalResult.Diag && Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) Diag(EvalResult.DiagLoc, EvalResult.Diag); if (Result) @@ -8803,8 +9081,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { ExprNeedsCleanups = false; } -void -Sema::PopExpressionEvaluationContext() { +void Sema::PopExpressionEvaluationContext() { // Pop the current expression evaluation context off the stack. ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); ExprEvalContexts.pop_back(); @@ -8874,10 +9151,10 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (D->isUsed(false)) return; - // Mark a parameter or variable declaration "used", regardless of whether we're in a - // template or not. The reason for this is that unevaluated expressions - // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and - // -Wunused-parameters) + // Mark a parameter or variable declaration "used", regardless of whether + // we're in a template or not. The reason for this is that unevaluated + // expressions (e.g. (void)sizeof()) constitute a use for warning purposes + // (-Wunused-variables and -Wunused-parameters) if (isa<ParmVarDecl>(D) || (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) { D->setUsed(); @@ -8917,15 +9194,19 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) { - if (Constructor->isTrivial()) - return; - if (!Constructor->isUsed(false)) - DefineImplicitDefaultConstructor(Loc, Constructor); - } else if (Constructor->isDefaulted() && - Constructor->isCopyConstructor()) { - if (!Constructor->isUsed(false)) - DefineImplicitCopyConstructor(Loc, Constructor); + if (Constructor->isDefaulted()) { + if (Constructor->isDefaultConstructor()) { + if (Constructor->isTrivial()) + return; + if (!Constructor->isUsed(false)) + DefineImplicitDefaultConstructor(Loc, Constructor); + } else if (Constructor->isCopyConstructor()) { + if (!Constructor->isUsed(false)) + DefineImplicitCopyConstructor(Loc, Constructor); + } else if (Constructor->isMoveConstructor()) { + if (!Constructor->isUsed(false)) + DefineImplicitMoveConstructor(Loc, Constructor); + } } MarkVTableUsed(Loc, Constructor->getParent()); @@ -8937,8 +9218,12 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { - if (!MethodDecl->isUsed(false)) - DefineImplicitCopyAssignment(Loc, MethodDecl); + if (!MethodDecl->isUsed(false)) { + if (MethodDecl->isCopyAssignmentOperator()) + DefineImplicitCopyAssignment(Loc, MethodDecl); + else + DefineImplicitMoveAssignment(Loc, MethodDecl); + } } else if (MethodDecl->isVirtual()) MarkVTableUsed(Loc, MethodDecl->getParent()); } @@ -9147,7 +9432,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. -bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case Unevaluated: @@ -9156,9 +9441,9 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: - if (stmt && getCurFunctionOrMethodDecl()) { + if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. - push_back(sema::PossiblyUnreachableDiag(PD, Loc, stmt)); + push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); } else Diag(Loc, PD); @@ -9203,8 +9488,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { unsigned diagnostic = diag::warn_condition_is_assignment; bool IsOrAssign = false; - if (isa<BinaryOperator>(E)) { - BinaryOperator *Op = cast<BinaryOperator>(E); + if (BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { if (Op->getOpcode() != BO_Assign && Op->getOpcode() != BO_OrAssign) return; @@ -9225,8 +9509,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { } Loc = Op->getOperatorLoc(); - } else if (isa<CXXOperatorCallExpr>(E)) { - CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E); + } else if (CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { if (Op->getOperator() != OO_Equal && Op->getOperator() != OO_PipeEqual) return; @@ -9255,16 +9538,16 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { /// \brief Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. -void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { +void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { // Don't warn if the parens came from a macro. - SourceLocation parenLoc = parenE->getLocStart(); + SourceLocation parenLoc = ParenE->getLocStart(); if (parenLoc.isInvalid() || parenLoc.isMacroID()) return; // Don't warn for dependent expressions. - if (parenE->isTypeDependent()) + if (ParenE->isTypeDependent()) return; - Expr *E = parenE->IgnoreParens(); + Expr *E = ParenE->IgnoreParens(); if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E)) if (opE->getOpcode() == BO_EQ && @@ -9274,8 +9557,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange(); Diag(Loc, diag::note_equality_comparison_silence) - << FixItHint::CreateRemoval(parenE->getSourceRange().getBegin()) - << FixItHint::CreateRemoval(parenE->getSourceRange().getEnd()); + << FixItHint::CreateRemoval(ParenE->getSourceRange().getBegin()) + << FixItHint::CreateRemoval(ParenE->getSourceRange().getEnd()); Diag(Loc, diag::note_equality_comparison_to_assign) << FixItHint::CreateReplacement(Loc, "="); } @@ -9311,11 +9594,11 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { } ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, - Expr *Sub) { - if (!Sub) + Expr *SubExpr) { + if (!SubExpr) return ExprError(); - return CheckBooleanCondition(Sub, Loc); + return CheckBooleanCondition(SubExpr, Loc); } namespace { @@ -9333,76 +9616,76 @@ namespace { return ExprError(); } - ExprResult VisitExpr(Expr *expr) { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call) - << expr->getSourceRange(); + ExprResult VisitExpr(Expr *E) { + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_call) + << E->getSourceRange(); return ExprError(); } /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. - template <class T> ExprResult rebuildSugarExpr(T *expr) { - ExprResult subResult = Visit(expr->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); + template <class T> ExprResult rebuildSugarExpr(T *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - expr->setSubExpr(subExpr); - expr->setType(subExpr->getType()); - expr->setValueKind(subExpr->getValueKind()); - assert(expr->getObjectKind() == OK_Ordinary); - return expr; + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(SubExpr->getType()); + E->setValueKind(SubExpr->getValueKind()); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult VisitParenExpr(ParenExpr *paren) { - return rebuildSugarExpr(paren); + ExprResult VisitParenExpr(ParenExpr *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryExtension(UnaryOperator *op) { - return rebuildSugarExpr(op); + ExprResult VisitUnaryExtension(UnaryOperator *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryAddrOf(UnaryOperator *op) { - ExprResult subResult = Visit(op->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); + ExprResult VisitUnaryAddrOf(UnaryOperator *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - op->setSubExpr(subExpr); - op->setType(S.Context.getPointerType(subExpr->getType())); - assert(op->getValueKind() == VK_RValue); - assert(op->getObjectKind() == OK_Ordinary); - return op; + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(S.Context.getPointerType(SubExpr->getType())); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult resolveDecl(Expr *expr, ValueDecl *decl) { - if (!isa<FunctionDecl>(decl)) return VisitExpr(expr); + ExprResult resolveDecl(Expr *E, ValueDecl *VD) { + if (!isa<FunctionDecl>(VD)) return VisitExpr(E); - expr->setType(decl->getType()); + E->setType(VD->getType()); - assert(expr->getValueKind() == VK_RValue); + assert(E->getValueKind() == VK_RValue); if (S.getLangOptions().CPlusPlus && - !(isa<CXXMethodDecl>(decl) && - cast<CXXMethodDecl>(decl)->isInstance())) - expr->setValueKind(VK_LValue); + !(isa<CXXMethodDecl>(VD) && + cast<CXXMethodDecl>(VD)->isInstance())) + E->setValueKind(VK_LValue); - return expr; + return E; } - ExprResult VisitMemberExpr(MemberExpr *mem) { - return resolveDecl(mem, mem->getMemberDecl()); + ExprResult VisitMemberExpr(MemberExpr *E) { + return resolveDecl(E, E->getMemberDecl()); } - ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { - return resolveDecl(ref, ref->getDecl()); + ExprResult VisitDeclRefExpr(DeclRefExpr *E) { + return resolveDecl(E, E->getDecl()); } }; } /// Given a function expression of unknown-any type, try to rebuild it /// to have a function type. -static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) { - ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn); - if (result.isInvalid()) return ExprError(); - return S.DefaultFunctionArrayConversion(result.take()); +static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *FunctionExpr) { + ExprResult Result = RebuildUnknownAnyFunction(S).Visit(FunctionExpr); + if (Result.isInvalid()) return ExprError(); + return S.DefaultFunctionArrayConversion(Result.take()); } namespace { @@ -9418,80 +9701,80 @@ namespace { /// The current destination type. QualType DestType; - RebuildUnknownAnyExpr(Sema &S, QualType castType) - : S(S), DestType(castType) {} + RebuildUnknownAnyExpr(Sema &S, QualType CastType) + : S(S), DestType(CastType) {} ExprResult VisitStmt(Stmt *S) { llvm_unreachable("unexpected statement!"); return ExprError(); } - ExprResult VisitExpr(Expr *expr) { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr) - << expr->getSourceRange(); + ExprResult VisitExpr(Expr *E) { + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << E->getSourceRange(); return ExprError(); } - ExprResult VisitCallExpr(CallExpr *call); - ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message); + ExprResult VisitCallExpr(CallExpr *E); + ExprResult VisitObjCMessageExpr(ObjCMessageExpr *E); /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. - template <class T> ExprResult rebuildSugarExpr(T *expr) { - ExprResult subResult = Visit(expr->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - expr->setSubExpr(subExpr); - expr->setType(subExpr->getType()); - expr->setValueKind(subExpr->getValueKind()); - assert(expr->getObjectKind() == OK_Ordinary); - return expr; + template <class T> ExprResult rebuildSugarExpr(T *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(SubExpr->getType()); + E->setValueKind(SubExpr->getValueKind()); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult VisitParenExpr(ParenExpr *paren) { - return rebuildSugarExpr(paren); + ExprResult VisitParenExpr(ParenExpr *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryExtension(UnaryOperator *op) { - return rebuildSugarExpr(op); + ExprResult VisitUnaryExtension(UnaryOperator *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryAddrOf(UnaryOperator *op) { - const PointerType *ptr = DestType->getAs<PointerType>(); - if (!ptr) { - S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof) - << op->getSourceRange(); + ExprResult VisitUnaryAddrOf(UnaryOperator *E) { + const PointerType *Ptr = DestType->getAs<PointerType>(); + if (!Ptr) { + S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof) + << E->getSourceRange(); return ExprError(); } - assert(op->getValueKind() == VK_RValue); - assert(op->getObjectKind() == OK_Ordinary); - op->setType(DestType); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); + E->setType(DestType); // Build the sub-expression as if it were an object of the pointee type. - DestType = ptr->getPointeeType(); - ExprResult subResult = Visit(op->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); - op->setSubExpr(subResult.take()); - return op; + DestType = Ptr->getPointeeType(); + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); + E->setSubExpr(SubResult.take()); + return E; } - ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice); + ExprResult VisitImplicitCastExpr(ImplicitCastExpr *E); - ExprResult resolveDecl(Expr *expr, ValueDecl *decl); + ExprResult resolveDecl(Expr *E, ValueDecl *VD); - ExprResult VisitMemberExpr(MemberExpr *mem) { - return resolveDecl(mem, mem->getMemberDecl()); + ExprResult VisitMemberExpr(MemberExpr *E) { + return resolveDecl(E, E->getMemberDecl()); } - ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { - return resolveDecl(ref, ref->getDecl()); + ExprResult VisitDeclRefExpr(DeclRefExpr *E) { + return resolveDecl(E, E->getDecl()); } }; } /// Rebuilds a call expression which yielded __unknown_anytype. -ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { - Expr *callee = call->getCallee(); +ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) { + Expr *CalleeExpr = E->getCallee(); enum FnKind { FK_MemberFunction, @@ -9499,49 +9782,49 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { FK_BlockPointer }; - FnKind kind; - QualType type = callee->getType(); - if (type == S.Context.BoundMemberTy) { - assert(isa<CXXMemberCallExpr>(call) || isa<CXXOperatorCallExpr>(call)); - kind = FK_MemberFunction; - type = Expr::findBoundMemberType(callee); - } else if (const PointerType *ptr = type->getAs<PointerType>()) { - type = ptr->getPointeeType(); - kind = FK_FunctionPointer; + FnKind Kind; + QualType CalleeType = CalleeExpr->getType(); + if (CalleeType == S.Context.BoundMemberTy) { + assert(isa<CXXMemberCallExpr>(E) || isa<CXXOperatorCallExpr>(E)); + Kind = FK_MemberFunction; + CalleeType = Expr::findBoundMemberType(CalleeExpr); + } else if (const PointerType *Ptr = CalleeType->getAs<PointerType>()) { + CalleeType = Ptr->getPointeeType(); + Kind = FK_FunctionPointer; } else { - type = type->castAs<BlockPointerType>()->getPointeeType(); - kind = FK_BlockPointer; + CalleeType = CalleeType->castAs<BlockPointerType>()->getPointeeType(); + Kind = FK_BlockPointer; } - const FunctionType *fnType = type->castAs<FunctionType>(); + const FunctionType *FnType = CalleeType->castAs<FunctionType>(); // Verify that this is a legal result type of a function. if (DestType->isArrayType() || DestType->isFunctionType()) { unsigned diagID = diag::err_func_returning_array_function; - if (kind == FK_BlockPointer) + if (Kind == FK_BlockPointer) diagID = diag::err_block_returning_array_function; - S.Diag(call->getExprLoc(), diagID) + S.Diag(E->getExprLoc(), diagID) << DestType->isFunctionType() << DestType; return ExprError(); } // Otherwise, go ahead and set DestType as the call's result. - call->setType(DestType.getNonLValueExprType(S.Context)); - call->setValueKind(Expr::getValueKindForType(DestType)); - assert(call->getObjectKind() == OK_Ordinary); + E->setType(DestType.getNonLValueExprType(S.Context)); + E->setValueKind(Expr::getValueKindForType(DestType)); + assert(E->getObjectKind() == OK_Ordinary); // Rebuild the function type, replacing the result type with DestType. - if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType)) DestType = S.Context.getFunctionType(DestType, - proto->arg_type_begin(), - proto->getNumArgs(), - proto->getExtProtoInfo()); + Proto->arg_type_begin(), + Proto->getNumArgs(), + Proto->getExtProtoInfo()); else DestType = S.Context.getFunctionNoProtoType(DestType, - fnType->getExtInfo()); + FnType->getExtInfo()); // Rebuild the appropriate pointer-to-function type. - switch (kind) { + switch (Kind) { case FK_MemberFunction: // Nothing to do. break; @@ -9556,121 +9839,131 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { } // Finally, we can recurse. - ExprResult calleeResult = Visit(callee); - if (!calleeResult.isUsable()) return ExprError(); - call->setCallee(calleeResult.take()); + ExprResult CalleeResult = Visit(CalleeExpr); + if (!CalleeResult.isUsable()) return ExprError(); + E->setCallee(CalleeResult.take()); // Bind a temporary if necessary. - return S.MaybeBindToTemporary(call); + return S.MaybeBindToTemporary(E); } -ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { +ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) { // Verify that this is a legal result type of a call. if (DestType->isArrayType() || DestType->isFunctionType()) { - S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function) + S.Diag(E->getExprLoc(), diag::err_func_returning_array_function) << DestType->isFunctionType() << DestType; return ExprError(); } // Rewrite the method result type if available. - if (ObjCMethodDecl *method = msg->getMethodDecl()) { - assert(method->getResultType() == S.Context.UnknownAnyTy); - method->setResultType(DestType); + if (ObjCMethodDecl *Method = E->getMethodDecl()) { + assert(Method->getResultType() == S.Context.UnknownAnyTy); + Method->setResultType(DestType); } // Change the type of the message. - msg->setType(DestType.getNonReferenceType()); - msg->setValueKind(Expr::getValueKindForType(DestType)); + E->setType(DestType.getNonReferenceType()); + E->setValueKind(Expr::getValueKindForType(DestType)); - return S.MaybeBindToTemporary(msg); + return S.MaybeBindToTemporary(E); } -ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) { +ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) { // The only case we should ever see here is a function-to-pointer decay. - assert(ice->getCastKind() == CK_FunctionToPointerDecay); - assert(ice->getValueKind() == VK_RValue); - assert(ice->getObjectKind() == OK_Ordinary); + assert(E->getCastKind() == CK_FunctionToPointerDecay); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); - ice->setType(DestType); + E->setType(DestType); // Rebuild the sub-expression as the pointee (function) type. DestType = DestType->castAs<PointerType>()->getPointeeType(); - ExprResult result = Visit(ice->getSubExpr()); - if (!result.isUsable()) return ExprError(); + ExprResult Result = Visit(E->getSubExpr()); + if (!Result.isUsable()) return ExprError(); - ice->setSubExpr(result.take()); - return S.Owned(ice); + E->setSubExpr(Result.take()); + return S.Owned(E); } -ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) { - ExprValueKind valueKind = VK_LValue; - QualType type = DestType; +ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { + ExprValueKind ValueKind = VK_LValue; + QualType Type = DestType; // We know how to make this work for certain kinds of decls: // - functions - if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { - // This is true because FunctionDecls must always have function - // type, so we can't be resolving the entire thing at once. - assert(type->isFunctionType()); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(VD)) { + if (const PointerType *Ptr = Type->getAs<PointerType>()) { + DestType = Ptr->getPointeeType(); + ExprResult Result = resolveDecl(E, VD); + if (Result.isInvalid()) return ExprError(); + return S.ImpCastExprToType(Result.take(), Type, + CK_FunctionToPointerDecay, VK_RValue); + } + + if (!Type->isFunctionType()) { + S.Diag(E->getExprLoc(), diag::err_unknown_any_function) + << VD << E->getSourceRange(); + return ExprError(); + } - if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn)) - if (method->isInstance()) { - valueKind = VK_RValue; - type = S.Context.BoundMemberTy; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + if (MD->isInstance()) { + ValueKind = VK_RValue; + Type = S.Context.BoundMemberTy; } // Function references aren't l-values in C. if (!S.getLangOptions().CPlusPlus) - valueKind = VK_RValue; + ValueKind = VK_RValue; // - variables - } else if (isa<VarDecl>(decl)) { - if (const ReferenceType *refTy = type->getAs<ReferenceType>()) { - type = refTy->getPointeeType(); - } else if (type->isFunctionType()) { - S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type) - << decl << expr->getSourceRange(); + } else if (isa<VarDecl>(VD)) { + if (const ReferenceType *RefTy = Type->getAs<ReferenceType>()) { + Type = RefTy->getPointeeType(); + } else if (Type->isFunctionType()) { + S.Diag(E->getExprLoc(), diag::err_unknown_any_var_function_type) + << VD << E->getSourceRange(); return ExprError(); } // - nothing else } else { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl) - << decl << expr->getSourceRange(); + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_decl) + << VD << E->getSourceRange(); return ExprError(); } - decl->setType(DestType); - expr->setType(type); - expr->setValueKind(valueKind); - return S.Owned(expr); + VD->setType(DestType); + E->setType(Type); + E->setValueKind(ValueKind); + return S.Owned(E); } /// Check a cast of an unknown-any type. We intentionally only /// trigger this for C-style casts. -ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType, - Expr *castExpr, CastKind &castKind, - ExprValueKind &VK, CXXCastPath &path) { +ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, + Expr *CastExpr, CastKind &CastKind, + ExprValueKind &VK, CXXCastPath &Path) { // Rewrite the casted expression from scratch. - ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr); + ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr); if (!result.isUsable()) return ExprError(); - castExpr = result.take(); - VK = castExpr->getValueKind(); - castKind = CK_NoOp; + CastExpr = result.take(); + VK = CastExpr->getValueKind(); + CastKind = CK_NoOp; - return castExpr; + return CastExpr; } -static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { - Expr *orig = e; +static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { + Expr *orig = E; unsigned diagID = diag::err_uncasted_use_of_unknown_any; while (true) { - e = e->IgnoreParenImpCasts(); - if (CallExpr *call = dyn_cast<CallExpr>(e)) { - e = call->getCallee(); + E = E->IgnoreParenImpCasts(); + if (CallExpr *call = dyn_cast<CallExpr>(E)) { + E = call->getCallee(); diagID = diag::err_uncasted_call_of_unknown_any; } else { break; @@ -9679,20 +9972,25 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { SourceLocation loc; NamedDecl *d; - if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) { + if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(E)) { loc = ref->getLocation(); d = ref->getDecl(); - } else if (MemberExpr *mem = dyn_cast<MemberExpr>(e)) { + } else if (MemberExpr *mem = dyn_cast<MemberExpr>(E)) { loc = mem->getMemberLoc(); d = mem->getMemberDecl(); - } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(e)) { + } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(E)) { diagID = diag::err_uncasted_call_of_unknown_any; - loc = msg->getSelectorLoc(); + loc = msg->getSelectorStartLoc(); d = msg->getMethodDecl(); - assert(d && "unknown method returning __unknown_any?"); + if (!d) { + S.Diag(loc, diag::err_uncasted_send_to_unknown_any_method) + << static_cast<unsigned>(msg->isClassMessage()) << msg->getSelector() + << orig->getSourceRange(); + return ExprError(); + } } else { - S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr) - << e->getSourceRange(); + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << E->getSourceRange(); return ExprError(); } @@ -9709,17 +10007,27 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { QualType type = E->getType(); // Overloaded expressions. - if (type == Context.OverloadTy) - return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true, - E->getSourceRange(), - QualType(), - diag::err_ovl_unresolvable); + if (type == Context.OverloadTy) { + // Try to resolve a single function template specialization. + // This is obligatory. + ExprResult result = Owned(E); + if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) { + return result; + + // If that failed, try to recover with a call. + } else { + tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable), + /*complain*/ true); + return result; + } + } // Bound member functions. if (type == Context.BoundMemberTy) { - Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) - << E->getSourceRange(); - return ExprError(); + ExprResult result = Owned(E); + tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function), + /*complain*/ true); + return result; } // Expressions of unknown type. @@ -9730,10 +10038,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { return Owned(E); } -bool Sema::CheckCaseExpression(Expr *expr) { - if (expr->isTypeDependent()) +bool Sema::CheckCaseExpression(Expr *E) { + if (E->isTypeDependent()) return true; - if (expr->isValueDependent() || expr->isIntegerConstantExpr(Context)) - return expr->getType()->isIntegralOrEnumerationType(); + if (E->isValueDependent() || E->isIntegerConstantExpr(Context)) + return E->getType()->isIntegralOrEnumerationType(); return false; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index e804fcd..3300444 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -295,6 +295,12 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation RParenLoc) { bool isUnevaluatedOperand = true; if (E && !E->isTypeDependent()) { + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + QualType T = E->getType(); if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); @@ -325,7 +331,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; - E = ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)).take(); + E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).take(); } } @@ -545,7 +551,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, - CastCategory(E)).take(); + E->getValueKind()).take(); ExprResult Res = DefaultFunctionArrayConversion(E); if (Res.isInvalid()) @@ -739,27 +745,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. - // if (NumExprs == 1) { - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - ExprResult CastExpr = - CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(), - TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], - Kind, VK, BasePath, - /*FunctionalStyle=*/true); - if (CastExpr.isInvalid()) - return ExprError(); - Exprs[0] = CastExpr.take(); - + Expr *Arg = Exprs[0]; exprs.release(); - - return Owned(CXXFunctionalCastExpr::Create(Context, - Ty.getNonLValueExprType(Context), - VK, TInfo, TyBeginLoc, Kind, - Exprs[0], &BasePath, - RParenLoc)); + return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); @@ -1058,7 +1047,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); - llvm::SmallVector<Expr *, 8> AllPlaceArgs; + SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. const FunctionProtoType *Proto = @@ -1079,6 +1068,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- CXXConstructorDecl *Constructor = 0; + bool HadMultipleCandidates = false; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); ASTOwningVector<Expr*> ConvertedConstructorArgs(*this); @@ -1125,6 +1115,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(FullInitExpr)) { Constructor = Construct->getConstructor(); + HadMultipleCandidates = Construct->hadMultipleCandidates(); for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(), AEnd = Construct->arg_end(); A != AEnd; ++A) @@ -1166,7 +1157,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, - ConsArgs, NumConsArgs, OperatorDelete, + ConsArgs, NumConsArgs, + HadMultipleCandidates, + OperatorDelete, UsualArrayDeleteWantsSize, ResultType, AllocTypeInfo, StartLoc, @@ -1246,12 +1239,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 3) The first argument is always size_t. Append the arguments from the // placement form. - llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs); + SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs); // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? IntegerLiteral Size(Context, llvm::APInt::getNullValue( - Context.Target.getPointerWidth(0)), + Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); AllocArgs[0] = &Size; @@ -1325,7 +1318,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, FoundDelete.suppressDiagnostics(); - llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; + SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; // Whether we're looking for a placement operator delete is dictated // by whether we selected a placement operator new, not by whether @@ -1352,7 +1345,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); - llvm::SmallVector<QualType, 4> ArgTypes; + SmallVector<QualType, 4> ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) ArgTypes.push_back(Proto->getArgType(I)); @@ -1525,8 +1518,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, return true; } } - assert(false && "Unreachable, bad result from BestViableFunction"); - return true; + llvm_unreachable("Unreachable, bad result from BestViableFunction"); } @@ -1671,7 +1663,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, SourceLocation(), 0, Argument, /*TInfo=*/0, SC_None, SC_None, 0); - Alloc->setParams(&Param, 1); + Alloc->setParams(Param); // FIXME: Also add this declaration to the IdentifierResolver, but // make sure it is at the end of the chain to coincide with the @@ -1691,7 +1683,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); - llvm::SmallVector<DeclAccessPair,4> Matches; + SmallVector<DeclAccessPair,4> Matches; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { NamedDecl *ND = (*F)->getUnderlyingDecl(); @@ -1727,7 +1719,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; - for (llvm::SmallVectorImpl<DeclAccessPair>::iterator + for (SmallVectorImpl<DeclAccessPair>::iterator F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; @@ -1792,7 +1784,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::err_delete_incomplete_class_type))) return ExprError(); - llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; + SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); @@ -1840,24 +1832,32 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex.get()->getSourceRange()); QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); + QualType PointeeElem = Context.getBaseElementType(Pointee); + + if (unsigned AddressSpace = Pointee.getAddressSpace()) + return Diag(Ex.get()->getLocStart(), + diag::err_address_space_qualified_delete) + << Pointee.getUnqualifiedType() << AddressSpace; + + CXXRecordDecl *PointeeRD = 0; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); - } else if (Pointee->isFunctionType() || Pointee->isVoidType()) + } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); - else if (!Pointee->isDependentType() && - RequireCompleteType(StartLoc, Pointee, - PDiag(diag::warn_delete_incomplete) - << Ex.get()->getSourceRange())) - return ExprError(); - else if (unsigned AddressSpace = Pointee.getAddressSpace()) - return Diag(Ex.get()->getLocStart(), - diag::err_address_space_qualified_delete) - << Pointee.getUnqualifiedType() << AddressSpace; + } else if (!Pointee->isDependentType()) { + if (!RequireCompleteType(StartLoc, Pointee, + PDiag(diag::warn_delete_incomplete) + << Ex.get()->getSourceRange())) { + if (const RecordType *RT = PointeeElem->getAs<RecordType>()) + PointeeRD = cast<CXXRecordDecl>(RT->getDecl()); + } + } + // C++ [expr.delete]p2: // [Note: a pointer to a const type can be the operand of a // delete-expression; it is not necessary to cast away the constness @@ -1877,12 +1877,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); - QualType PointeeElem = Context.getBaseElementType(Pointee); - if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - + if (PointeeRD) { if (!UseGlobal && - FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) + FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, + OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the @@ -1900,8 +1898,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); } - if (!RD->hasTrivialDestructor()) - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (!PointeeRD->hasTrivialDestructor()) + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkDeclarationReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); @@ -1915,10 +1913,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // behavior is undefined. // // Note: a final class cannot be derived from, no issue there - if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) { - CXXDestructorDecl *dtor = RD->getDestructor(); - if (!dtor || !dtor->isVirtual()) - Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) { + CXXDestructorDecl *dtor = PointeeRD->getDestructor(); + if (dtor && !dtor->isVirtual()) { + if (PointeeRD->isAbstract()) { + // If the class is abstract, we warn by default, because we're + // sure the code has undefined behavior. + Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor) + << PointeeElem; + } else if (!ArrayForm) { + // Otherwise, if this is not an array delete, it's a bit suspect, + // but not necessarily wrong. + Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + } + } } } else if (getLangOptions().ObjCAutoRefCount && @@ -1944,9 +1952,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, MarkDeclarationReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. - if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (PointeeRD) { + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } @@ -2026,12 +2033,20 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { = ToPtrType->getPointeeType()->getAs<BuiltinType>()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). - if (!ToPtrType->getPointeeType().hasQualifiers() && - ((StrLit->isWide() && ToPointeeType->isWideCharType()) || - (!StrLit->isWide() && - (ToPointeeType->getKind() == BuiltinType::Char_U || - ToPointeeType->getKind() == BuiltinType::Char_S)))) - return true; + if (!ToPtrType->getPointeeType().hasQualifiers()) { + switch (StrLit->getKind()) { + case StringLiteral::UTF8: + case StringLiteral::UTF16: + case StringLiteral::UTF32: + // We don't allow UTF literals to be implicitly converted + break; + case StringLiteral::Ascii: + return (ToPointeeType->getKind() == BuiltinType::Char_U || + ToPointeeType->getKind() == BuiltinType::Char_S); + case StringLiteral::Wide: + return ToPointeeType->isWideCharType(); + } + } } return false; @@ -2042,23 +2057,28 @@ static ExprResult BuildCXXCastArgument(Sema &S, QualType Ty, CastKind Kind, CXXMethodDecl *Method, - NamedDecl *FoundDecl, + DeclAccessPair FoundDecl, + bool HadMultipleCandidates, Expr *From) { switch (Kind) { - default: assert(0 && "Unhandled cast kind!"); + default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method); ASTOwningVector<Expr*> ConstructorArgs(S); - if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + if (S.CompleteConstructorCall(Constructor, MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - ExprResult Result = - S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs), - /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, - SourceRange()); + S.CheckConstructorAccess(CastLoc, Constructor, Constructor->getAccess(), + S.PDiag(diag::err_access_ctor)); + + ExprResult Result + = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); @@ -2069,10 +2089,13 @@ static ExprResult BuildCXXCastArgument(Sema &S, assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. - ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method); + ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); + S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl); + return S.MaybeBindToTemporary(Result.get()); } } @@ -2138,6 +2161,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ToType.getNonReferenceType(), CastKind, cast<CXXMethodDecl>(FD), ICS.UserDefined.FoundConversionFunction, + ICS.UserDefined.HadMultipleCandidates, From); if (CastArg.isInvalid()) @@ -2156,8 +2180,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); case ImplicitConversionSequence::EllipsisConversion: - assert(false && "Cannot perform an ellipsis conversion"); - return Owned(From); + llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: return ExprError(); @@ -2198,6 +2221,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, move_arg(ConstructorArgs), + /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -2205,6 +2229,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, MultiExprArg(*this, &From, 1), + /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -2241,9 +2266,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (!From->isGLValue()) break; } - // Check for trivial buffer overflows. - CheckArrayAccess(From); - FromType = FromType.getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, From, 0, VK_RValue); @@ -2262,8 +2284,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, break; default: - assert(false && "Improper first standard conversion"); - break; + llvm_unreachable("Improper first standard conversion"); } // Perform the second implicit conversion @@ -2340,12 +2361,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action - << From->getSourceRange(); + << From->getSourceRange() << 0; else Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action - << From->getSourceRange(); + << From->getSourceRange() << 0; if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) @@ -2354,20 +2375,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, else if (getLangOptions().ObjCAutoRefCount && !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { - if (Action == AA_Initializing) - Diag(From->getSourceRange().getBegin(), - diag::err_arc_weak_unavailable_assign); - else - Diag(From->getSourceRange().getBegin(), - diag::err_arc_convesion_of_weak_unavailable) - << (Action == AA_Casting) << From->getType() << ToType - << From->getSourceRange(); - } + if (Action == AA_Initializing) + Diag(From->getSourceRange().getBegin(), + diag::err_arc_weak_unavailable_assign); + else + Diag(From->getSourceRange().getBegin(), + diag::err_arc_convesion_of_weak_unavailable) + << (Action == AA_Casting) << From->getType() << ToType + << From->getSourceRange(); + } CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); + + // Make sure we extend blocks if necessary. + // FIXME: doing this here is really ugly. + if (Kind == CK_BlockPointerToObjCPointerCast) { + ExprResult E = From; + (void) PrepareCastToObjCObjectPointer(E); + From = E.take(); + } + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .take(); break; @@ -2386,6 +2416,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Boolean_Conversion: + // Perform half-to-boolean conversion via float. + if (From->getType()->isHalfType()) { + From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take(); + FromType = Context.FloatTy; + } + From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/0, CCK).take(); @@ -2402,7 +2438,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); From = ImpCastExprToType(From, ToType.getNonReferenceType(), - CK_DerivedToBase, CastCategory(From), + CK_DerivedToBase, From->getValueKind(), &BasePath, CCK).take(); break; } @@ -2493,8 +2529,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Function_To_Pointer: case ICK_Qualification: case ICK_Num_Conversion_Kinds: - assert(false && "Improper second standard conversion"); - break; + llvm_unreachable("Improper second standard conversion"); } switch (SCS.Third) { @@ -2506,7 +2541,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? - CastCategory(From) : VK_RValue; + From->getValueKind() : VK_RValue; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK_NoOp, VK, /*BasePath=*/0, CCK).take(); @@ -2519,8 +2554,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } default: - assert(false && "Improper third standard conversion"); - break; + llvm_unreachable("Improper third standard conversion"); } return Owned(From); @@ -2835,8 +2869,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), Sema::LookupOrdinaryName); if (Self.LookupQualifiedName(Res, RD)) { + Res.suppressDiagnostics(); for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); Op != OpEnd; ++Op) { + if (isa<FunctionTemplateDecl>(*Op)) + continue; + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); if (Operator->isCopyAssignmentOperator()) { FoundAssign = true; @@ -2849,7 +2887,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, } } } - + return FoundAssign; } return false; @@ -3240,34 +3278,34 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, RParen, Context.BoolTy)); } -QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, +QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { - assert(!lex.get()->getType()->isPlaceholderType() && - !rex.get()->getType()->isPlaceholderType() && + assert(!LHS.get()->getType()->isPlaceholderType() && + !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); // The LHS undergoes lvalue conversions if this is ->*. if (isIndirect) { - lex = DefaultLvalueConversion(lex.take()); - if (lex.isInvalid()) return QualType(); + LHS = DefaultLvalueConversion(LHS.take()); + if (LHS.isInvalid()) return QualType(); } // The RHS always undergoes lvalue conversions. - rex = DefaultLvalueConversion(rex.take()); - if (rex.isInvalid()) return QualType(); + RHS = DefaultLvalueConversion(RHS.take()); + if (RHS.isInvalid()) return QualType(); const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] - QualType RType = rex.get()->getType(); - const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>(); + QualType RHSType = RHS.get()->getType(); + const MemberPointerType *MemPtr = RHSType->getAs<MemberPointerType>(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) - << OpSpelling << RType << rex.get()->getSourceRange(); + << OpSpelling << RHSType << RHS.get()->getSourceRange(); return QualType(); } @@ -3283,21 +3321,21 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] - QualType LType = lex.get()->getType(); + QualType LHSType = LHS.get()->getType(); if (isIndirect) { - if (const PointerType *Ptr = LType->getAs<PointerType>()) - LType = Ptr->getPointeeType(); + if (const PointerType *Ptr = LHSType->getAs<PointerType>()) + LHSType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) - << OpSpelling << 1 << LType + << OpSpelling << 1 << LHSType << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } - if (!Context.hasSameUnqualifiedType(Class, LType)) { + if (!Context.hasSameUnqualifiedType(Class, LHSType)) { // If we want to check the hierarchy, we need a complete type. - if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs) + if (RequireCompleteType(Loc, LHSType, PDiag(diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect)) { return QualType(); } @@ -3305,23 +3343,23 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? - if (!IsDerivedFrom(LType, Class, Paths) || + if (!IsDerivedFrom(LHSType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex.get()->getType(); + << (int)isIndirect << LHS.get()->getType(); return QualType(); } // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; - ExprValueKind VK = - isIndirect ? VK_RValue : CastCategory(lex.get()); + ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind(); CXXCastPath BasePath; BuildBasePathArray(Paths, BasePath); - lex = ImpCastExprToType(lex.take(), UseType, CK_DerivedToBase, VK, &BasePath); + LHS = ImpCastExprToType(LHS.take(), UseType, CK_DerivedToBase, VK, + &BasePath); } - if (isa<CXXScalarValueInitExpr>(rex.get()->IgnoreParens())) { + if (isa<CXXScalarValueInitExpr>(RHS.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; @@ -3334,7 +3372,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. QualType Result = MemPtr->getPointeeType(); - Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is @@ -3349,15 +3387,15 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, break; case RQ_LValue: - if (!isIndirect && !lex.get()->Classify(Context).isLValue()) + if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 1 << lex.get()->getSourceRange(); + << RHSType << 1 << LHS.get()->getSourceRange(); break; case RQ_RValue: - if (isIndirect || !lex.get()->Classify(Context).isRValue()) + if (isIndirect || !LHS.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 0 << lex.get()->getSourceRange(); + << RHSType << 0 << LHS.get()->getSourceRange(); break; } } @@ -3375,7 +3413,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, } else if (isIndirect) { VK = VK_LValue; } else { - VK = lex.get()->getValueKind(); + VK = LHS.get()->getValueKind(); } return Result; @@ -3528,8 +3566,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS break; case OR_Deleted: - assert(false && "Conditional operator has only built-in overloads"); - break; + llvm_unreachable("Conditional operator has only built-in overloads"); } return true; } @@ -3838,9 +3875,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. // FIXME: extended qualifiers? - typedef llvm::SmallVector<unsigned, 4> QualifierVector; + typedef SmallVector<unsigned, 4> QualifierVector; QualifierVector QualifierUnion; - typedef llvm::SmallVector<std::pair<const Type *, const Type *>, 4> + typedef SmallVector<std::pair<const Type *, const Type *>, 4> ContainingClassVector; ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), @@ -4044,27 +4081,30 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { // actual method. FIXME: we should infer retention by selector in // cases where we don't have an actual method. } else { - Decl *D = 0; + ObjCMethodDecl *D = 0; if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) { D = Send->getMethodDecl(); } else { CastExpr *CE = cast<CastExpr>(E); - // FIXME. What other cast kinds to check for? - if (CE->getCastKind() == CK_ObjCProduceObject || - CE->getCastKind() == CK_LValueToRValue) - return MaybeBindToTemporary(CE->getSubExpr()); assert(CE->getCastKind() == CK_GetObjCProperty); const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty(); D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0); } ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>()); + + // Don't do reclaims on performSelector calls; despite their + // return type, the invoked method doesn't necessarily actually + // return an object. + if (!ReturnsRetained && + D && D->getMethodFamily() == OMF_performSelector) + return Owned(E); } ExprNeedsCleanups = true; - CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject - : CK_ObjCReclaimReturnedObject); + CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject + : CK_ARCReclaimReturnedObject); return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0, VK_RValue)); } @@ -4172,7 +4212,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, if (OpKind == tok::arrow) { // The set of types we've considered so far. llvm::SmallPtrSet<CanQualType,8> CTypes; - llvm::SmallVector<SourceLocation, 8> Locations; + SmallVector<SourceLocation, 8> Locations; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { @@ -4509,7 +4549,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, - CXXMethodDecl *Method) { + CXXMethodDecl *Method, + bool HadMultipleCandidates) { ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0, FoundDecl, Method); if (Exp.isInvalid()) @@ -4519,6 +4560,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method, SourceLocation(), Method->getType(), VK_RValue, OK_Ordinary); + if (HadMultipleCandidates) + ME->setHadMultipleCandidates(true); + QualType ResultType = Method->getResultType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); @@ -4608,7 +4652,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE) { if (FullExpr.isInvalid()) return ExprError(); - CheckImplicitConversions(FullExpr.get()); + CheckImplicitConversions(FullExpr.get(), FullExpr.get()->getExprLoc()); return MaybeCreateExprWithCleanups(FullExpr); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index 2488dc8..26867c2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp @@ -298,7 +298,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); + << StringRef(compStr, 1) << SourceRange(CompLoc); return QualType(); } @@ -337,10 +337,14 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); // Now look up the TypeDefDecl from the vector type. Without this, // diagostics look bad. We want extended vector types to appear built-in. - for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { - if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) - return S.Context.getTypedefType(S.ExtVectorDecls[i]); + for (Sema::ExtVectorDeclsType::iterator + I = S.ExtVectorDecls.begin(S.ExternalSource), + E = S.ExtVectorDecls.end(); + I != E; ++I) { + if ((*I)->getUnderlyingType() == VT) + return S.Context.getTypedefType(*I); } + return VT; // should never get here (a typedef type should always be found). } @@ -949,9 +953,9 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { QualType redef; if (ty->isObjCId()) { - redef = S.Context.ObjCIdRedefinitionType; + redef = S.Context.getObjCIdRedefinitionType(); } else if (ty->isObjCClass()) { - redef = S.Context.ObjCClassRedefinitionType; + redef = S.Context.getObjCClassRedefinitionType(); } else { return false; } @@ -966,6 +970,15 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { return true; } +static bool isRecordType(QualType T) { + return T->isRecordType(); +} +static bool isPointerToRecordType(QualType T) { + if (const PointerType *PT = T->getAs<PointerType>()) + return PT->getPointeeType()->isRecordType(); + return false; +} + /// Look up the given member of the given non-type-dependent /// expression. This can return in one of two ways: /// * If it returns a sentinel null-but-valid result, the caller will @@ -985,6 +998,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Perform default conversions. BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); if (IsArrow) { BaseExpr = DefaultLvalueConversion(BaseExpr.take()); @@ -1041,6 +1056,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Handle ivar access to Objective-C objects. if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { + if (!SS.isEmpty() && !SS.isInvalid()) { + Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access) + << 1 << SS.getScopeRep() + << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); // There are three cases for the base type: @@ -1159,6 +1181,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Objective-C property access. const ObjCObjectPointerType *OPT; if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { + if (!SS.isEmpty() && !SS.isInvalid()) { + Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access) + << 0 << SS.getScopeRep() + << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } + // This actually uses the base as an r-value. BaseExpr = DefaultLvalueConversion(BaseExpr.take()); if (BaseExpr.isInvalid()) @@ -1318,8 +1347,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // not just a pointer to builtin-sel again. if (IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && - !Context.ObjCSelRedefinitionType->isObjCSelType()) { - BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, + !Context.getObjCSelRedefinitionType()->isObjCSelType()) { + BaseExpr = ImpCastExprToType(BaseExpr.take(), + Context.getObjCSelRedefinitionType(), CK_BitCast); return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); @@ -1351,50 +1381,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // If the user is trying to apply -> or . to a function name, it's probably // because they forgot parentheses to call that function. - QualType ZeroArgCallTy; - UnresolvedSet<4> Overloads; - if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { - if (ZeroArgCallTy.isNull()) { - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); - UnresolvedSet<2> PlausibleOverloads; - for (OverloadExpr::decls_iterator It = Overloads.begin(), - DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { - const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); - QualType OverloadResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && OverloadResultTy->isRecordType()) || - (IsArrow && OverloadResultTy->isPointerType() && - OverloadResultTy->getPointeeType()->isRecordType())) - PlausibleOverloads.addDecl(It.getDecl()); - } - NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); + if (tryToRecoverWithCall(BaseExpr, + PDiag(diag::err_member_reference_needs_call), + /*complain*/ false, + IsArrow ? &isRecordType : &isPointerToRecordType)) { + if (BaseExpr.isInvalid()) return ExprError(); - } - if ((!IsArrow && ZeroArgCallTy->isRecordType()) || - (IsArrow && ZeroArgCallTy->isPointerType() && - ZeroArgCallTy->getPointeeType()->isRecordType())) { - // At this point, we know BaseExpr looks like it's potentially callable - // with 0 arguments, and that it returns something of a reasonable type, - // so we can emit a fixit and carry on pretending that BaseExpr was - // actually a CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - // FIXME: Try this before emitting the fixit, and suppress diagnostics - // while doing so. - ExprResult NewBase = - ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc.getFileLocWithOffset(1)); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); } Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) @@ -1427,7 +1422,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, return ExprError(); // Warn about the explicit constructor calls Microsoft extension. - if (getLangOptions().Microsoft && + if (getLangOptions().MicrosoftExt && Id.getKind() == UnqualifiedId::IK_ConstructorName) Diag(Id.getSourceRange().getBegin(), diag::ext_ms_explicit_constructor_call); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 02a4682..20098b2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" @@ -26,6 +27,7 @@ using namespace clang; using namespace sema; +using llvm::makeArrayRef; ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, Expr **strings, @@ -42,13 +44,13 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, if (NumStrings != 1) { // Concatenate objc strings. llvm::SmallString<128> StrBuf; - llvm::SmallVector<SourceLocation, 8> StrLocs; + SmallVector<SourceLocation, 8> StrLocs; for (unsigned i = 0; i != NumStrings; ++i) { S = Strings[i]; - // ObjC strings can't be wide. - if (S->isWide()) { + // ObjC strings can't be wide or UTF. + if (!S->isAscii()) { Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant) << S->getSourceRange(); return true; @@ -64,7 +66,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // Create the aggregate string with the appropriate content and location // information. S = StringLiteral::Create(Context, StrBuf, - /*Wide=*/false, /*Pascal=*/false, + StringLiteral::Ascii, /*Pascal=*/false, Context.getPointerType(Context.CharTy), &StrLocs[0], StrLocs.size()); } @@ -203,6 +205,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, case OMF_None: case OMF_alloc: case OMF_copy: + case OMF_finalize: case OMF_init: case OMF_mutableCopy: case OMF_new: @@ -270,6 +273,13 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() { return method; } +static QualType stripObjCInstanceType(ASTContext &Context, QualType T) { + if (T == Context.getObjCInstanceType()) + return Context.getObjCIdType(); + + return T; +} + QualType Sema::getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage) { @@ -282,7 +292,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) - return Method->getSendResultType(); + return stripObjCInstanceType(Context, Method->getSendResultType()); // - if the receiver is super, T is a pointer to the class of the // enclosing method definition @@ -301,7 +311,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) - return Method->getSendResultType(); + return stripObjCInstanceType(Context, Method->getSendResultType()); // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise @@ -327,6 +337,10 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) { MsgSend->getType())) return; + if (!Context.hasSameUnqualifiedType(Method->getResultType(), + Context.getObjCInstanceType())) + return; + Diag(Method->getLocation(), diag::note_related_result_type_inferred) << Method->isInstanceMethod() << Method->getSelector() << MsgSend->getType(); @@ -356,8 +370,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, else DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; - Diag(lbrac, DiagID) - << Sel << isClassMessage << SourceRange(lbrac, rbrac); + if (!getLangOptions().DebuggerSupport) + Diag(lbrac, DiagID) + << Sel << isClassMessage << SourceRange(lbrac, rbrac); // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. @@ -947,7 +962,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { // Determine whether we are inside a method or not. @@ -975,13 +990,18 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // We are in a method whose class has a superclass, so 'super' // is acting as a keyword. if (Method->isInstanceMethod()) { + if (Sel.getMethodFamily() == OMF_dealloc) + ObjCShouldCallSuperDealloc = false; + if (Sel.getMethodFamily() == OMF_finalize) + ObjCShouldCallSuperFinalize = false; + // Since we are in an instance method, this is an instance // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(0, SuperTy, SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } // Since we are in a class method, this is a class message to @@ -989,7 +1009,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return BuildClassMessage(/*ReceiverTypeInfo=*/0, Context.getObjCInterfaceType(Super), SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build an Objective-C class message expression. @@ -1026,7 +1046,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg ArgsIn) { SourceLocation Loc = SuperLoc.isValid()? SuperLoc @@ -1045,8 +1065,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, - Sel, SelectorLoc, /*Method=*/0, - Args, NumArgs, RBracLoc)); + Sel, SelectorLocs, /*Method=*/0, + makeArrayRef(Args, NumArgs),RBracLoc)); } // Find the class to which we are sending this message. @@ -1107,12 +1127,14 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, SelectorLoc, - Method, Args, NumArgs, RBracLoc); + ReceiverType, Sel, SelectorLocs, + Method, makeArrayRef(Args, NumArgs), + RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - ReceiverTypeInfo, Sel, SelectorLoc, - Method, Args, NumArgs, RBracLoc); + ReceiverTypeInfo, Sel, SelectorLocs, + Method, makeArrayRef(Args, NumArgs), + RBracLoc); return MaybeBindToTemporary(Result); } @@ -1123,7 +1145,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { TypeSourceInfo *ReceiverTypeInfo; @@ -1137,7 +1159,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, return BuildClassMessage(ReceiverTypeInfo, ReceiverType, /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build an Objective-C instance message expression. @@ -1174,7 +1196,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg ArgsIn) { // The location of the receiver. @@ -1197,8 +1219,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel, - SelectorLoc, /*Method=*/0, - Args, NumArgs, RBracLoc)); + SelectorLocs, /*Method=*/0, + makeArrayRef(Args, NumArgs), + RBracLoc)); } // If necessary, apply function/array conversion to the receiver. @@ -1346,7 +1369,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_BitCast).take(); + CK_CPointerToObjCPointerCast).take(); else { // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, @@ -1355,24 +1378,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, IsNull ? CK_NullToPointer : CK_IntegralToPointer).take(); } ReceiverType = Receiver->getType(); - } - else { + } else { ExprResult ReceiverRes; if (getLangOptions().CPlusPlus) - ReceiverRes = PerformContextuallyConvertToObjCId(Receiver); + ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver); if (ReceiverRes.isUsable()) { Receiver = ReceiverRes.take(); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { - Receiver = ICE->getSubExpr(); - ReceiverType = Receiver->getType(); - } return BuildInstanceMessage(Receiver, ReceiverType, SuperLoc, Sel, Method, LBracLoc, - SelectorLoc, + SelectorLocs, RBracLoc, move(ArgsIn)); } else { @@ -1402,6 +1420,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); + SourceLocation SelLoc = SelectorLocs.front(); + // In ARC, forbid the user from sending messages to // retain/release/autorelease/dealloc/retainCount explicitly. if (getLangOptions().ObjCAutoRefCount) { @@ -1415,6 +1435,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_None: case OMF_alloc: case OMF_copy: + case OMF_finalize: case OMF_mutableCopy: case OMF_new: case OMF_self: @@ -1426,7 +1447,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_autorelease: case OMF_retainCount: Diag(Loc, diag::err_arc_illegal_explicit_message) - << Sel << SelectorLoc; + << Sel << SelLoc; break; case OMF_performSelector: @@ -1452,7 +1473,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // Issue error, unless ns_returns_not_retained. if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { // selector names a +1 method - Diag(SelectorLoc, + Diag(SelLoc, diag::err_arc_perform_selector_retains); Diag(SelMethod->getLocation(), diag::note_method_declared_at); } @@ -1461,7 +1482,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // +0 call. OK. unless ns_returns_retained. if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) { // selector names a +1 method - Diag(SelectorLoc, + Diag(SelLoc, diag::err_arc_perform_selector_retains); Diag(SelMethod->getLocation(), diag::note_method_declared_at); } @@ -1470,7 +1491,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } else { // error (may leak). - Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks); + Diag(SelLoc, diag::warn_arc_perform_selector_leaks); Diag(Args[0]->getExprLoc(), diag::note_used_here); } } @@ -1483,12 +1504,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, SelectorLoc, Method, - Args, NumArgs, RBracLoc); + ReceiverType, Sel, SelectorLocs, Method, + makeArrayRef(Args, NumArgs), RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - Receiver, Sel, SelectorLoc, Method, - Args, NumArgs, RBracLoc); + Receiver, Sel, SelectorLocs, Method, + makeArrayRef(Args, NumArgs), RBracLoc); if (getLangOptions().ObjCAutoRefCount) { // In ARC, annotate delegate init calls. @@ -1520,7 +1541,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { if (!Receiver) @@ -1528,206 +1549,360 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, return BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } enum ARCConversionTypeClass { + /// int, void, struct A ACTC_none, + + /// id, void (^)() ACTC_retainable, - ACTC_indirectRetainable + + /// id*, id***, void (^*)(), + ACTC_indirectRetainable, + + /// void* might be a normal C type, or it might a CF type. + ACTC_voidPtr, + + /// struct A* + ACTC_coreFoundation }; +static bool isAnyRetainable(ARCConversionTypeClass ACTC) { + return (ACTC == ACTC_retainable || + ACTC == ACTC_coreFoundation || + ACTC == ACTC_voidPtr); +} +static bool isAnyCLike(ARCConversionTypeClass ACTC) { + return ACTC == ACTC_none || + ACTC == ACTC_voidPtr || + ACTC == ACTC_coreFoundation; +} + static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) { - ARCConversionTypeClass ACTC = ACTC_retainable; + bool isIndirect = false; // Ignore an outermost reference type. - if (const ReferenceType *ref = type->getAs<ReferenceType>()) + if (const ReferenceType *ref = type->getAs<ReferenceType>()) { type = ref->getPointeeType(); + isIndirect = true; + } // Drill through pointers and arrays recursively. while (true) { if (const PointerType *ptr = type->getAs<PointerType>()) { type = ptr->getPointeeType(); + + // The first level of pointer may be the innermost pointer on a CF type. + if (!isIndirect) { + if (type->isVoidType()) return ACTC_voidPtr; + if (type->isRecordType()) return ACTC_coreFoundation; + } } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) { type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0); } else { break; } - ACTC = ACTC_indirectRetainable; + isIndirect = true; } - if (!type->isObjCRetainableType()) return ACTC_none; - return ACTC; + if (isIndirect) { + if (type->isObjCARCBridgableType()) + return ACTC_indirectRetainable; + return ACTC_none; + } + + if (type->isObjCARCBridgableType()) + return ACTC_retainable; + + return ACTC_none; } namespace { - /// Return true if the given expression can be reasonably converted - /// between a retainable pointer type and a C pointer type. - struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> { + /// A result from the cast checker. + enum ACCResult { + /// Cannot be casted. + ACC_invalid, + + /// Can be safely retained or not retained. + ACC_bottom, + + /// Can be casted at +0. + ACC_plusZero, + + /// Can be casted at +1. + ACC_plusOne + }; + ACCResult merge(ACCResult left, ACCResult right) { + if (left == right) return left; + if (left == ACC_bottom) return right; + if (right == ACC_bottom) return left; + return ACC_invalid; + } + + /// A checker which white-lists certain expressions whose conversion + /// to or from retainable type would otherwise be forbidden in ARC. + class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> { + typedef StmtVisitor<ARCCastChecker, ACCResult> super; + ASTContext &Context; - ARCCastChecker(ASTContext &Context) : Context(Context) {} - bool VisitStmt(Stmt *s) { - return false; + ARCConversionTypeClass SourceClass; + ARCConversionTypeClass TargetClass; + + static bool isCFType(QualType type) { + // Someday this can use ns_bridged. For now, it has to do this. + return type->isCARCBridgableType(); } - bool VisitExpr(Expr *e) { - return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); + + public: + ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source, + ARCConversionTypeClass target) + : Context(Context), SourceClass(source), TargetClass(target) {} + + using super::Visit; + ACCResult Visit(Expr *e) { + return super::Visit(e->IgnoreParens()); } - - bool VisitParenExpr(ParenExpr *e) { - return Visit(e->getSubExpr()); + + ACCResult VisitStmt(Stmt *s) { + return ACC_invalid; + } + + /// Null pointer constants can be casted however you please. + ACCResult VisitExpr(Expr *e) { + if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + return ACC_bottom; + return ACC_invalid; } - bool VisitCastExpr(CastExpr *e) { + + /// Objective-C string literals can be safely casted. + ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) { + // If we're casting to any retainable type, go ahead. Global + // strings are immune to retains, so this is bottom. + if (isAnyRetainable(TargetClass)) return ACC_bottom; + + return ACC_invalid; + } + + /// Look through certain implicit and explicit casts. + ACCResult VisitCastExpr(CastExpr *e) { switch (e->getCastKind()) { case CK_NullToPointer: - return true; + return ACC_bottom; + case CK_NoOp: case CK_LValueToRValue: case CK_BitCast: - case CK_AnyPointerToObjCPointerCast: + case CK_GetObjCProperty: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(e->getSubExpr()); + default: - return false; + return ACC_invalid; } } - bool VisitUnaryExtension(UnaryOperator *e) { + + /// Look through unary extension. + ACCResult VisitUnaryExtension(UnaryOperator *e) { return Visit(e->getSubExpr()); } - bool VisitBinComma(BinaryOperator *e) { + + /// Ignore the LHS of a comma operator. + ACCResult VisitBinComma(BinaryOperator *e) { return Visit(e->getRHS()); } - bool VisitConditionalOperator(ConditionalOperator *e) { - // Conditional operators are okay if both sides are okay. - return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr()); - } - bool VisitObjCStringLiteral(ObjCStringLiteral *e) { - // Always white-list Objective-C string literals. - return true; + + /// Conditional operators are okay if both sides are okay. + ACCResult VisitConditionalOperator(ConditionalOperator *e) { + ACCResult left = Visit(e->getTrueExpr()); + if (left == ACC_invalid) return ACC_invalid; + return merge(left, Visit(e->getFalseExpr())); } - bool VisitStmtExpr(StmtExpr *e) { + + /// Statement expressions are okay if their result expression is okay. + ACCResult VisitStmtExpr(StmtExpr *e) { return Visit(e->getSubStmt()->body_back()); } - bool VisitDeclRefExpr(DeclRefExpr *e) { - // White-list references to global extern strings from system - // headers. - if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl())) - if (var->getStorageClass() == SC_Extern && - var->getType().isConstQualified() && - Context.getSourceManager().isInSystemHeader(var->getLocation())) - return true; - return false; + + /// Some declaration references are okay. + ACCResult VisitDeclRefExpr(DeclRefExpr *e) { + // References to global constants from system headers are okay. + // These are things like 'kCFStringTransformToLatin'. They are + // can also be assumed to be immune to retains. + VarDecl *var = dyn_cast<VarDecl>(e->getDecl()); + if (isAnyRetainable(TargetClass) && + isAnyRetainable(SourceClass) && + var && + var->getStorageClass() == SC_Extern && + var->getType().isConstQualified() && + Context.getSourceManager().isInSystemHeader(var->getLocation())) { + return ACC_bottom; + } + + // Nothing else. + return ACC_invalid; } - }; -} -bool -Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) { - Expr *NewExp = Exp->IgnoreParenCasts(); - - if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp) - && !isa<CallExpr>(NewExp)) - return false; - ObjCMethodDecl *method = 0; - bool MethodReturnsPlusOne = false; - - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) { - method = PRE->getExplicitProperty()->getGetterMethodDecl(); - } - else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp)) - method = ME->getMethodDecl(); - else { - CallExpr *CE = cast<CallExpr>(NewExp); - Decl *CallDecl = CE->getCalleeDecl(); - if (!CallDecl) - return false; - if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>()) - return true; - MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>(); - if (!MethodReturnsPlusOne) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl)) - if (const IdentifierInfo *Id = ND->getIdentifier()) - if (Id->isStr("__builtin___CFStringMakeConstantString")) - return true; + /// Some calls are okay. + ACCResult VisitCallExpr(CallExpr *e) { + if (FunctionDecl *fn = e->getDirectCallee()) + if (ACCResult result = checkCallToFunction(fn)) + return result; + + return super::VisitCallExpr(e); } - } - - if (!MethodReturnsPlusOne) { - if (!method) - return false; - if (method->hasAttr<CFReturnsNotRetainedAttr>()) - return true; - MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>(); - if (!MethodReturnsPlusOne) { - ObjCMethodFamily family = method->getSelector().getMethodFamily(); - switch (family) { - case OMF_alloc: - case OMF_copy: - case OMF_mutableCopy: - case OMF_new: - MethodReturnsPlusOne = true; - break; - default: - break; + + ACCResult checkCallToFunction(FunctionDecl *fn) { + // Require a CF*Ref return type. + if (!isCFType(fn->getResultType())) + return ACC_invalid; + + if (!isAnyRetainable(TargetClass)) + return ACC_invalid; + + // Honor an explicit 'not retained' attribute. + if (fn->hasAttr<CFReturnsNotRetainedAttr>()) + return ACC_plusZero; + + // Honor an explicit 'retained' attribute, except that for + // now we're not going to permit implicit handling of +1 results, + // because it's a bit frightening. + if (fn->hasAttr<CFReturnsRetainedAttr>()) + return ACC_invalid; // ACC_plusOne if we start accepting this + + // Recognize this specific builtin function, which is used by CFSTR. + unsigned builtinID = fn->getBuiltinID(); + if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) + return ACC_bottom; + + // Otherwise, don't do anything implicit with an unaudited function. + if (!fn->hasAttr<CFAuditedTransferAttr>()) + return ACC_invalid; + + // Otherwise, it's +0 unless it follows the create convention. + if (ento::coreFoundation::followsCreateRule(fn)) + return ACC_invalid; // ACC_plusOne if we start accepting this + + return ACC_plusZero; + } + + ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) { + return checkCallToMethod(e->getMethodDecl()); + } + + ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) { + ObjCMethodDecl *method; + if (e->isExplicitProperty()) + method = e->getExplicitProperty()->getGetterMethodDecl(); + else + method = e->getImplicitPropertyGetter(); + return checkCallToMethod(method); + } + + ACCResult checkCallToMethod(ObjCMethodDecl *method) { + if (!method) return ACC_invalid; + + // Check for message sends to functions returning CF types. We + // just obey the Cocoa conventions with these, even though the + // return type is CF. + if (!isAnyRetainable(TargetClass) || !isCFType(method->getResultType())) + return ACC_invalid; + + // If the method is explicitly marked not-retained, it's +0. + if (method->hasAttr<CFReturnsNotRetainedAttr>()) + return ACC_plusZero; + + // If the method is explicitly marked as returning retained, or its + // selector follows a +1 Cocoa convention, treat it as +1. + if (method->hasAttr<CFReturnsRetainedAttr>()) + return ACC_plusOne; + + switch (method->getSelector().getMethodFamily()) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + return ACC_plusOne; + + default: + // Otherwise, treat it as +0. + return ACC_plusZero; } } - } - - if (MethodReturnsPlusOne) { - TypeSourceInfo *TSInfo = - Context.getTrivialTypeSourceInfo(castType, SourceLocation()); - ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer, - SourceLocation(), TSInfo, Exp); - Exp = ExpRes.take(); - } - return true; + }; } void Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK) { QualType castExprType = castExpr->getType(); + + // For the purposes of the classification, we assume reference types + // will bind to temporaries. + QualType effCastType = castType; + if (const ReferenceType *ref = castType->getAs<ReferenceType>()) + effCastType = ref->getPointeeType(); ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); - ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); + ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); if (exprACTC == castACTC) return; - if (exprACTC && castType->isIntegralType(Context)) return; + if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return; + + // Allow all of these types to be cast to integer types (but not + // vice-versa). + if (castACTC == ACTC_none && castType->isIntegralType(Context)) + return; // Allow casts between pointers to lifetime types (e.g., __strong id*) // and pointers to void (e.g., cv void *). Casting from void* to lifetime* // must be explicit. - if (const PointerType *CastPtr = castType->getAs<PointerType>()) { - if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) { - QualType CastPointee = CastPtr->getPointeeType(); - QualType CastExprPointee = CastExprPtr->getPointeeType(); - if ((CCK != CCK_ImplicitConversion && - CastPointee->isObjCIndirectLifetimeType() && - CastExprPointee->isVoidType()) || - (CastPointee->isVoidType() && - CastExprPointee->isObjCIndirectLifetimeType())) - return; - } - } - - if (ARCCastChecker(Context).Visit(castExpr)) + if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) + return; + if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && + CCK != CCK_ImplicitConversion) return; + + switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) { + // For invalid casts, fall through. + case ACC_invalid: + break; + + // Do nothing for both bottom and +0. + case ACC_bottom: + case ACC_plusZero: + return; + + // If the result is +1, consume it here. + case ACC_plusOne: + castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(), + CK_ARCConsumeObject, castExpr, + 0, VK_RValue); + ExprNeedsCleanups = true; + return; + } SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); + (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); if (makeUnavailableInSystemHeader(loc, - "converts between Objective-C and C pointers in -fobjc-arc")) + "converts between Objective-C and C pointers in -fobjc-arc")) return; unsigned srcKind = 0; switch (exprACTC) { - case ACTC_none: - srcKind = (castExprType->isPointerType() ? 1 : 0); - break; - case ACTC_retainable: - srcKind = (castExprType->isBlockPointerType() ? 2 : 3); - break; - case ACTC_indirectRetainable: - srcKind = 4; - break; + case ACTC_none: + case ACTC_coreFoundation: + case ACTC_voidPtr: + srcKind = (castExprType->isPointerType() ? 1 : 0); + break; + case ACTC_retainable: + srcKind = (castExprType->isBlockPointerType() ? 2 : 3); + break; + case ACTC_indirectRetainable: + srcKind = 4; + break; } if (CCK == CCK_CStyleCast) { @@ -1735,12 +1910,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin()); SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc; - if (castType->isObjCARCBridgableType() && - castExprType->isCARCBridgableType()) { - // explicit unbridged casts are allowed if the source of the cast is a - // message sent to an objc method (or property access) - if (ValidObjCARCNoBridgeCastExpr(castExpr, castType)) - return; + if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { Diag(loc, diag::err_arc_cast_requires_bridge) << 2 << castExprType @@ -1757,8 +1927,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, return; } - if (castType->isCARCBridgableType() && - castExprType->isObjCARCBridgableType()){ + if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { Diag(loc, diag::err_arc_cast_requires_bridge) << (castExprType->isBlockPointerType()? 1 : 0) << castExprType @@ -1806,7 +1975,7 @@ static Expr *maybeUndoReclaimObject(Expr *e) { // value-propagating subexpressions --- we can't reliably rebuild // in-place because of expression sharing. if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) - if (ice->getCastKind() == CK_ObjCReclaimReturnedObject) + if (ice->getCastKind() == CK_ARCReclaimReturnedObject) return ice->getSubExpr(); return e; @@ -1817,14 +1986,23 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr) { + ExprResult SubResult = UsualUnaryConversions(SubExpr); + if (SubResult.isInvalid()) return ExprError(); + SubExpr = SubResult.take(); + QualType T = TSInfo->getType(); QualType FromType = SubExpr->getType(); + CastKind CK; + bool MustConsume = false; if (T->isDependentType() || SubExpr->isTypeDependent()) { // Okay: we'll build a dependent expression type. + CK = CK_Dependent; } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) { // Casting CF -> id + CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast + : CK_CPointerToObjCPointerCast); switch (Kind) { case OBC_Bridge: break; @@ -1854,6 +2032,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, } } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) { // Okay: id -> CF + CK = CK_BitCast; switch (Kind) { case OBC_Bridge: // Reclaiming a value that's going to be __bridge-casted to CF @@ -1864,7 +2043,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, case OBC_BridgeRetained: // Produce the object before casting it. SubExpr = ImplicitCastExpr::Create(Context, FromType, - CK_ObjCProduceObject, + CK_ARCProduceObject, SubExpr, 0, VK_RValue); break; @@ -1894,13 +2073,13 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, return ExprError(); } - Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, + Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK, BridgeKeywordLoc, TSInfo, SubExpr); if (MustConsume) { ExprNeedsCleanups = true; - Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result, + Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result, 0, VK_RValue); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp new file mode 100644 index 0000000..8e8a46d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp @@ -0,0 +1,160 @@ +//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaFixItUtils.h" + +using namespace clang; + +bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + if (!To.isAtLeastAsQualifiedAs(From)) + return false; + + From = From.getNonReferenceType(); + To = To.getNonReferenceType(); + + // If both are pointer types, work with the pointee types. + if (isa<PointerType>(From) && isa<PointerType>(To)) { + From = S.Context.getCanonicalType( + (cast<PointerType>(From))->getPointeeType()); + To = S.Context.getCanonicalType( + (cast<PointerType>(To))->getPointeeType()); + } + + const CanQualType FromUnq = From.getUnqualifiedType(); + const CanQualType ToUnq = To.getUnqualifiedType(); + + if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) && + To.isAtLeastAsQualifiedAs(From)) + return true; + return false; +} + +bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, + const QualType FromTy, + const QualType ToTy, + Sema &S) { + if (!FullExpr) + return false; + + const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); + const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); + const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); + const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange() + .getEnd()); + + // Strip the implicit casts - those are implied by the compiler, not the + // original source code. + const Expr* Expr = FullExpr->IgnoreImpCasts(); + + bool NeedParen = true; + if (isa<ArraySubscriptExpr>(Expr) || + isa<CallExpr>(Expr) || + isa<DeclRefExpr>(Expr) || + isa<CastExpr>(Expr) || + isa<CXXNewExpr>(Expr) || + isa<CXXConstructExpr>(Expr) || + isa<CXXDeleteExpr>(Expr) || + isa<CXXNoexceptExpr>(Expr) || + isa<CXXPseudoDestructorExpr>(Expr) || + isa<CXXScalarValueInitExpr>(Expr) || + isa<CXXThisExpr>(Expr) || + isa<CXXTypeidExpr>(Expr) || + isa<CXXUnresolvedConstructExpr>(Expr) || + isa<ObjCMessageExpr>(Expr) || + isa<ObjCPropertyRefExpr>(Expr) || + isa<ObjCProtocolExpr>(Expr) || + isa<MemberExpr>(Expr) || + isa<ParenExpr>(FullExpr) || + isa<ParenListExpr>(Expr) || + isa<SizeOfPackExpr>(Expr) || + isa<UnaryOperator>(Expr)) + NeedParen = false; + + // Check if the argument needs to be dereferenced: + // (type * -> type) or (type * -> type &). + if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { + OverloadFixItKind FixKind = OFIK_Dereference; + + bool CanConvert = CompareTypes( + S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, + S, Begin, VK_LValue); + if (CanConvert) { + // Do not suggest dereferencing a Null pointer. + if (Expr->IgnoreParenCasts()-> + isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) + return false; + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_AddrOf) { + FixKind = OFIK_RemoveTakeAddress; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + // Check if the pointer to the argument needs to be passed: + // (type -> type *) or (type & -> type *). + if (isa<PointerType>(ToQTy)) { + bool CanConvert = false; + OverloadFixItKind FixKind = OFIK_TakeAddress; + + // Only suggest taking address of L-values. + if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) + return false; + + CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, + S, Begin, VK_RValue); + if (CanConvert) { + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_Deref) { + FixKind = OFIK_RemoveDereference; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index 9fbcbab..7ed3fa8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -7,9 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for initializers. The main entry -// point is Sema::CheckInitList(), but all of the work is performed -// within the InitListChecker class. +// This file implements semantic analysis for initializers. // //===----------------------------------------------------------------------===// @@ -24,6 +22,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include <map> using namespace clang; @@ -48,20 +47,30 @@ static Expr *IsStringInit(Expr *Init, const ArrayType *AT, if (SL == 0) return 0; QualType ElemTy = Context.getCanonicalType(AT->getElementType()); - // char array can be initialized with a narrow string. - // Only allow char x[] = "foo"; not char x[] = L"foo"; - if (!SL->isWide()) + + switch (SL->getKind()) { + case StringLiteral::Ascii: + case StringLiteral::UTF8: + // char array can be initialized with a narrow string. + // Only allow char x[] = "foo"; not char x[] = L"foo"; return ElemTy->isCharType() ? Init : 0; + case StringLiteral::UTF16: + return ElemTy->isChar16Type() ? Init : 0; + case StringLiteral::UTF32: + return ElemTy->isChar32Type() ? Init : 0; + case StringLiteral::Wide: + // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with + // correction from DR343): "An array with element type compatible with a + // qualified or unqualified version of wchar_t may be initialized by a wide + // string literal, optionally enclosed in braces." + if (Context.typesAreCompatible(Context.getWCharType(), + ElemTy.getUnqualifiedType())) + return Init; - // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with - // correction from DR343): "An array with element type compatible with a - // qualified or unqualified version of wchar_t may be initialized by a wide - // string literal, optionally enclosed in braces." - if (Context.typesAreCompatible(Context.getWCharType(), - ElemTy.getUnqualifiedType())) - return Init; + return 0; + } - return 0; + llvm_unreachable("missed a StringLiteral kind?"); } static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { @@ -160,14 +169,14 @@ namespace { class InitListChecker { Sema &SemaRef; bool hadError; + bool VerifyOnly; // no diagnostics, no structure building std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; void CheckImplicitInitList(const InitializedEntity &Entity, InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, - bool TopLevelObject = false); + unsigned &StructuredIndex); void CheckExplicitInitList(const InitializedEntity &Entity, InitListExpr *IList, QualType &T, unsigned &Index, InitListExpr *StructuredList, @@ -185,6 +194,11 @@ class InitListChecker { unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); + void CheckComplexType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); void CheckScalarType(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, unsigned &Index, @@ -239,9 +253,12 @@ class InitListChecker { InitListExpr *ILE, bool &RequiresSecondPass); void FillInValueInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass); + bool CheckFlexibleArrayInit(const InitializedEntity &Entity, + Expr *InitExpr, FieldDecl *Field, + bool TopLevelObject); public: InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T); + InitListExpr *IL, QualType &T, bool VerifyOnly); bool HadError() { return hadError; } // @brief Retrieves the fully-structured initializer list used for @@ -434,8 +451,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T) - : SemaRef(S) { + InitListExpr *IL, QualType &T, + bool VerifyOnly) + : SemaRef(S), VerifyOnly(VerifyOnly) { hadError = false; unsigned newIndex = 0; @@ -446,7 +464,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); - if (!hadError) { + if (!hadError && !VerifyOnly) { bool RequiresSecondPass = false; FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); if (RequiresSecondPass && !hadError) @@ -472,7 +490,7 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { Field = structDecl->field_begin(), FieldEnd = structDecl->field_end(); Field != FieldEnd; ++Field) { - if ((*Field)->getIdentifier() || !(*Field)->isBitField()) + if (!Field->isUnnamedBitfield()) ++InitializableMembers; } if (structDecl->isUnion()) @@ -484,8 +502,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, - bool TopLevelObject) { + unsigned &StructuredIndex) { int maxElements = 0; if (T->isArrayType()) @@ -495,11 +512,12 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, else if (T->isVectorType()) maxElements = T->getAs<VectorType>()->getNumElements(); else - assert(0 && "CheckImplicitInitList(): Illegal type"); + llvm_unreachable("CheckImplicitInitList(): Illegal type"); if (maxElements == 0) { - SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), - diag::err_implicit_empty_initializer); + if (!VerifyOnly) + SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), + diag::err_implicit_empty_initializer); ++Index; hadError = true; return; @@ -518,29 +536,31 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, CheckListElementTypes(Entity, ParentIList, T, /*SubobjectIsDesignatorContext=*/false, Index, StructuredSubobjectInitList, - StructuredSubobjectInitIndex, - TopLevelObject); + StructuredSubobjectInitIndex); unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); - StructuredSubobjectInitList->setType(T); - - // Update the structured sub-object initializer so that it's ending - // range corresponds with the end of the last initializer it used. - if (EndIndex < ParentIList->getNumInits()) { - SourceLocation EndLoc - = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); - StructuredSubobjectInitList->setRBraceLoc(EndLoc); - } - - // Warn about missing braces. - if (T->isArrayType() || T->isRecordType()) { - SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), - diag::warn_missing_braces) - << StructuredSubobjectInitList->getSourceRange() - << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), - "{") - << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( + if (!VerifyOnly) { + StructuredSubobjectInitList->setType(T); + + // Update the structured sub-object initializer so that it's ending + // range corresponds with the end of the last initializer it used. + if (EndIndex < ParentIList->getNumInits()) { + SourceLocation EndLoc + = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); + StructuredSubobjectInitList->setRBraceLoc(EndLoc); + } + + // Warn about missing braces. + if (T->isArrayType() || T->isRecordType()) { + SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), + diag::warn_missing_braces) + << StructuredSubobjectInitList->getSourceRange() + << FixItHint::CreateInsertion( + StructuredSubobjectInitList->getLocStart(), "{") + << FixItHint::CreateInsertion( + SemaRef.PP.getLocForEndOfToken( StructuredSubobjectInitList->getLocEnd()), - "}"); + "}"); + } } } @@ -551,18 +571,31 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, unsigned &StructuredIndex, bool TopLevelObject) { assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); - SyntacticToSemantic[IList] = StructuredList; - StructuredList->setSyntacticForm(IList); + if (!VerifyOnly) { + SyntacticToSemantic[IList] = StructuredList; + StructuredList->setSyntacticForm(IList); + } CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); - QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); - IList->setType(ExprTy); - StructuredList->setType(ExprTy); + if (!VerifyOnly) { + QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); + IList->setType(ExprTy); + StructuredList->setType(ExprTy); + } if (hadError) return; if (Index < IList->getNumInits()) { // We have leftover initializers + if (VerifyOnly) { + if (SemaRef.getLangOptions().CPlusPlus || + (SemaRef.getLangOptions().OpenCL && + IList->getType()->isVectorType())) { + hadError = true; + } + return; + } + if (StructuredIndex == 1 && IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) { unsigned DK = diag::warn_excess_initializers_in_char_array_initializer; @@ -599,7 +632,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, } } - if (T->isScalarType() && !TopLevelObject) + if (!VerifyOnly && T->isScalarType() && IList->getNumInits() == 1 && + !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() << FixItHint::CreateRemoval(IList->getLocStart()) @@ -614,7 +648,12 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { - if (DeclType->isScalarType()) { + if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) { + // Explicitly braced initializer for complex type can be real+imaginary + // parts. + CheckComplexType(Entity, IList, DeclType, Index, + StructuredList, StructuredIndex); + } else if (DeclType->isScalarType()) { CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { @@ -635,12 +674,13 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); } else - assert(0 && "Aggregate that isn't a structure or array?!"); + llvm_unreachable("Aggregate that isn't a structure or array?!"); } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { // This type is invalid, issue a diagnostic. ++Index; - SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; hadError = true; } else if (DeclType->isRecordType()) { // C++ [dcl.init]p14: @@ -651,19 +691,22 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, // we have an initializer list and a destination type that is not // an aggregate. // FIXME: In C++0x, this is yet another form of initialization. - SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) - << DeclType << IList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); hadError = true; } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isObjCObjectType()) { - SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) + << DeclType; hadError = true; } else { - SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; hadError = true; } } @@ -701,8 +744,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // type here, though. if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) { - CheckStringInit(Str, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + if (!VerifyOnly) { + CheckStringInit(Str, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + } ++Index; return; } @@ -712,7 +757,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } else if (SemaRef.getLangOptions().CPlusPlus) { // C++ [dcl.init.aggr]p12: // All implicit type conversions (clause 4) are considered when - // initializing the aggregate member with an ini- tializer from + // initializing the aggregate member with an initializer from // an initializer-list. If the initializer can initialize a // member, the member is initialized. [...] @@ -722,13 +767,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); if (Seq) { - ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); - if (Result.isInvalid()) - hadError = true; - - UpdateStructuredListElement(StructuredList, StructuredIndex, - Result.takeAs<Expr>()); + if (!VerifyOnly) { + ExprResult Result = + Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); + if (Result.isInvalid()) + hadError = true; + + UpdateStructuredListElement(StructuredList, StructuredIndex, + Result.takeAs<Expr>()); + } ++Index; return; } @@ -745,7 +792,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // that of the expression. ExprResult ExprRes = SemaRef.Owned(expr); if ((ElemType->isRecordType() || ElemType->isVectorType()) && - SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes) + SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes, + !VerifyOnly) == Sema::Compatible) { if (ExprRes.isInvalid()) hadError = true; @@ -775,25 +823,68 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, StructuredIndex); ++StructuredIndex; } else { - // We cannot initialize this element, so let - // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(Entity, SourceLocation(), - SemaRef.Owned(expr)); + if (!VerifyOnly) { + // We cannot initialize this element, so let + // PerformCopyInitialization produce the appropriate diagnostic. + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); + } hadError = true; ++Index; ++StructuredIndex; } } +void InitListChecker::CheckComplexType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + assert(Index == 0 && "Index in explicit init list must be zero"); + + // As an extension, clang supports complex initializers, which initialize + // a complex number component-wise. When an explicit initializer list for + // a complex number contains two two initializers, this extension kicks in: + // it exepcts the initializer list to contain two elements convertible to + // the element type of the complex type. The first element initializes + // the real part, and the second element intitializes the imaginary part. + + if (IList->getNumInits() != 2) + return CheckScalarType(Entity, IList, DeclType, Index, StructuredList, + StructuredIndex); + + // This is an extension in C. (The builtin _Complex type does not exist + // in the C++ standard.) + if (!SemaRef.getLangOptions().CPlusPlus && !VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init) + << IList->getSourceRange(); + + // Initialize the complex number. + QualType elementType = DeclType->getAs<ComplexType>()->getElementType(); + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + + for (unsigned i = 0; i < 2; ++i) { + ElementEntity.setElementIndex(Index); + CheckSubElementType(ElementEntity, IList, elementType, Index, + StructuredList, StructuredIndex); + } +} + + void InitListChecker::CheckScalarType(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { - SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) - << IList->getSourceRange(); - hadError = true; + if (!SemaRef.getLangOptions().CPlusPlus0x) { + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + hadError = true; + } ++Index; ++StructuredIndex; return; @@ -801,26 +892,36 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, Expr *expr = IList->getInit(Index); if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) { - SemaRef.Diag(SubIList->getLocStart(), - diag::warn_many_braces_around_scalar_init) - << SubIList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(SubIList->getLocStart(), + diag::warn_many_braces_around_scalar_init) + << SubIList->getSourceRange(); CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, StructuredIndex); return; } else if (isa<DesignatedInitExpr>(expr)) { - SemaRef.Diag(expr->getSourceRange().getBegin(), - diag::err_designator_for_scalar_init) - << DeclType << expr->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(expr->getSourceRange().getBegin(), + diag::err_designator_for_scalar_init) + << DeclType << expr->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; return; } + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr))) + hadError = true; + ++Index; + return; + } + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), - SemaRef.Owned(expr)); + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); Expr *ResultExpr = 0; @@ -846,46 +947,57 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { - if (Index < IList->getNumInits()) { - Expr *expr = IList->getInit(Index); - if (isa<InitListExpr>(expr)) { - SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) - << DeclType << IList->getSourceRange(); - hadError = true; - ++Index; - ++StructuredIndex; - return; - } - - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), - SemaRef.Owned(expr)); - - if (Result.isInvalid()) - hadError = true; - - expr = Result.takeAs<Expr>(); - IList->setInit(Index, expr); - - if (hadError) - ++StructuredIndex; - else - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); - ++Index; - } else { + if (Index >= IList->getNumInits()) { // FIXME: It would be wonderful if we could point at the actual member. In // general, it would be useful to pass location information down the stack, // so that we know the location (or decl) of the "current object" being // initialized. - SemaRef.Diag(IList->getLocStart(), - diag::err_init_reference_member_uninitialized) - << DeclType - << IList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), + diag::err_init_reference_member_uninitialized) + << DeclType + << IList->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; return; } + + Expr *expr = IList->getInit(Index); + if (isa<InitListExpr>(expr)) { + // FIXME: Allowed in C++11. + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr))) + hadError = true; + ++Index; + return; + } + + ExprResult Result = + SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); + + if (Result.isInvalid()) + hadError = true; + + expr = Result.takeAs<Expr>(); + IList->setInit(Index, expr); + + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; } void InitListChecker::CheckVectorType(const InitializedEntity &Entity, @@ -906,9 +1018,17 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, // instead of breaking it apart (which is doomed to failure anyway). Expr *Init = IList->getInit(Index); if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) { + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(Init))) + hadError = true; + ++Index; + return; + } + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(), - SemaRef.Owned(Init)); + SemaRef.Owned(Init), + /*TopLevelOfInitList=*/true); Expr *ResultExpr = 0; if (Result.isInvalid()) @@ -924,7 +1044,8 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, if (hadError) ++StructuredIndex; else - UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); + UpdateStructuredListElement(StructuredList, StructuredIndex, + ResultExpr); ++Index; return; } @@ -977,11 +1098,11 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, } // OpenCL requires all elements to be initialized. - if (numEltsInit != maxElements) - if (SemaRef.getLangOptions().OpenCL) - SemaRef.Diag(IList->getSourceRange().getBegin(), - diag::err_vector_incorrect_num_initializers) - << (numEltsInit < maxElements) << maxElements << numEltsInit; + // FIXME: Shouldn't this set hadError to true then? + if (numEltsInit != maxElements && !VerifyOnly) + SemaRef.Diag(IList->getSourceRange().getBegin(), + diag::err_vector_incorrect_num_initializers) + << (numEltsInit < maxElements) << maxElements << numEltsInit; } void InitListChecker::CheckArrayType(const InitializedEntity &Entity, @@ -997,14 +1118,16 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, if (Index < IList->getNumInits()) { if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context)) { - CheckStringInit(Str, DeclType, arrayType, SemaRef); // We place the string literal directly into the resulting // initializer list. This is the only place where the structure // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); - StructuredList->resizeInits(SemaRef.Context, StructuredIndex); + if (!VerifyOnly) { + CheckStringInit(Str, DeclType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + StructuredList->resizeInits(SemaRef.Context, StructuredIndex); + } ++Index; return; } @@ -1013,9 +1136,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for VLAs; in standard C it would be possible to check this // earlier, but I don't know where clang accepts VLAs (gcc accepts // them in all sorts of strange places). - SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), - diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; @@ -1085,7 +1209,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, if (!maxElementsKnown && elementIndex > maxElements) maxElements = elementIndex; } - if (!hadError && DeclType->isIncompleteArrayType()) { + if (!hadError && DeclType->isIncompleteArrayType() && !VerifyOnly) { // If this is an incomplete array type, the actual type needs to // be calculated here. llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned()); @@ -1101,6 +1225,45 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, } } +bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity, + Expr *InitExpr, + FieldDecl *Field, + bool TopLevelObject) { + // Handle GNU flexible array initializers. + unsigned FlexArrayDiag; + if (isa<InitListExpr>(InitExpr) && + cast<InitListExpr>(InitExpr)->getNumInits() == 0) { + // Empty flexible array init always allowed as an extension + FlexArrayDiag = diag::ext_flexible_array_init; + } else if (SemaRef.getLangOptions().CPlusPlus) { + // Disallow flexible array init in C++; it is not required for gcc + // compatibility, and it needs work to IRGen correctly in general. + FlexArrayDiag = diag::err_flexible_array_init; + } else if (!TopLevelObject) { + // Disallow flexible array init on non-top-level object + FlexArrayDiag = diag::err_flexible_array_init; + } else if (Entity.getKind() != InitializedEntity::EK_Variable) { + // Disallow flexible array init on anything which is not a variable. + FlexArrayDiag = diag::err_flexible_array_init; + } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) { + // Disallow flexible array init on local variables. + FlexArrayDiag = diag::err_flexible_array_init; + } else { + // Allow other cases. + FlexArrayDiag = diag::ext_flexible_array_init; + } + + if (!VerifyOnly) { + SemaRef.Diag(InitExpr->getSourceRange().getBegin(), + FlexArrayDiag) + << InitExpr->getSourceRange().getBegin(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << Field; + } + + return FlexArrayDiag != diag::ext_flexible_array_init; +} + void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, @@ -1120,13 +1283,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - // Value-initialize the first named member of the union. - RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); - for (RecordDecl::field_iterator FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Field->getDeclName()) { - StructuredList->setInitializedFieldInUnion(*Field); - break; + if (!VerifyOnly) { + // Value-initialize the first named member of the union. + RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Field->getDeclName()) { + StructuredList->setInitializedFieldInUnion(*Field); + break; + } } } return; @@ -1186,13 +1351,18 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } // Make sure we can use this declaration. - if (SemaRef.DiagnoseUseOfDecl(*Field, - IList->getInit(Index)->getLocStart())) { + bool InvalidUse; + if (VerifyOnly) + InvalidUse = !SemaRef.CanUseDecl(*Field); + else + InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, + IList->getInit(Index)->getLocStart()); + if (InvalidUse) { ++Index; ++Field; hadError = true; continue; - } + } InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); @@ -1200,7 +1370,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, StructuredList, StructuredIndex); InitializedSomething = true; - if (DeclType->isUnionType()) { + if (DeclType->isUnionType() && !VerifyOnly) { // Initialize the first field within the union. StructuredList->setInitializedFieldInUnion(*Field); } @@ -1209,8 +1379,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } // Emit warnings for missing struct field initializers. - if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && - !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { + if (!VerifyOnly && InitializedSomething && CheckForMissingFields && + Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && + !DeclType->isUnionType()) { // It is possible we have one or more unnamed bitfields remaining. // Find first (if any) named field and emit warning. for (RecordDecl::field_iterator it = Field, end = RD->field_end(); @@ -1227,24 +1398,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, Index >= IList->getNumInits()) return; - // Handle GNU flexible array initializers. - if (!TopLevelObject && - (!isa<InitListExpr>(IList->getInit(Index)) || - cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), - diag::err_flexible_array_init_nonempty) - << IList->getInit(Index)->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field, + TopLevelObject)) { hadError = true; ++Index; return; - } else { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), - diag::ext_flexible_array_init) - << IList->getInit(Index)->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; } InitializedEntity MemberEntity = @@ -1269,7 +1427,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, typedef DesignatedInitExpr::Designator Designator; // Build the replacement designators. - llvm::SmallVector<Designator, 4> Replacements; + SmallVector<Designator, 4> Replacements; for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(), PE = IndirectField->chain_end(); PI != PE; ++PI) { if (PI + 1 == PE) @@ -1304,6 +1462,18 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, return 0; } +static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, + DesignatedInitExpr *DIE) { + unsigned NumIndexExprs = DIE->getNumSubExprs() - 1; + SmallVector<Expr*, 4> IndexExprs(NumIndexExprs); + for (unsigned I = 0; I < NumIndexExprs; ++I) + IndexExprs[I] = DIE->getSubExpr(I + 1); + return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(), + DIE->size(), IndexExprs.data(), + NumIndexExprs, DIE->getEqualOrColonLoc(), + DIE->usesGNUSyntax(), DIE->getInit()); +} + /// @brief Check the well-formedness of a C99 designated initializer. /// /// Determines whether the designated initializer @p DIE, which @@ -1342,14 +1512,14 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, bool InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, InitListExpr *IList, - DesignatedInitExpr *DIE, - unsigned DesigIdx, - QualType &CurrentObjectType, - RecordDecl::field_iterator *NextField, - llvm::APSInt *NextElementIndex, - unsigned &Index, - InitListExpr *StructuredList, - unsigned &StructuredIndex, + DesignatedInitExpr *DIE, + unsigned DesigIdx, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, bool FinishSubobjectInit, bool TopLevelObject) { if (DesigIdx == DIE->size()) { @@ -1374,19 +1544,21 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return hadError && !prevHadError; } - bool IsFirstDesignator = (DesigIdx == 0); - assert((IsFirstDesignator || StructuredList) && - "Need a non-designated initializer list to start from"); - DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); - // Determine the structural initializer list that corresponds to the - // current subobject. - StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] - : getStructuredSubobjectInit(IList, Index, CurrentObjectType, - StructuredList, StructuredIndex, - SourceRange(D->getStartLocation(), - DIE->getSourceRange().getEnd())); - assert(StructuredList && "Expected a structured initializer list"); + bool IsFirstDesignator = (DesigIdx == 0); + if (!VerifyOnly) { + assert((IsFirstDesignator || StructuredList) && + "Need a non-designated initializer list to start from"); + + // Determine the structural initializer list that corresponds to the + // current subobject. + StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] + : getStructuredSubobjectInit(IList, Index, CurrentObjectType, + StructuredList, StructuredIndex, + SourceRange(D->getStartLocation(), + DIE->getSourceRange().getEnd())); + assert(StructuredList && "Expected a structured initializer list"); + } if (D->isFieldDesignator()) { // C99 6.7.8p7: @@ -1403,8 +1575,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, SourceLocation Loc = D->getDotLoc(); if (Loc.isInvalid()) Loc = D->getFieldLoc(); - SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) - << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType; + if (!VerifyOnly) + SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) + << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType; ++Index; return true; } @@ -1427,6 +1600,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (!KnownField && Field->isAnonymousStructOrUnion()) { if (IndirectFieldDecl *IF = FindIndirectFieldDesignator(*Field, FieldName)) { + // In verify mode, don't modify the original. + if (VerifyOnly) + DIE = CloneDesignatedInitExpr(SemaRef, DIE); ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF); D = DIE->getDesignator(DesigIdx); break; @@ -1441,6 +1617,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } if (Field == FieldEnd) { + if (VerifyOnly) { + ++Index; + return true; // No typo correction when just trying this out. + } + // There was no normal field in the struct with the designated // name. Perform another lookup for this name, which may find // something that we can't designate (e.g., a member function), @@ -1470,6 +1651,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr); SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; + hadError = true; } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; @@ -1510,22 +1692,30 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // the initializer list. if (RT->getDecl()->isUnion()) { FieldIndex = 0; - StructuredList->setInitializedFieldInUnion(*Field); + if (!VerifyOnly) + StructuredList->setInitializedFieldInUnion(*Field); } // Make sure we can use this declaration. - if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) { + bool InvalidUse; + if (VerifyOnly) + InvalidUse = !SemaRef.CanUseDecl(*Field); + else + InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc()); + if (InvalidUse) { ++Index; return true; - } + } - // Update the designator with the field declaration. - D->setField(*Field); + if (!VerifyOnly) { + // Update the designator with the field declaration. + D->setField(*Field); - // Make sure that our non-designated initializer list has space - // for a subobject corresponding to this field. - if (FieldIndex >= StructuredList->getNumInits()) - StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this field. + if (FieldIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + } // This designator names a flexible array member. if (Field->getType()->isIncompleteArrayType()) { @@ -1533,38 +1723,36 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if ((DesigIdx + 1) != DIE->size()) { // We can't designate an object within the flexible array // member (because GCC doesn't allow it). - DesignatedInitExpr::Designator *NextD - = DIE->getDesignator(DesigIdx + 1); - SemaRef.Diag(NextD->getStartLocation(), - diag::err_designator_into_flexible_array_member) - << SourceRange(NextD->getStartLocation(), - DIE->getSourceRange().getEnd()); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (!VerifyOnly) { + DesignatedInitExpr::Designator *NextD + = DIE->getDesignator(DesigIdx + 1); + SemaRef.Diag(NextD->getStartLocation(), + diag::err_designator_into_flexible_array_member) + << SourceRange(NextD->getStartLocation(), + DIE->getSourceRange().getEnd()); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + } Invalid = true; } if (!hadError && !isa<InitListExpr>(DIE->getInit()) && !isa<StringLiteral>(DIE->getInit())) { // The initializer is not an initializer list. - SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), - diag::err_flexible_array_init_needs_braces) - << DIE->getInit()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (!VerifyOnly) { + SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), + diag::err_flexible_array_init_needs_braces) + << DIE->getInit()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + } Invalid = true; } - // Handle GNU flexible array initializers. - if (!Invalid && !TopLevelObject && - cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) { - SemaRef.Diag(DIE->getSourceRange().getBegin(), - diag::err_flexible_array_init_nonempty) - << DIE->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + // Check GNU flexible array initializer. + if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field, + TopLevelObject)) Invalid = true; - } if (Invalid) { ++Index; @@ -1651,8 +1839,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // [ constant-expression ... constant-expression ] const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType); if (!AT) { - SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) - << CurrentObjectType; + if (!VerifyOnly) + SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) + << CurrentObjectType; ++Index; return true; } @@ -1661,15 +1850,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, llvm::APSInt DesignatedStartIndex, DesignatedEndIndex; if (D->isArrayDesignator()) { IndexExpr = DIE->getArrayIndex(*D); - DesignatedStartIndex = IndexExpr->EvaluateAsInt(SemaRef.Context); + DesignatedStartIndex = IndexExpr->EvaluateKnownConstInt(SemaRef.Context); DesignatedEndIndex = DesignatedStartIndex; } else { assert(D->isArrayRangeDesignator() && "Need array-range designator"); DesignatedStartIndex = - DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context); + DIE->getArrayRangeStart(*D)->EvaluateKnownConstInt(SemaRef.Context); DesignatedEndIndex = - DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context); + DIE->getArrayRangeEnd(*D)->EvaluateKnownConstInt(SemaRef.Context); IndexExpr = DIE->getArrayRangeEnd(*D); // Codegen can't handle evaluating array range designators that have side @@ -1678,7 +1867,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // elements with something that has a side effect, so codegen can emit an // "error unsupported" error instead of miscompiling the app. if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&& - DIE->getInit()->HasSideEffects(SemaRef.Context)) + DIE->getInit()->HasSideEffects(SemaRef.Context) && !VerifyOnly) FullyStructuredList->sawArrayRangeDesignator(); } @@ -1691,10 +1880,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, = DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned()); if (DesignatedEndIndex >= MaxElements) { - SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), - diag::err_array_designator_too_large) - << DesignatedEndIndex.toString(10) << MaxElements.toString(10) - << IndexExpr->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), + diag::err_array_designator_too_large) + << DesignatedEndIndex.toString(10) << MaxElements.toString(10) + << IndexExpr->getSourceRange(); ++Index; return true; } @@ -1713,7 +1903,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Make sure that our non-designated initializer list has space // for a subobject corresponding to this array element. - if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) + if (!VerifyOnly && + DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) StructuredList->resizeInits(SemaRef.Context, DesignatedEndIndex.getZExtValue() + 1); @@ -1773,6 +1964,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, InitListExpr *StructuredList, unsigned StructuredIndex, SourceRange InitRange) { + if (VerifyOnly) + return 0; // No structured list in verification-only mode. Expr *ExistingInit = 0; if (!StructuredList) ExistingInit = SyntacticToSemantic[IList]; @@ -1844,9 +2037,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, RDecl->field_end()); } - if (NumElements < NumInits) - NumElements = IList->getNumInits(); - Result->reserveInits(SemaRef.Context, NumElements); // Link this new initializer list into the structured initializer @@ -1915,8 +2105,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, typedef DesignatedInitExpr::Designator ASTDesignator; bool Invalid = false; - llvm::SmallVector<ASTDesignator, 32> Designators; - llvm::SmallVector<Expr *, 32> InitExpressions; + SmallVector<ASTDesignator, 32> Designators; + SmallVector<Expr *, 32> InitExpressions; // Build designators and check array designator expressions. for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) { @@ -2007,15 +2197,6 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, return Owned(DIE); } -bool Sema::CheckInitList(const InitializedEntity &Entity, - InitListExpr *&InitList, QualType &DeclType) { - InitListChecker CheckInitList(*this, Entity, InitList, DeclType); - if (!CheckInitList.HadError()) - InitList = CheckInitList.getFullyStructuredList(); - - return CheckInitList.HadError(); -} - //===----------------------------------------------------------------------===// // Initialization entity //===----------------------------------------------------------------------===// @@ -2027,9 +2208,14 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { Kind = EK_ArrayElement; Type = AT->getElementType(); - } else { + } else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) { Kind = EK_VectorElement; - Type = Parent.getType()->getAs<VectorType>()->getElementType(); + Type = VT->getElementType(); + } else { + const ComplexType *CT = Parent.getType()->getAs<ComplexType>(); + assert(CT && "Unexpected type"); + Kind = EK_ComplexElement; + Type = CT->getElementType(); } } @@ -2066,6 +2252,7 @@ DeclarationName InitializedEntity::getName() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return DeclarationName(); } @@ -2091,6 +2278,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return 0; } @@ -2114,6 +2302,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: break; } @@ -2139,6 +2328,7 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionXValue: case SK_QualificationConversionLValue: case SK_ListInitialization: + case SK_ListConstructorCall: case SK_ConstructorInitialization: case SK_ZeroInitialization: case SK_CAssignment: @@ -2182,6 +2372,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_Incomplete: case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: + case FK_ListInitializationFailed: return false; case FK_ReferenceInitOverloadFailed: @@ -2197,12 +2388,171 @@ bool InitializationSequence::isConstructorInitialization() const { return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization; } +bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx, + const Expr *Initializer, + bool *isInitializerConstant, + APValue *ConstantValue) const { + if (Steps.empty() || Initializer->isValueDependent()) + return false; + + const Step &LastStep = Steps.back(); + if (LastStep.Kind != SK_ConversionSequence) + return false; + + const ImplicitConversionSequence &ICS = *LastStep.ICS; + const StandardConversionSequence *SCS = NULL; + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + SCS = &ICS.Standard; + break; + case ImplicitConversionSequence::UserDefinedConversion: + SCS = &ICS.UserDefined.After; + break; + case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + return false; + } + + // Check if SCS represents a narrowing conversion, according to C++0x + // [dcl.init.list]p7: + // + // A narrowing conversion is an implicit conversion ... + ImplicitConversionKind PossibleNarrowing = SCS->Second; + QualType FromType = SCS->getToType(0); + QualType ToType = SCS->getToType(1); + switch (PossibleNarrowing) { + // * from a floating-point type to an integer type, or + // + // * from an integer type or unscoped enumeration type to a floating-point + // type, except where the source is a constant expression and the actual + // value after conversion will fit into the target type and will produce + // the original value when converted back to the original type, or + case ICK_Floating_Integral: + if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) { + *isInitializerConstant = false; + return true; + } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) { + llvm::APSInt IntConstantValue; + if (Initializer && + Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) { + // Convert the integer to the floating type. + llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType)); + Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(), + llvm::APFloat::rmNearestTiesToEven); + // And back. + llvm::APSInt ConvertedValue = IntConstantValue; + bool ignored; + Result.convertToInteger(ConvertedValue, + llvm::APFloat::rmTowardZero, &ignored); + // If the resulting value is different, this was a narrowing conversion. + if (IntConstantValue != ConvertedValue) { + *isInitializerConstant = true; + *ConstantValue = APValue(IntConstantValue); + return true; + } + } else { + // Variables are always narrowings. + *isInitializerConstant = false; + return true; + } + } + return false; + + // * from long double to double or float, or from double to float, except + // where the source is a constant expression and the actual value after + // conversion is within the range of values that can be represented (even + // if it cannot be represented exactly), or + case ICK_Floating_Conversion: + if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) { + // FromType is larger than ToType. + Expr::EvalResult InitializerValue; + // FIXME: Check whether Initializer is a constant expression according + // to C++0x [expr.const], rather than just whether it can be folded. + if (Initializer->Evaluate(InitializerValue, Ctx) && + !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) { + // Constant! (Except for FIXME above.) + llvm::APFloat FloatVal = InitializerValue.Val.getFloat(); + // Convert the source value into the target type. + bool ignored; + llvm::APFloat::opStatus ConvertStatus = FloatVal.convert( + Ctx.getFloatTypeSemantics(ToType), + llvm::APFloat::rmNearestTiesToEven, &ignored); + // If there was no overflow, the source value is within the range of + // values that can be represented. + if (ConvertStatus & llvm::APFloat::opOverflow) { + *isInitializerConstant = true; + *ConstantValue = InitializerValue.Val; + return true; + } + } else { + *isInitializerConstant = false; + return true; + } + } + return false; + + // * from an integer type or unscoped enumeration type to an integer type + // that cannot represent all the values of the original type, except where + // the source is a constant expression and the actual value after + // conversion will fit into the target type and will produce the original + // value when converted back to the original type. + case ICK_Boolean_Conversion: // Bools are integers too. + if (!FromType->isIntegralOrUnscopedEnumerationType()) { + // Boolean conversions can be from pointers and pointers to members + // [conv.bool], and those aren't considered narrowing conversions. + return false; + } // Otherwise, fall through to the integral case. + case ICK_Integral_Conversion: { + assert(FromType->isIntegralOrUnscopedEnumerationType()); + assert(ToType->isIntegralOrUnscopedEnumerationType()); + const bool FromSigned = FromType->isSignedIntegerOrEnumerationType(); + const unsigned FromWidth = Ctx.getIntWidth(FromType); + const bool ToSigned = ToType->isSignedIntegerOrEnumerationType(); + const unsigned ToWidth = Ctx.getIntWidth(ToType); + + if (FromWidth > ToWidth || + (FromWidth == ToWidth && FromSigned != ToSigned)) { + // Not all values of FromType can be represented in ToType. + llvm::APSInt InitializerValue; + if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) { + *isInitializerConstant = true; + *ConstantValue = APValue(InitializerValue); + + // Add a bit to the InitializerValue so we don't have to worry about + // signed vs. unsigned comparisons. + InitializerValue = InitializerValue.extend( + InitializerValue.getBitWidth() + 1); + // Convert the initializer to and from the target width and signed-ness. + llvm::APSInt ConvertedValue = InitializerValue; + ConvertedValue = ConvertedValue.trunc(ToWidth); + ConvertedValue.setIsSigned(ToSigned); + ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth()); + ConvertedValue.setIsSigned(InitializerValue.isSigned()); + // If the result is different, this was a narrowing conversion. + return ConvertedValue != InitializerValue; + } else { + // Variables are always narrowings. + *isInitializerConstant = false; + return true; + } + } + return false; + } + + default: + // Other kinds of conversions are not narrowings. + return false; + } +} + void InitializationSequence::AddAddressOverloadResolutionStep( FunctionDecl *Function, DeclAccessPair Found) { Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); + S.Function.HadMultipleCandidates = false; S.Function.Function = Function; S.Function.FoundDecl = Found; Steps.push_back(S); @@ -2242,6 +2592,7 @@ void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, Step S; S.Kind = SK_UserConversion; S.Type = T; + S.Function.HadMultipleCandidates = false; S.Function.Function = Function; S.Function.FoundDecl = FoundDecl; Steps.push_back(S); @@ -2291,6 +2642,7 @@ InitializationSequence::AddConstructorInitializationStep( Step S; S.Kind = SK_ConstructorInitialization; S.Type = T; + S.Function.HadMultipleCandidates = false; S.Function.Function = Constructor; S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access); Steps.push_back(S); @@ -2391,44 +2743,33 @@ static void TryListInitialization(Sema &S, const InitializationKind &Kind, InitListExpr *InitList, InitializationSequence &Sequence) { - // FIXME: We only perform rudimentary checking of list - // initializations at this point, then assume that any list - // initialization of an array, aggregate, or scalar will be - // well-formed. When we actually "perform" list initialization, we'll - // do all of the necessary checking. C++0x initializer lists will - // force us to perform more checking here. - QualType DestType = Entity.getType(); - // C++ [dcl.init]p13: - // If T is a scalar type, then a declaration of the form - // - // T x = { a }; - // - // is equivalent to - // - // T x = a; - if (DestType->isScalarType()) { - if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) { - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); - return; - } - - // Assume scalar initialization from a single value works. - } else if (DestType->isAggregateType()) { - // Assume aggregate initialization works. - } else if (DestType->isVectorType()) { - // Assume vector initialization works. - } else if (DestType->isReferenceType()) { - // FIXME: C++0x defines behavior for this. + // C++ doesn't allow scalar initialization with more than one argument. + // But C99 complex numbers are scalars and it makes sense there. + if (S.getLangOptions().CPlusPlus && DestType->isScalarType() && + !DestType->isAnyComplexType() && InitList->getNumInits() > 1) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + return; + } + // FIXME: C++0x defines behavior for these two cases. + if (DestType->isReferenceType()) { Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); return; - } else if (DestType->isRecordType()) { - // FIXME: C++0x defines behavior for this + } + if (DestType->isRecordType() && !DestType->isAggregateType()) { Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + return; } - // Add a general "list initialization" step. + InitListChecker CheckInitList(S, Entity, InitList, + DestType, /*VerifyOnly=*/true); + if (CheckInitList.HadError()) { + Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed); + return; + } + + // Add the list initialization step with the built init list. Sequence.AddListInitializationStep(DestType); } @@ -2767,7 +3108,7 @@ static void TryReferenceInitialization(Sema &S, // // The constructor that would be used to make the copy shall // be callable whether or not the copy is actually done. - if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft) + if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt) Sequence.AddExtraneousCopyToTemporary(cv2T2); } @@ -2887,6 +3228,14 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { + // Check constructor arguments for self reference. + if (DeclaratorDecl *DD = Entity.getDecl()) + // Parameters arguments are occassionially constructed with itself, + // for instance, in recursive functions. Skip them. + if (!isa<ParmVarDecl>(DD)) + for (unsigned i = 0; i < NumArgs; ++i) + S.CheckSelfReference(DD, Args[i]); + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -3577,7 +3926,7 @@ InitializationSequence::InitializationSequence(Sema &S, } InitializationSequence::~InitializationSequence() { - for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(), + for (SmallVectorImpl<Step>::iterator Step = Steps.begin(), StepEnd = Steps.end(); Step != StepEnd; ++Step) Step->Destroy(); @@ -3613,6 +3962,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_Member: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: return Sema::AA_Initializing; } @@ -3632,6 +3982,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: return false; @@ -3654,6 +4005,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: return false; @@ -3739,6 +4091,7 @@ static ExprResult CopyObject(Sema &S, case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart(); break; @@ -3790,6 +4143,8 @@ static ExprResult CopyObject(Sema &S, &CurInitExpr, 1, CandidateSet, true); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, Loc, Best)) { case OR_Success: @@ -3867,6 +4222,7 @@ static ExprResult CopyObject(Sema &S, // Actually perform the constructor call. CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -3982,6 +4338,7 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionXValue: case SK_QualificationConversionRValue: case SK_ConversionSequence: + case SK_ListConstructorCall: case SK_ListInitialization: case SK_CAssignment: case SK_StringInit: @@ -4127,8 +4484,8 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; bool CreatedObject = false; - bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); @@ -4146,6 +4503,7 @@ InitializationSequence::Perform(Sema &S, // Build the an expression that constructs a temporary. CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -4166,7 +4524,6 @@ InitializationSequence::Perform(Sema &S, } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); - IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0, FoundFn); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); @@ -4182,7 +4539,8 @@ InitializationSequence::Perform(Sema &S, CurInit = move(CurInitExprRes); // Build the actual call to the conversion function. - CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion); + CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion, + HadMultipleCandidates); if (CurInit.isInvalid() || !CurInit.get()) return ExprError(); @@ -4206,11 +4564,10 @@ InitializationSequence::Perform(Sema &S, } } - // FIXME: xvalues CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), CastKind, CurInit.get(), 0, - IsLvalue ? VK_LValue : VK_RValue)); + CurInit.get()->getValueKind())); if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, @@ -4251,18 +4608,24 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); QualType Ty = Step->Type; - if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty)) + InitListChecker PerformInitList(S, Entity, InitList, + ResultType ? *ResultType : Ty, /*VerifyOnly=*/false); + if (PerformInitList.HadError()) return ExprError(); CurInit.release(); - CurInit = S.Owned(InitList); + CurInit = S.Owned(PerformInitList.getFullyStructuredList()); break; } + case SK_ListConstructorCall: + assert(false && "List constructor calls not yet supported."); + case SK_ConstructorInitialization: { unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); + bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); @@ -4309,6 +4672,7 @@ InitializationSequence::Perform(Sema &S, Exprs, NumExprs, Kind.getParenRange(), + HadMultipleCandidates, ConstructorInitRequiresZeroInit)); } else { CXXConstructExpr::ConstructionKind ConstructKind = @@ -4333,6 +4697,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, /*Elidable=*/true, move_arg(ConstructorArgs), + HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, parenRange); @@ -4340,6 +4705,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, move_arg(ConstructorArgs), + HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, parenRange); @@ -4427,7 +4793,7 @@ InitializationSequence::Perform(Sema &S, case SK_ObjCObjectConversion: CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_ObjCObjectLValueCast, - S.CastCategory(CurInit.get())); + CurInit.get()->getValueKind()); break; case SK_ArrayInit: @@ -4463,7 +4829,7 @@ InitializationSequence::Perform(Sema &S, case SK_ProduceObjCObject: CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type, - CK_ObjCProduceObject, + CK_ARCProduceObject, CurInit.take(), 0, VK_RValue)); break; } @@ -4759,17 +5125,28 @@ bool InitializationSequence::Diagnose(Sema &S, } break; - case FK_Incomplete: - S.RequireCompleteType(Kind.getLocation(), DestType, - diag::err_init_incomplete_type); - break; + case FK_Incomplete: + S.RequireCompleteType(Kind.getLocation(), DestType, + diag::err_init_incomplete_type); + break; + + case FK_ListInitializationFailed: { + // Run the init list checker again to emit diagnostics. + InitListExpr* InitList = cast<InitListExpr>(Args[0]); + QualType DestType = Entity.getType(); + InitListChecker DiagnoseInitList(S, Entity, InitList, + DestType, /*VerifyOnly=*/false); + assert(DiagnoseInitList.HadError() && + "Inconsistent init list check result."); + break; + } } PrintInitLocationNote(S, Entity); return true; } -void InitializationSequence::dump(llvm::raw_ostream &OS) const { +void InitializationSequence::dump(raw_ostream &OS) const { switch (SequenceKind) { case FailedSequence: { OS << "Failed sequence: "; @@ -4857,6 +5234,9 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case FK_Incomplete: OS << "initialization of incomplete type"; break; + + case FK_ListInitializationFailed: + OS << "list initialization checker failure"; } OS << '\n'; return; @@ -4906,7 +5286,7 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_UserConversion: - OS << "user-defined conversion via " << S->Function.Function; + OS << "user-defined conversion via " << *S->Function.Function; break; case SK_QualificationConversionRValue: @@ -4926,7 +5306,11 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_ListInitialization: - OS << "list initialization"; + OS << "list aggregate initialization"; + break; + + case SK_ListConstructorCall: + OS << "list initialization via constructor"; break; case SK_ConstructorInitialization: @@ -4972,6 +5356,51 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } +static void DiagnoseNarrowingInInitList( + Sema& S, QualType EntityType, const Expr *InitE, + bool Constant, const APValue &ConstantValue) { + if (Constant) { + S.Diag(InitE->getLocStart(), + S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt + ? diag::err_init_list_constant_narrowing + : diag::warn_init_list_constant_narrowing) + << InitE->getSourceRange() + << ConstantValue + << EntityType.getLocalUnqualifiedType(); + } else + S.Diag(InitE->getLocStart(), + S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt + ? diag::err_init_list_variable_narrowing + : diag::warn_init_list_variable_narrowing) + << InitE->getSourceRange() + << InitE->getType().getLocalUnqualifiedType() + << EntityType.getLocalUnqualifiedType(); + + llvm::SmallString<128> StaticCast; + llvm::raw_svector_ostream OS(StaticCast); + OS << "static_cast<"; + if (const TypedefType *TT = EntityType->getAs<TypedefType>()) { + // It's important to use the typedef's name if there is one so that the + // fixit doesn't break code using types like int64_t. + // + // FIXME: This will break if the typedef requires qualification. But + // getQualifiedNameAsString() includes non-machine-parsable components. + OS << *TT->getDecl(); + } else if (const BuiltinType *BT = EntityType->getAs<BuiltinType>()) + OS << BT->getName(S.getLangOptions()); + else { + // Oops, we didn't find the actual type of the variable. Don't emit a fixit + // with a broken cast. + return; + } + OS << ">("; + S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override) + << InitE->getSourceRange() + << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str()) + << FixItHint::CreateInsertion( + S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")"); +} + //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// @@ -4993,7 +5422,8 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, - ExprResult Init) { + ExprResult Init, + bool TopLevelOfInitList) { if (Init.isInvalid()) return ExprError(); @@ -5007,5 +5437,13 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, EqualLoc); InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); Init.release(); + + bool Constant = false; + APValue Result; + if (TopLevelOfInitList && + Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) { + DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE, + Constant, Result); + } return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 0e448e3..d5bee1d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/ErrorHandling.h" #include <limits> #include <list> @@ -86,7 +87,7 @@ namespace { /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { - typedef llvm::SmallVector<UnqualUsingEntry, 8> ListTy; + typedef SmallVector<UnqualUsingEntry, 8> ListTy; ListTy list; llvm::SmallPtrSet<DeclContext*, 8> visited; @@ -147,7 +148,7 @@ namespace { // by its using directives, transitively) as if they appeared in // the given effective context. void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { - llvm::SmallVector<DeclContext*,4> queue; + SmallVector<DeclContext*,4> queue; while (true) { DeclContext::udir_iterator I, End; for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) { @@ -460,7 +461,7 @@ void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { setAmbiguous(AmbiguousBaseSubobjectTypes); } -void LookupResult::print(llvm::raw_ostream &Out) { +void LookupResult::print(raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; @@ -549,6 +550,16 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); + if (getLangOptions().CPlusPlus0x) { + // If the move constructor has not yet been declared, do so now. + if (Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); // might not actually do it + + // If the move assignment operator has not yet been declared, do so now. + if (Class->needsImplicitMoveAssignment()) + DeclareImplicitMoveAssignment(Class); // might not actually do it + } + // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) DeclareImplicitDestructor(Class); @@ -585,11 +596,14 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(S.Context, Record)) { + CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record); if (Record->needsImplicitDefaultConstructor()) - S.DeclareImplicitDefaultConstructor( - const_cast<CXXRecordDecl *>(Record)); + S.DeclareImplicitDefaultConstructor(Class); if (!Record->hasDeclaredCopyConstructor()) - S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record)); + S.DeclareImplicitCopyConstructor(Class); + if (S.getLangOptions().CPlusPlus0x && + Record->needsImplicitMoveConstructor()) + S.DeclareImplicitMoveConstructor(Class); } break; @@ -604,10 +618,17 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (Name.getCXXOverloadedOperator() != OO_Equal) break; - if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) - if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() && - CanDeclareSpecialMemberFunction(S.Context, Record)) - S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record)); + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) { + if (Record->getDefinition() && + CanDeclareSpecialMemberFunction(S.Context, Record)) { + CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record); + if (!Record->hasDeclaredCopyAssignment()) + S.DeclareImplicitCopyAssignment(Class); + if (S.getLangOptions().CPlusPlus0x && + Record->needsImplicitMoveAssignment()) + S.DeclareImplicitMoveAssignment(Class); + } + } break; default: @@ -648,7 +669,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - if (!Record->isDefinition()) + if (!Record->isCompleteDefinition()) return Found; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); @@ -1187,7 +1208,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, // We have not yet looked into these namespaces, much less added // their "using-children" to the queue. - llvm::SmallVector<NamespaceDecl*, 8> Queue; + SmallVector<NamespaceDecl*, 8> Queue; // We have already looked into the initial namespace; seed the queue // with its using-children. @@ -1332,7 +1353,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Make sure that the declaration context is complete. assert((!isa<TagDecl>(LookupCtx) || LookupCtx->isDependentContext() || - cast<TagDecl>(LookupCtx)->isDefinition() || + cast<TagDecl>(LookupCtx)->isCompleteDefinition() || Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>() ->isBeingDefined()) && "Declaration context must already be complete!"); @@ -1802,7 +1823,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Add direct and indirect base classes along with their associated // namespaces. - llvm::SmallVector<CXXRecordDecl *, 32> Bases; + SmallVector<CXXRecordDecl *, 32> Bases; Bases.push_back(Class); while (!Bases.empty()) { // Pop this class off the stack. @@ -1852,7 +1873,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // the types do not contribute to this set. The sets of namespaces // and classes are determined in the following way: - llvm::SmallVector<const Type *, 16> Queue; + SmallVector<const Type *, 16> Queue; const Type *T = Ty->getCanonicalTypeInternal().getTypePtr(); while (true) { @@ -1979,6 +2000,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::ObjCObjectPointer: Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; + + // Atomic types are just wrappers; use the associations of the + // contained type. + case Type::Atomic: + T = cast<AtomicType>(T)->getValueType().getTypePtr(); + continue; } if (Queue.empty()) break; @@ -2210,12 +2237,14 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, Name = Context.DeclarationNames.getCXXConstructorName(CanTy); if (!RD->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(RD); - // TODO: Move constructors + if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(RD); } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); if (!RD->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(RD); - // TODO: Move assignment + if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveAssignment()) + DeclareImplicitMoveAssignment(RD); } QualType ArgType = CanTy; @@ -2358,6 +2387,15 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, return cast_or_null<CXXConstructorDecl>(Result->getMethod()); } +/// \brief Look up the moving constructor for the given class. +CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) { + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXMoveConstructor, false, + false, false, false, false); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. @@ -2366,6 +2404,8 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { DeclareImplicitDefaultConstructor(Class); if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); + if (getLangOptions().CPlusPlus0x && Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); @@ -2394,6 +2434,20 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, return Result->getMethod(); } +/// \brief Look up the moving assignment operator for the given class. +CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, + bool RValueThis, + unsigned ThisQuals) { + assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy assignment this"); + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXMoveAssignment, false, false, RValueThis, + ThisQuals & Qualifiers::Const, + ThisQuals & Qualifiers::Volatile); + + return Result->getMethod(); +} + /// \brief Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of @@ -2530,24 +2584,7 @@ public: /// \brief An entry in the shadow map, which is optimized to store a /// single declaration (the common case) but can also store a list /// of declarations. - class ShadowMapEntry { - typedef llvm::SmallVector<NamedDecl *, 4> DeclVector; - - /// \brief Contains either the solitary NamedDecl * or a vector - /// of declarations. - llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector; - - public: - ShadowMapEntry() : DeclOrVector() { } - - void Add(NamedDecl *ND); - void Destroy(); - - // Iteration. - typedef NamedDecl * const *iterator; - iterator begin(); - iterator end(); - }; + typedef llvm::TinyPtrVector<NamedDecl*> ShadowMapEntry; private: /// \brief A mapping from declaration names to the declarations that have @@ -2581,7 +2618,9 @@ public: NamedDecl *checkHidden(NamedDecl *ND); /// \brief Add a declaration to the current shadow map. - void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].Add(ND); } + void add(NamedDecl *ND) { + ShadowMaps.back()[ND->getDeclName()].push_back(ND); + } }; /// \brief RAII object that records when we've entered a shadow context. @@ -2596,66 +2635,12 @@ public: } ~ShadowContextRAII() { - for (ShadowMap::iterator E = Visible.ShadowMaps.back().begin(), - EEnd = Visible.ShadowMaps.back().end(); - E != EEnd; - ++E) - E->second.Destroy(); - Visible.ShadowMaps.pop_back(); } }; } // end anonymous namespace -void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) { - if (DeclOrVector.isNull()) { - // 0 - > 1 elements: just set the single element information. - DeclOrVector = ND; - return; - } - - if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { - // 1 -> 2 elements: create the vector of results and push in the - // existing declaration. - DeclVector *Vec = new DeclVector; - Vec->push_back(PrevND); - DeclOrVector = Vec; - } - - // Add the new element to the end of the vector. - DeclOrVector.get<DeclVector*>()->push_back(ND); -} - -void VisibleDeclsRecord::ShadowMapEntry::Destroy() { - if (DeclVector *Vec = DeclOrVector.dyn_cast<DeclVector *>()) { - delete Vec; - DeclOrVector = ((NamedDecl *)0); - } -} - -VisibleDeclsRecord::ShadowMapEntry::iterator -VisibleDeclsRecord::ShadowMapEntry::begin() { - if (DeclOrVector.isNull()) - return 0; - - if (DeclOrVector.is<NamedDecl *>()) - return DeclOrVector.getAddrOf<NamedDecl *>(); - - return DeclOrVector.get<DeclVector *>()->begin(); -} - -VisibleDeclsRecord::ShadowMapEntry::iterator -VisibleDeclsRecord::ShadowMapEntry::end() { - if (DeclOrVector.isNull()) - return 0; - - if (DeclOrVector.is<NamedDecl *>()) - return DeclOrVector.getAddrOf<NamedDecl *>() + 1; - - return DeclOrVector.get<DeclVector *>()->end(); -} - NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); @@ -2722,7 +2707,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } else if (ObjCForwardProtocolDecl *ForwardProto @@ -2733,19 +2718,17 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, P != PEnd; ++P) { if (Result.isAcceptableDecl(*P)) { - Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass); + Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass); Visited.add(*P); } } } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) { - for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); - I != IEnd; ++I) { - ObjCInterfaceDecl *IFace = I->getInterface(); + ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl(); if (Result.isAcceptableDecl(IFace)) { - Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass); + Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx, + InBaseClass); Visited.add(IFace); } - } } // Visit transparent contexts and inline namespaces inside this context. @@ -2885,7 +2868,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false); Visited.add(ND); } } @@ -2909,24 +2892,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); - - // Look for properties from which we can synthesize ivars, if - // permitted. - if (Result.getSema().getLangOptions().ObjCNonFragileABI2 && - IFace->getImplementation() && - Result.getLookupKind() == Sema::LookupOrdinaryName) { - for (ObjCInterfaceDecl::prop_iterator - P = IFace->prop_begin(), - PEnd = IFace->prop_end(); - P != PEnd; ++P) { - if (Result.getSema().canSynthesizeProvisionalIvar(*P) && - !IFace->lookupInstanceVariable((*P)->getIdentifier())) { - Consumer.FoundDecl(*P, Visited.checkHidden(*P), false); - Visited.add(*P); - } - } - } + /*InBaseClass=*/false, Consumer, Visited); } } @@ -3056,7 +3022,7 @@ static const unsigned MaxTypoDistanceResultSets = 5; class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The name written that is a typo in the source. - llvm::StringRef Typo; + StringRef Typo; /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. @@ -3084,11 +3050,12 @@ public: delete I->second; } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); - void FoundName(llvm::StringRef Name); - void addKeywordResult(llvm::StringRef Keyword); - void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance, - NestedNameSpecifier *NNS=NULL); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass); + void FoundName(StringRef Name); + void addKeywordResult(StringRef Keyword); + void addName(StringRef Name, NamedDecl *ND, unsigned Distance, + NestedNameSpecifier *NNS=NULL, bool isKeyword=false); void addCorrection(TypoCorrection Correction); typedef TypoResultsMap::iterator result_iterator; @@ -3099,7 +3066,7 @@ public: unsigned size() const { return BestResults.size(); } bool empty() const { return BestResults.empty(); } - TypoCorrection &operator[](llvm::StringRef Name) { + TypoCorrection &operator[](StringRef Name) { return (*BestResults.begin()->second)[Name]; } @@ -3115,7 +3082,7 @@ public: } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, - bool InBaseClass) { + DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; @@ -3130,7 +3097,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, FoundName(Name->getName()); } -void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { +void TypoCorrectionConsumer::FoundName(StringRef Name) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); @@ -3156,7 +3123,7 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { addName(Name, NULL, ED); } -void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) { +void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. @@ -3167,19 +3134,21 @@ void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) { return; } - addName(Keyword, TypoCorrection::KeywordDecl(), ED); + addName(Keyword, NULL, ED, NULL, true); } -void TypoCorrectionConsumer::addName(llvm::StringRef Name, +void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, unsigned Distance, - NestedNameSpecifier *NNS) { - addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name), - ND, NNS, Distance)); + NestedNameSpecifier *NNS, + bool isKeyword) { + TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance); + if (isKeyword) TC.makeKeyword(); + addCorrection(TC); } void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { - llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); + StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); TypoResultsMap *& Map = BestResults[Correction.getEditDistance()]; if (!Map) Map = new TypoResultsMap; @@ -3213,8 +3182,8 @@ class SpecifierInfo { : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {} }; -typedef llvm::SmallVector<DeclContext*, 4> DeclContextList; -typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList; +typedef SmallVector<DeclContext*, 4> DeclContextList; +typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; class NamespaceSpecifierSet { ASTContext &Context; @@ -3264,14 +3233,14 @@ DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { } void NamespaceSpecifierSet::SortNamespaces() { - llvm::SmallVector<unsigned, 4> sortedDistances; + SmallVector<unsigned, 4> sortedDistances; sortedDistances.append(Distances.begin(), Distances.end()); if (sortedDistances.size() > 1) std::sort(sortedDistances.begin(), sortedDistances.end()); Specifiers.clear(); - for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(), + for (SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(), DIEnd = sortedDistances.end(); DI != DIEnd; ++DI) { SpecifierInfoList &SpecList = DistanceMap[*DI]; @@ -3648,7 +3617,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, = Context.Idents.getExternalIdentifierLookup()) { llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers()); do { - llvm::StringRef Name = Iter->Next(); + StringRef Name = Iter->Next(); if (Name.empty()) break; @@ -3692,7 +3661,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (getLangOptions().CPlusPlus) { // Load any externally-known namespaces. if (ExternalSource && !LoadedExternalKnownNamespaces) { - llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; + SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; LoadedExternalKnownNamespaces = true; ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) @@ -3730,6 +3699,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, switch (TmpRes.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundUnresolvedValue: QualifiedResults.insert(Name); // We didn't find this name in our scope, or didn't like what we found; // ignore it. @@ -3745,12 +3715,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // We don't deal with ambiguities. return TypoCorrection(); + case LookupResult::FoundOverloaded: { + // Store all of the Decls for overloaded symbols + for (LookupResult::iterator TRD = TmpRes.begin(), + TRDEnd = TmpRes.end(); + TRD != TRDEnd; ++TRD) + I->second.addCorrectionDecl(*TRD); + ++I; + break; + } + case LookupResult::Found: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>()); - // FIXME: This sets the CorrectionDecl to NULL for overloaded functions. - // It would be nice to find the right one with overload resolution. ++I; break; } @@ -3786,14 +3762,23 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, switch (TmpRes.getResultKind()) { case LookupResult::Found: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(), QualifiedED, NI->NameSpecifier); break; + case LookupResult::FoundOverloaded: { + TypoCorrection corr(&Context.Idents.get((*QRI)->getName()), NULL, + NI->NameSpecifier, QualifiedED); + for (LookupResult::iterator TRD = TmpRes.begin(), + TRDEnd = TmpRes.end(); + TRD != TRDEnd; ++TRD) + corr.addCorrectionDecl(*TRD); + Consumer.addCorrection(corr); + break; + } case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: + case LookupResult::FoundUnresolvedValue: break; } } @@ -3870,6 +3855,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, return TypoCorrection(); } +void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { + if (!CDecl) return; + + if (isKeyword()) + CorrectionDecls.clear(); + + CorrectionDecls.push_back(CDecl); + + if (!CorrectionName) + CorrectionName = CDecl->getDeclName(); +} + std::string TypoCorrection::getAsString(const LangOptions &LO) const { if (CorrectionNameSpec) { std::string tmpBuffer; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index d826ea8..751f553 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Initialization.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/DenseSet.h" using namespace clang; @@ -24,6 +25,37 @@ using namespace clang; // Grammar actions. //===----------------------------------------------------------------------===// +/// getImpliedARCOwnership - Given a set of property attributes and a +/// type, infer an expected lifetime. The type's ownership qualification +/// is not considered. +/// +/// Returns OCL_None if the attributes as stated do not imply an ownership. +/// Never returns OCL_Autoreleasing. +static Qualifiers::ObjCLifetime getImpliedARCOwnership( + ObjCPropertyDecl::PropertyAttributeKind attrs, + QualType type) { + // retain, strong, copy, weak, and unsafe_unretained are only legal + // on properties of retainable pointer type. + if (attrs & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy)) { + return type->getObjCARCImplicitLifetime(); + } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) { + return Qualifiers::OCL_Weak; + } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) { + return Qualifiers::OCL_ExplicitNone; + } + + // assign can appear on other types, so we have to check the + // property type. + if (attrs & ObjCPropertyDecl::OBJC_PR_assign && + type->isObjCRetainableType()) { + return Qualifiers::OCL_ExplicitNone; + } + + return Qualifiers::OCL_None; +} + /// Check the internal consistency of a property declaration. static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { if (property->isInvalidDecl()) return; @@ -36,26 +68,23 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { // Nothing to do if we don't have a lifetime. if (propertyLifetime == Qualifiers::OCL_None) return; - Qualifiers::ObjCLifetime expectedLifetime; - unsigned selector; - - // Strong properties should have either strong or no lifetime. - if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy)) { - expectedLifetime = Qualifiers::OCL_Strong; - selector = 0; - } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) { - expectedLifetime = Qualifiers::OCL_Weak; - selector = 1; - } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained) && - property->getType()->isObjCRetainableType()) { - expectedLifetime = Qualifiers::OCL_ExplicitNone; - selector = 2; - } else { + Qualifiers::ObjCLifetime expectedLifetime + = getImpliedARCOwnership(propertyKind, property->getType()); + if (!expectedLifetime) { // We have a lifetime qualifier but no dominating property - // attribute. That's okay. + // attribute. That's okay, but restore reasonable invariants by + // setting the property attribute according to the lifetime + // qualifier. + ObjCPropertyDecl::PropertyAttributeKind attr; + if (propertyLifetime == Qualifiers::OCL_Strong) { + attr = ObjCPropertyDecl::OBJC_PR_strong; + } else if (propertyLifetime == Qualifiers::OCL_Weak) { + attr = ObjCPropertyDecl::OBJC_PR_weak; + } else { + assert(propertyLifetime == Qualifiers::OCL_ExplicitNone); + attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + } + property->setPropertyAttributes(attr); return; } @@ -65,7 +94,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { S.Diag(property->getLocation(), diag::err_arc_inconsistent_property_ownership) << property->getDeclName() - << selector + << expectedLifetime << propertyLifetime; } @@ -74,14 +103,13 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, - Decl *ClassCategory, bool *isOverridingProperty, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - if ((getLangOptions().getGCMode() != LangOptions::NonGC && + if ((getLangOptions().getGC() != LangOptions::NonGC && T.isObjCGCWeak()) || (getLangOptions().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_Weak)) @@ -101,12 +129,11 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_weak))); // Proceed with constructing the ObjCPropertDecls. - ObjCContainerDecl *ClassDecl = - cast<ObjCContainerDecl>(ClassCategory); + ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) if (CDecl->IsClassExtension()) { - Decl *Res = HandlePropertyInClassExtension(S, CDecl, AtLoc, + Decl *Res = HandlePropertyInClassExtension(S, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, @@ -137,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, } Decl * -Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, +Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, @@ -146,9 +173,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, bool *isOverridingProperty, TypeSourceInfo *T, tok::ObjCKeywordKind MethodImplKind) { - + ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext); // Diagnose if this property is already in continuation class. - DeclContext *DC = cast<DeclContext>(CDecl); + DeclContext *DC = CurContext; IdentifierInfo *PropertyId = FD.D.getIdentifier(); ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); @@ -209,7 +236,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, /* lexicalDC = */ CDecl); return PDecl; } - + if (PIDecl->getType().getCanonicalType() + != PDecl->getType().getCanonicalType()) { + Diag(AtLoc, + diag::warn_type_mismatch_continuation_class) << PDecl->getType(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + // The property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributesAsWritten(); @@ -235,12 +268,15 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ProtocolPropertyODS. setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) PIkind); - + // Must re-establish the context from class extension to primary + // class context. + ContextRAII SavedContext(*this, CCPrimary); + Decl *ProtocolPtrTy = ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, PIDecl->getGetterName(), PIDecl->getSetterName(), - CCPrimary, isOverridingProperty, + isOverridingProperty, MethodImplKind, /* lexicalDC = */ CDecl); PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy); @@ -290,7 +326,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol - if (getLangOptions().getGCMode() != LangOptions::NonGC && + if (getLangOptions().getGC() != LangOptions::NonGC && isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) if (const ObjCObjectPointerType *ObjPtrTy = T->getAs<ObjCObjectPointerType>()) { @@ -392,9 +428,10 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (isAssign) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + // In the semantic attributes, one of nonatomic or atomic is always set. if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - else if (Attributes & ObjCDeclSpec::DQ_PR_atomic) + else PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); // 'unsafe_unretained' is alias for 'assign'. @@ -416,82 +453,49 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, ObjCIvarDecl *ivar) { if (property->isInvalidDecl() || ivar->isInvalidDecl()) return; - QualType propertyType = property->getType(); - Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime(); - ObjCPropertyDecl::PropertyAttributeKind propertyKind - = property->getPropertyAttributes(); - QualType ivarType = ivar->getType(); Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime(); - - // Case 1: strong properties. - if (propertyLifetime == Qualifiers::OCL_Strong || - (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy))) { - switch (ivarLifetime) { - case Qualifiers::OCL_Strong: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Weak: - S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) - << property->getDeclName() - << ivar->getDeclName() - << ivarLifetime; - break; - } - // Case 2: weak properties. - } else if (propertyLifetime == Qualifiers::OCL_Weak || - (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) { - switch (ivarLifetime) { - case Qualifiers::OCL_Weak: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Strong: - S.Diag(propertyImplLoc, diag::error_weak_property) - << property->getDeclName() - << ivar->getDeclName(); - break; - } + // The lifetime implied by the property's attributes. + Qualifiers::ObjCLifetime propertyLifetime = + getImpliedARCOwnership(property->getPropertyAttributes(), + property->getType()); - // Case 3: assign properties. - } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) && - propertyType->isObjCRetainableType()) { - switch (ivarLifetime) { - case Qualifiers::OCL_ExplicitNone: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Strong: - S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) - << property->getDeclName() - << ivar->getDeclName(); - break; - } + // We're fine if they match. + if (propertyLifetime == ivarLifetime) return; - // Any other property should be ignored. - } else { + // These aren't valid lifetimes for object ivars; don't diagnose twice. + if (ivarLifetime == Qualifiers::OCL_None || + ivarLifetime == Qualifiers::OCL_Autoreleasing) + return; + + switch (propertyLifetime) { + case Qualifiers::OCL_Strong: + S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) + << property->getDeclName() + << ivar->getDeclName() + << ivarLifetime; + break; + + case Qualifiers::OCL_Weak: + S.Diag(propertyImplLoc, diag::error_weak_property) + << property->getDeclName() + << ivar->getDeclName(); + break; + + case Qualifiers::OCL_ExplicitNone: + S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) + << property->getDeclName() + << ivar->getDeclName() + << ((property->getPropertyAttributesAsWritten() + & ObjCPropertyDecl::OBJC_PR_assign) != 0); + break; + + case Qualifiers::OCL_Autoreleasing: + llvm_unreachable("properties cannot be autoreleasing"); + + case Qualifiers::OCL_None: + // Any other property should be ignored. return; } @@ -507,12 +511,11 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize, - Decl *ClassCatImpDecl, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc) { ObjCContainerDecl *ClassImpDecl = - cast_or_null<ObjCContainerDecl>(ClassCatImpDecl); + dyn_cast<ObjCContainerDecl>(CurContext); // Make sure we have a context for the property implementation declaration. if (!ClassImpDecl) { Diag(AtLoc, diag::error_missing_property_context); @@ -586,61 +589,65 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCIvarDecl *Ivar = 0; // Check that we have a valid, previously declared ivar for @synthesize if (Synthesize) { - if (getLangOptions().ObjCAutoRefCount && - !property->hasWrittenStorageAttribute() && - property->getType()->isObjCRetainableType()) { - Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object); - Diag(property->getLocation(), diag::note_property_declare); - } - // @synthesize if (!PropertyIvar) PropertyIvar = PropertyId; ObjCPropertyDecl::PropertyAttributeKind kind = property->getPropertyAttributes(); - QualType PropType = Context.getCanonicalType(property->getType()); - QualType PropertyIvarType = PropType; - if (PropType->isReferenceType()) - PropertyIvarType = cast<ReferenceType>(PropType)->getPointeeType(); + QualType PropType = property->getType(); + + QualType PropertyIvarType = PropType.getNonReferenceType(); + + // Add GC __weak to the ivar type if the property is weak. + if ((kind & ObjCPropertyDecl::OBJC_PR_weak) && + getLangOptions().getGC() != LangOptions::NonGC) { + assert(!getLangOptions().ObjCAutoRefCount); + if (PropertyIvarType.isObjCGCStrong()) { + Diag(PropertyLoc, diag::err_gc_weak_property_strong_type); + Diag(property->getLocation(), diag::note_property_declare); + } else { + PropertyIvarType = + Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); + } + } + // Check that this is a previously declared 'ivar' in 'IDecl' interface ObjCInterfaceDecl *ClassDeclared; Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { - // In ARC, give the ivar a lifetime qualifier based on its + // In ARC, give the ivar a lifetime qualifier based on the // property attributes. if (getLangOptions().ObjCAutoRefCount && - !PropertyIvarType.getObjCLifetime()) { - - // retain/copy have retaining lifetime. - if (kind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy)) { - Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_Strong); - PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); - } - else if (kind & ObjCPropertyDecl::OBJC_PR_weak) { - if (!getLangOptions().ObjCRuntimeHasWeak) { + !PropertyIvarType.getObjCLifetime() && + PropertyIvarType->isObjCRetainableType()) { + + // It's an error if we have to do this and the user didn't + // explicitly write an ownership attribute on the property. + if (!property->hasWrittenStorageAttribute() && + !(kind & ObjCPropertyDecl::OBJC_PR_strong)) { + Diag(PropertyLoc, + diag::err_arc_objc_property_default_assign_on_object); + Diag(property->getLocation(), diag::note_property_declare); + } else { + Qualifiers::ObjCLifetime lifetime = + getImpliedARCOwnership(kind, PropertyIvarType); + assert(lifetime && "no lifetime for property?"); + + if (lifetime == Qualifiers::OCL_Weak && + !getLangOptions().ObjCRuntimeHasWeak) { Diag(PropertyLoc, diag::err_arc_weak_no_runtime); Diag(property->getLocation(), diag::note_property_declare); } + Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_Weak); + qs.addObjCLifetime(lifetime); PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); } - else if (kind & ObjCPropertyDecl::OBJC_PR_assign && - PropertyIvarType->isObjCRetainableType()) { - // assume that an 'assign' property synthesizes __unsafe_unretained - // ivar - Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); - PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); - } } if (kind & ObjCPropertyDecl::OBJC_PR_weak && !getLangOptions().ObjCAutoRefCount && - getLangOptions().getGCMode() == LangOptions::NonGC) { + getLangOptions().getGC() == LangOptions::NonGC) { Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc); Diag(property->getLocation(), diag::note_property_declare); } @@ -670,7 +677,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, QualType IvarType = Context.getCanonicalType(Ivar->getType()); // Check that type of property and its ivar are type compatible. - if (PropertyIvarType != IvarType) { + if (Context.getCanonicalType(PropertyIvarType) != IvarType) { bool compat = false; if (isa<ObjCObjectPointerType>(PropertyIvarType) && isa<ObjCObjectPointerType>(IvarType)) @@ -709,15 +716,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } // __weak is explicit. So it works on Canonical type. if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC)) { + getLangOptions().getGC() != LangOptions::NonGC)) { Diag(PropertyLoc, diag::error_weak_property) << property->getDeclName() << Ivar->getDeclName(); + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Fall thru - see previous comment } // Fall thru - see previous comment if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { + getLangOptions().getGC() != LangOptions::NonGC) { Diag(PropertyLoc, diag::error_strong_property) << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment @@ -793,6 +801,17 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, VK_LValue, SourceLocation()); ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); + if (property->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Expr *callExpr = Res.takeAs<Expr>(); + if (const CXXOperatorCallExpr *CXXCE = + dyn_cast_or_null<CXXOperatorCallExpr>(callExpr)) + if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee()) + if (!FuncDecl->isTrivial()) + Diag(PropertyLoc, + diag::warn_atomic_property_nontrivial_assign_op) + << property->getType(); + } PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); } } @@ -880,7 +899,7 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "copy" << inheritedName; - else { + else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){ unsigned CAttrRetain = (CAttr & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); @@ -917,9 +936,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, QualType ConvertedType; if (!isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC) || - IncompatibleObjC) + IncompatibleObjC) { Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) << Property->getType() << SuperProperty->getType() << inheritedName; + Diag(SuperProperty->getLocation(), diag::note_property_declare); + } } } @@ -1146,7 +1167,8 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()]; // Exclude property for protocols which conform to class's super-class, // as super-class has to implement the property. - if (!PropertyFromSuper || PropertyFromSuper != Prop) { + if (!PropertyFromSuper || + PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) { ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; if (!PropEntry) PropEntry = Prop; @@ -1241,10 +1263,20 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return 0; } +static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop, + ASTContext &Ctx) { + llvm::SmallString<128> ivarName; + { + llvm::raw_svector_ostream os(ivarName); + os << '_' << Prop->getIdentifier()->getName(); + } + return &Ctx.Idents.get(ivarName.str()); +} + /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in class's @implementation. -void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl) { +void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl) { llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; CollectClassPropertyImplementations(IDecl, PropMap); @@ -1280,12 +1312,23 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, // Saying that they are located at the @implementation isn't really going // to help users. ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(), - true,IMPDecl, - Prop->getIdentifier(), Prop->getIdentifier(), + true, + /* property = */ Prop->getIdentifier(), + /* ivar = */ getDefaultSynthIvarName(Prop, Context), SourceLocation()); } } +void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { + if (!LangOpts.ObjCDefaultSynthProperties || !LangOpts.ObjCNonFragileABI2) + return; + ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D); + if (!IC) + return; + if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) + DefaultSynthesizeProperties(S, IC, IDecl); +} + void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap) { @@ -1313,23 +1356,23 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>()) continue; if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), + Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); + Diag(Prop->getLocation(), + diag::note_property_declare); } if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), + Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); + Diag(Prop->getLocation(), + diag::note_property_declare); } } } @@ -1338,7 +1381,7 @@ void Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl) { // Rules apply in non-GC mode only - if (getLangOptions().getGCMode() != LangOptions::NonGC) + if (getLangOptions().getGC() != LangOptions::NonGC) return; for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), E = IDecl->prop_end(); @@ -1349,10 +1392,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, bool LookedUpGetterSetter = false; unsigned Attributes = Property->getPropertyAttributes(); - unsigned AttributesAsWrittern = Property->getPropertyAttributesAsWritten(); + unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten(); - if (!(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_atomic) && - !(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_nonatomic)) { + if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) && + !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) { GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); LookedUpGetterSetter = true; @@ -1388,7 +1431,9 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, (GetterMethod ? GetterMethod->getLocation() : SetterMethod->getLocation()); Diag(MethodLoc, diag::warn_atomic_property_rule) - << Property->getIdentifier(); + << Property->getIdentifier() << (GetterMethod != 0) + << (SetterMethod != 0); + Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); Diag(Property->getLocation(), diag::note_property_declare); } } @@ -1396,7 +1441,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) { - if (getLangOptions().getGCMode() == LangOptions::GCOnly) + if (getLangOptions().getGC() == LangOptions::GCOnly) return; for (ObjCImplementationDecl::propimpl_iterator @@ -1417,7 +1462,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D if (getLangOptions().ObjCAutoRefCount) Diag(PID->getLocation(), diag::err_ownin_getter_rule); else - Diag(PID->getLocation(), diag::warn_ownin_getter_rule); + Diag(PID->getLocation(), diag::warn_owning_getter_rule); Diag(PD->getLocation(), diag::note_property_declare); } } @@ -1464,7 +1509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, Context.VoidTy) Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || - ((*SetterMethod->param_begin())->getType() != property->getType())) { + !Context.hasSameUnqualifiedType( + (*SetterMethod->param_begin())->getType(), property->getType())) { Diag(property->getLocation(), diag::warn_accessor_property_type_mismatch) << property->getDeclName() @@ -1489,8 +1535,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getGetterName(), - property->getType(), 0, CD, true, false, true, - false, + property->getType(), 0, CD, /*isInstance=*/true, + /*isVariadic=*/false, /*isSynthesized=*/true, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1526,7 +1573,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getSetterName(), Context.VoidTy, 0, - CD, true, false, true, false, + CD, /*isInstance=*/true, /*isVariadic=*/false, + /*isSynthesized=*/true, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1542,7 +1592,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SC_None, SC_None, 0); - SetterMethod->setMethodParams(Context, &Argument, 1, 1); + SetterMethod->setMethodParams(Context, Argument, + ArrayRef<SourceLocation>()); AddPropertyAttrs(*this, SetterMethod, property); @@ -1686,7 +1737,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, (Attributes & ObjCDeclSpec::DQ_PR_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; } else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) && (Attributes & ObjCDeclSpec::DQ_PR_weak)) { @@ -1695,6 +1746,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, Attributes &= ~ObjCDeclSpec::DQ_PR_weak; } + if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) && + (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "atomic" << "nonatomic"; + Attributes &= ~ObjCDeclSpec::DQ_PR_atomic; + } + // Warn if user supplied no assignment attribute, property is // readwrite, and this is an object type. if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | @@ -1703,13 +1761,19 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, ObjCDeclSpec::DQ_PR_weak)) && !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && PropertyTy->isObjCObjectPointerType()) { - // Skip this warning in gc-only mode. - if (getLangOptions().getGCMode() != LangOptions::GCOnly) - Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + if (getLangOptions().ObjCAutoRefCount) + // With arc, @property definitions should default to (strong) when + // not specified + PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + else { + // Skip this warning in gc-only mode. + if (getLangOptions().getGC() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); - // If non-gc code warn that this is likely inappropriate. - if (getLangOptions().getGCMode() == LangOptions::NonGC) - Diag(Loc, diag::warn_objc_property_default_assign_on_object); + // If non-gc code warn that this is likely inappropriate. + if (getLangOptions().getGC() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + } // FIXME: Implement warning dependent on NSCopying being // implemented. See also: @@ -1719,7 +1783,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly) - && getLangOptions().getGCMode() == LangOptions::GCOnly + && getLangOptions().getGC() == LangOptions::GCOnly && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); + else if (getLangOptions().ObjCAutoRefCount && + (Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && + !(Attributes & ObjCDeclSpec::DQ_PR_strong) && + PropertyTy->isBlockPointerType()) + Diag(Loc, diag::warn_objc_property_retain_of_block); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 437b2b5..b0dd5e2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -37,11 +37,14 @@ using namespace sema; /// A convenience routine for creating a decayed reference to a /// function. static ExprResult -CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, +CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ - ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), - VK_LValue, Loc, LocInfo)); + DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, Fn->getType(), + VK_LValue, Loc, LocInfo); + if (HadMultipleCandidates) + DRE->setHadMultipleCandidates(true); + ExprResult E = S.Owned(DRE); E = S.DefaultFunctionArrayConversion(E.take()); if (E.isInvalid()) return ExprError(); @@ -258,7 +261,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// DebugPrint - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. void StandardConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { OS << GetImplicitConversionName(First); @@ -297,12 +300,12 @@ void StandardConversionSequence::DebugPrint() const { /// DebugPrint - Print this user-defined conversion sequence to standard /// error. Useful for debugging overloading issues. void UserDefinedConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); if (Before.First || Before.Second || Before.Third) { Before.DebugPrint(); OS << " -> "; } - OS << '\'' << ConversionFunction << '\''; + OS << '\'' << *ConversionFunction << '\''; if (After.First || After.Second || After.Third) { OS << " -> "; After.DebugPrint(); @@ -312,7 +315,7 @@ void UserDefinedConversionSequence::DebugPrint() const { /// DebugPrint - Print this implicit conversion sequence to standard /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); switch (ConversionKind) { case StandardConversion: OS << "Standard conversion: "; @@ -909,20 +912,22 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType, /// explicit user-defined conversions are permitted. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, - AssignmentAction Action, bool AllowExplicit) { + AssignmentAction Action, bool AllowExplicit, + bool Diagnose) { ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS, + Diagnose); } ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - ImplicitConversionSequence& ICS) { + ImplicitConversionSequence& ICS, + bool Diagnose) { // Objective-C ARC: Determine whether we will allow the writeback conversion. bool AllowObjCWritebackConversion = getLangOptions().ObjCAutoRefCount && (Action == AA_Passing || Action == AA_Sending); - ICS = clang::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, @@ -930,6 +935,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, /*InOverloadResolution=*/false, /*CStyle=*/false, AllowObjCWritebackConversion); + if (!Diagnose && ICS.isFailure()) + return ExprError(); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -1113,10 +1120,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, return false; } } - // Lvalue-to-rvalue conversion (C++ 4.1): - // An lvalue (3.10) of a non-function, non-array type T can be - // converted to an rvalue. - bool argIsLValue = From->isLValue(); + // Lvalue-to-rvalue conversion (C++11 4.1): + // A glvalue (3.10) of a non-function, non-array type T can + // be converted to a prvalue. + bool argIsLValue = From->isGLValue(); if (argIsLValue && !FromType->isFunctionType() && !FromType->isArrayType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { @@ -1392,12 +1399,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. - bool FromIsSigned; + bool FromIsSigned = FromType->isSignedIntegerType(); uint64_t FromSize = Context.getTypeSize(FromType); - // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. - FromIsSigned = true; - // The types we'll try to promote to, in the appropriate // order. Try each of these types. QualType PromoteTypes[6] = { @@ -1465,10 +1469,10 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { /// FromType to ToType is a floating point promotion (C++ 4.6). If so, /// returns true and sets PromotedType to the promoted type. bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { - /// An rvalue of type float can be converted to an rvalue of type - /// double. (C++ 4.6p1). if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>()) if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) { + /// An rvalue of type float can be converted to an rvalue of type + /// double. (C++ 4.6p1). if (FromBuiltin->getKind() == BuiltinType::Float && ToBuiltin->getKind() == BuiltinType::Double) return true; @@ -1481,6 +1485,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { FromBuiltin->getKind() == BuiltinType::Double) && (ToBuiltin->getKind() == BuiltinType::LongDouble)) return true; + + // Half can be promoted to float. + if (FromBuiltin->getKind() == BuiltinType::Half && + ToBuiltin->getKind() == BuiltinType::Float) + return true; } return false; @@ -1668,7 +1677,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, } // MSVC allows implicit function to void* type conversion. - if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() && + if (getLangOptions().MicrosoftExt && FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, @@ -2073,6 +2082,11 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, // Argument types are too different. Abort. return false; } + if (LangOpts.ObjCAutoRefCount && + !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType, + ToFunctionType)) + return false; + ConvertedType = ToType; return true; } @@ -2136,8 +2150,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, PDiag(diag::warn_impcast_bool_to_null_pointer) << ToType << From->getSourceRange()); - if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) - if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { + if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { + if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) { QualType FromPointeeType = FromPtrType->getPointeeType(), ToPointeeType = ToPtrType->getPointeeType(); @@ -2155,16 +2169,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, Kind = CK_DerivedToBase; } } - if (const ObjCObjectPointerType *FromPtrType = - FromType->getAs<ObjCObjectPointerType>()) { - if (const ObjCObjectPointerType *ToPtrType = - ToType->getAs<ObjCObjectPointerType>()) { + } else if (const ObjCObjectPointerType *ToPtrType = + ToType->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *FromPtrType = + FromType->getAs<ObjCObjectPointerType>()) { // Objective-C++ conversions are always okay. // FIXME: We should have a different class of conversions for the // Objective-C++ implicit conversions. if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType()) return false; + } else if (FromType->isBlockPointerType()) { + Kind = CK_BlockPointerToObjCPointerCast; + } else { + Kind = CK_CPointerToObjCPointerCast; } + } else if (ToType->isBlockPointerType()) { + if (!FromType->isBlockPointerType()) + Kind = CK_AnyPointerToBlockPointerCast; } // We shouldn't fall into this case unless it's valid for other @@ -2483,6 +2504,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) { case OR_Success: @@ -2504,8 +2527,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, User.Before = Best->Conversions[0].Standard; User.EllipsisConversion = false; } + User.HadMultipleCandidates = HadMultipleCandidates; User.ConversionFunction = Constructor; - User.FoundConversionFunction = Best->FoundDecl.getDecl(); + User.FoundConversionFunction = Best->FoundDecl; User.After.setAsIdentityConversion(); User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType()); User.After.setAllToTypes(ToType); @@ -2521,8 +2545,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // conversion sequence converts the source type to the // implicit object parameter of the conversion function. User.Before = Best->Conversions[0].Standard; + User.HadMultipleCandidates = HadMultipleCandidates; User.ConversionFunction = Conversion; - User.FoundConversionFunction = Best->FoundDecl.getDecl(); + User.FoundConversionFunction = Best->FoundDecl; User.EllipsisConversion = false; // C++ [over.ics.user]p2: @@ -2862,6 +2887,25 @@ CompareStandardConversionSequences(Sema &S, } } + // In Microsoft mode, prefer an integral conversion to a + // floating-to-integral conversion if the integral conversion + // is between types of the same size. + // For example: + // void f(float); + // void f(int); + // int main { + // long a; + // f(a); + // } + // Here, MSVC will call f(int) instead of generating a compile error + // as clang will do in standard mode. + if (S.getLangOptions().MicrosoftMode && + SCS1.Second == ICK_Integral_Conversion && + SCS2.Second == ICK_Floating_Integral && + S.Context.getTypeSize(SCS1.getFromType()) == + S.Context.getTypeSize(SCS1.getToType(2))) + return ImplicitConversionSequence::Better; + return ImplicitConversionSequence::Indistinguishable; } @@ -3292,6 +3336,16 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, bool DerivedToBase = false; bool ObjCConversion = false; bool ObjCLifetimeConversion = false; + + // If we are initializing an rvalue reference, don't permit conversion + // functions that return lvalues. + if (!ConvTemplate && DeclType->isRValueReferenceType()) { + const ReferenceType *RefType + = Conv->getConversionType()->getAs<LValueReferenceType>(); + if (RefType && !RefType->getPointeeType()->isFunctionType()) + continue; + } + if (!ConvTemplate && S.CompareReferenceRelationship( DeclLoc, @@ -3322,6 +3376,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, DeclType, CandidateSet); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { case OR_Success: @@ -3343,8 +3399,9 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, ICS.setUserDefined(); ICS.UserDefined.Before = Best->Conversions[0].Standard; ICS.UserDefined.After = Best->FinalConversion; + ICS.UserDefined.HadMultipleCandidates = HadMultipleCandidates; ICS.UserDefined.ConversionFunction = Best->Function; - ICS.UserDefined.FoundConversionFunction = Best->FoundDecl.getDecl(); + ICS.UserDefined.FoundConversionFunction = Best->FoundDecl; ICS.UserDefined.EllipsisConversion = false; assert(ICS.UserDefined.After.ReferenceBinding && ICS.UserDefined.After.DirectBinding && @@ -3611,12 +3668,25 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.ObjCLifetimeConversionBinding = false; } else if (ICS.isUserDefined()) { + // Don't allow rvalue references to bind to lvalues. + if (DeclType->isRValueReferenceType()) { + if (const ReferenceType *RefType + = ICS.UserDefined.ConversionFunction->getResultType() + ->getAs<LValueReferenceType>()) { + if (!RefType->getPointeeType()->isFunctionType()) { + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, + DeclType); + return ICS; + } + } + } + ICS.UserDefined.After.ReferenceBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = true; - ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; - ICS.Standard.ObjCLifetimeConversionBinding = false; + ICS.UserDefined.After.IsLvalueReference = !isRValRef; + ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.UserDefined.After.BindsToRvalue = true; + ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.UserDefined.After.ObjCLifetimeConversionBinding = false; } return ICS; @@ -3647,6 +3717,18 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, AllowObjCWritebackConversion); } +static bool TryCopyInitialization(const CanQualType FromQTy, + const CanQualType ToQTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK); + ImplicitConversionSequence ICS = + TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); + + return !ICS.isBad(); +} + /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. @@ -3852,25 +3934,57 @@ ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) { return ExprError(); } -/// TryContextuallyConvertToObjCId - Attempt to contextually convert the -/// expression From to 'id'. +/// dropPointerConversions - If the given standard conversion sequence +/// involves any pointer conversions, remove them. This may change +/// the result type of the conversion sequence. +static void dropPointerConversion(StandardConversionSequence &SCS) { + if (SCS.Second == ICK_Pointer_Conversion) { + SCS.Second = ICK_Identity; + SCS.Third = ICK_Identity; + SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0]; + } +} + +/// TryContextuallyConvertToObjCPointer - Attempt to contextually +/// convert the expression From to an Objective-C pointer type. static ImplicitConversionSequence -TryContextuallyConvertToObjCId(Sema &S, Expr *From) { +TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { + // Do an implicit conversion to 'id'. QualType Ty = S.Context.getObjCIdType(); - return TryImplicitConversion(S, From, Ty, - // FIXME: Are these flags correct? - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, - /*InOverloadResolution=*/false, - /*CStyle=*/false, - /*AllowObjCWritebackConversion=*/false); + ImplicitConversionSequence ICS + = TryImplicitConversion(S, From, Ty, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); + + // Strip off any final conversions to 'id'. + switch (ICS.getKind()) { + case ImplicitConversionSequence::BadConversion: + case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::EllipsisConversion: + break; + + case ImplicitConversionSequence::UserDefinedConversion: + dropPointerConversion(ICS.UserDefined.After); + break; + + case ImplicitConversionSequence::StandardConversion: + dropPointerConversion(ICS.Standard); + break; + } + + return ICS; } -/// PerformContextuallyConvertToObjCId - Perform a contextual conversion -/// of the expression From to 'id'. -ExprResult Sema::PerformContextuallyConvertToObjCId(Expr *From) { +/// PerformContextuallyConvertToObjCPointer - Perform a contextual +/// conversion of the expression From to an Objective-C pointer type. +ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { QualType Ty = Context.getObjCIdType(); - ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From); + ImplicitConversionSequence ICS = + TryContextuallyConvertToObjCPointer(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Ty, ICS, AA_Converting); return ExprError(); @@ -3951,6 +4065,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions(); + bool HadMultipleCandidates = (Conversions->size() > 1); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; @@ -3978,7 +4094,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; - ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy); + ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy()); Diag(Loc, ExplicitConvDiag) << T << ConvTy @@ -3995,7 +4111,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, return ExprError(); CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion); + ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); @@ -4022,8 +4139,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange(); } - ExprResult Result = BuildCXXMemberCallExpr(From, Found, - cast<CXXConversionDecl>(Found->getUnderlyingDecl())); + ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); @@ -4144,6 +4261,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, return; } + // (CUDA B.1): Check for invalid calls between targets. + if (getLangOptions().CUDA) + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) + if (CheckCUDATarget(Caller, Function)) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_target; + return; + } + // Determine the implicit conversion sequences for each of the // arguments. Candidate.Conversions.resize(NumArgs); @@ -4590,7 +4716,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, break; default: - assert(false && + llvm_unreachable( "Can only end up with a standard conversion sequence or failure"); } } @@ -4686,9 +4812,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[0].setUserDefined(); Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; + Candidate.Conversions[0].UserDefined.HadMultipleCandidates = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; - Candidate.Conversions[0].UserDefined.FoundConversionFunction - = FoundDecl.getDecl(); + Candidate.Conversions[0].UserDefined.FoundConversionFunction = FoundDecl; Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion(); @@ -4973,7 +5099,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, buildObjCPtr = true; } else - assert(false && "type was not a pointer type!"); + llvm_unreachable("type was not a pointer type!"); } else PointeeTy = PointerTy->getPointeeType(); @@ -5230,7 +5356,7 @@ class BuiltinOperatorOverloadBuilder { unsigned NumArgs; Qualifiers VisibleTypeConversionsQuals; bool HasArithmeticOrEnumeralCandidateType; - llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; + SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; OverloadCandidateSet &CandidateSet; // Define some constants used to index and iterate over the arithemetic types @@ -5366,7 +5492,7 @@ public: Sema &S, Expr **Args, unsigned NumArgs, Qualifiers VisibleTypeConversionsQuals, bool HasArithmeticOrEnumeralCandidateType, - llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, + SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, OverloadCandidateSet &CandidateSet) : S(S), Args(Args), NumArgs(NumArgs), VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), @@ -6235,7 +6361,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, bool HasNonRecordCandidateType = false; bool HasArithmeticOrEnumeralCandidateType = false; - llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; + SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), @@ -6254,7 +6380,11 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Exit early when no non-record types have been added to the candidate set // for any of the arguments to the operator. - if (!HasNonRecordCandidateType) + // + // We can't exit early for !, ||, or &&, since there we have always have + // 'bool' overloads. + if (!HasNonRecordCandidateType && + !(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe)) return; // Setup an object to manage the common state for building overloads. @@ -6267,16 +6397,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, switch (Op) { case OO_None: case NUM_OVERLOADED_OPERATORS: - assert(false && "Expected an overloaded operator"); - break; + llvm_unreachable("Expected an overloaded operator"); case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: case OO_Call: - assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); - break; + llvm_unreachable( + "Special operators don't use AddBuiltinOperatorCandidates"); case OO_Comma: case OO_Arrow: @@ -6846,6 +6975,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + // Special diagnostic for failure to convert an initializer list, since + // telling the user that it has type void is not useful. + if (FromExpr && isa<InitListExpr>(FromExpr)) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + // Diagnose references or pointers to incomplete types differently, // since it's far from impossible that the incompleteness triggered // the failure. @@ -6902,11 +7042,34 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } - // TODO: specialize more based on the kind of mismatch - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) - << (unsigned) FnKind << FnDesc + if (isa<ObjCObjectPointerType>(CFromTy) && + isa<PointerType>(CToTy)) { + Qualifiers FromQs = CFromTy.getQualifiers(); + Qualifiers ToQs = CToTy.getQualifiers(); + if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + } + + // Emit the generic diagnostic and, optionally, add the hints to it. + PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); + FDiag << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + << FromTy << ToTy << (unsigned) isObjectArgument << I + 1 + << (unsigned) (Cand->Fix.Kind); + + // If we can fix the conversion, suggest the FixIts. + for (SmallVector<FixItHint, 1>::iterator + HI = Cand->Fix.Hints.begin(), HE = Cand->Fix.Hints.end(); + HI != HE; ++HI) + FDiag << *HI; + S.Diag(Fn->getLocation(), FDiag); + MaybeEmitInheritedConstructorNote(S, Fn); } @@ -7081,6 +7244,21 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, } } +/// CUDA: diagnose an invalid call across targets. +void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { + FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext); + FunctionDecl *Callee = Cand->Function; + + Sema::CUDAFunctionTarget CallerTarget = S.IdentifyCUDATarget(Caller), + CalleeTarget = S.IdentifyCUDATarget(Callee); + + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc); + + S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) + << (unsigned) FnKind << CalleeTarget << CallerTarget; +} + /// Generates a 'note' diagnostic for an overload candidate. We've /// already generated a primary error at the call site. /// @@ -7140,6 +7318,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // those conditions and diagnose them well. return S.NoteOverloadCandidate(Fn); } + + case ovl_fail_bad_target: + return DiagnoseBadTarget(S, Cand); } } @@ -7217,6 +7398,37 @@ SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { return SourceLocation(); } +static unsigned +RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) { + switch ((Sema::TemplateDeductionResult)DFI.Result) { + case Sema::TDK_Success: + llvm_unreachable("TDK_success while diagnosing bad deduction"); + + case Sema::TDK_Incomplete: + return 1; + + case Sema::TDK_Underqualified: + case Sema::TDK_Inconsistent: + return 2; + + case Sema::TDK_SubstitutionFailure: + case Sema::TDK_NonDeducedMismatch: + return 3; + + case Sema::TDK_InstantiationDepth: + case Sema::TDK_FailedOverloadResolution: + return 4; + + case Sema::TDK_InvalidExplicitArguments: + return 5; + + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + return 6; + } + llvm_unreachable("Unhandled deduction result"); +} + struct CompareOverloadCandidatesForDisplay { Sema &S; CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} @@ -7256,6 +7468,19 @@ struct CompareOverloadCandidatesForDisplay { if (R->FailureKind != ovl_fail_bad_conversion) return true; + // The conversion that can be fixed with a smaller number of changes, + // comes first. + unsigned numLFixes = L->Fix.NumConversionsFixed; + unsigned numRFixes = R->Fix.NumConversionsFixed; + numLFixes = (numLFixes == 0) ? UINT_MAX : numLFixes; + numRFixes = (numRFixes == 0) ? UINT_MAX : numRFixes; + if (numLFixes != numRFixes) { + if (numLFixes < numRFixes) + return true; + else + return false; + } + // If there's any ordering between the defined conversions... // FIXME: this might not be transitive. assert(L->Conversions.size() == R->Conversions.size()); @@ -7284,6 +7509,16 @@ struct CompareOverloadCandidatesForDisplay { } else if (R->FailureKind == ovl_fail_bad_conversion) return false; + if (L->FailureKind == ovl_fail_bad_deduction) { + if (R->FailureKind != ovl_fail_bad_deduction) + return true; + + if (L->DeductionFailure.Result != R->DeductionFailure.Result) + return RankDeductionFailure(L->DeductionFailure) + < RankDeductionFailure(R->DeductionFailure); + } else if (R->FailureKind == ovl_fail_bad_deduction) + return false; + // TODO: others? } @@ -7300,7 +7535,7 @@ struct CompareOverloadCandidatesForDisplay { }; /// CompleteNonViableCandidate - Normally, overload resolution only -/// computes up to the first +/// computes up to the first. Produces the FixIt set if possible. void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { assert(!Cand->Viable); @@ -7308,14 +7543,21 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, // Don't do anything on failures other than bad conversion. if (Cand->FailureKind != ovl_fail_bad_conversion) return; + // We only want the FixIts if all the arguments can be corrected. + bool Unfixable = false; + // Use a implicit copy initialization to check conversion fixes. + Cand->Fix.setConversionChecker(TryCopyInitialization); + // Skip forward to the first bad conversion. unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); unsigned ConvCount = Cand->Conversions.size(); while (true) { assert(ConvIdx != ConvCount && "no bad conversion in candidate"); ConvIdx++; - if (Cand->Conversions[ConvIdx - 1].isBad()) + if (Cand->Conversions[ConvIdx - 1].isBad()) { + Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S); break; + } } if (ConvIdx == ConvCount) @@ -7360,13 +7602,17 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, // Fill in the rest of the conversions. unsigned NumArgsInProto = Proto->getNumArgs(); for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { - if (ArgIdx < NumArgsInProto) + if (ArgIdx < NumArgsInProto) { Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ S.getLangOptions().ObjCAutoRefCount); + // Store the FixIt in the candidate if it exists. + if (!Unfixable && Cand->Conversions[ConvIdx].isBad()) + Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S); + } else Cand->Conversions[ConvIdx].setEllipsis(); } @@ -7384,7 +7630,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, SourceLocation OpLoc) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. - llvm::SmallVector<OverloadCandidate*, 32> Cands; + SmallVector<OverloadCandidate*, 32> Cands; if (OCD == OCD_AllCandidates) Cands.reserve(size()); for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { if (Cand->Viable) @@ -7403,8 +7649,9 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, bool ReportedAmbiguousConversions = false; - llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E; - const Diagnostic::OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); + SmallVectorImpl<OverloadCandidate*>::iterator I, E; + const DiagnosticsEngine::OverloadsShown ShowOverloads = + S.Diags.getShowOverloads(); unsigned CandsShown = 0; for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { OverloadCandidate *Cand = *I; @@ -7412,7 +7659,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, // Set an arbitrary limit on the number of candidate functions we'll spam // the user with. FIXME: This limit should depend on details of the // candidate list. - if (CandsShown >= 4 && ShowOverloads == Diagnostic::Ovl_Best) { + if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) { break; } ++CandsShown; @@ -7485,7 +7732,7 @@ class AddressOfFunctionResolver OverloadExpr::FindResult OvlExprInfo; OverloadExpr *OvlExpr; TemplateArgumentListInfo OvlExplicitTemplateArgs; - llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; + SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; public: AddressOfFunctionResolver(Sema &S, Expr* SourceExpr, @@ -7607,6 +7854,11 @@ private: return false; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { + if (S.getLangOptions().CUDA) + if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) + if (S.CheckCUDATarget(Caller, FunDecl)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || @@ -7873,25 +8125,31 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, -// Resolve and fix an overloaded expression that -// can be resolved because it identifies a single function -// template specialization +// Resolve and fix an overloaded expression that can be resolved +// because it identifies a single function template specialization. +// // Last three arguments should only be supplied if Complain = true -ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( - Expr *SrcExpr, bool doFunctionPointerConverion, bool complain, - const SourceRange& OpRangeForComplaining, +// +// Return true if it was logically possible to so resolve the +// expression, regardless of whether or not it succeeded. Always +// returns true if 'complain' is set. +bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization( + ExprResult &SrcExpr, bool doFunctionPointerConverion, + bool complain, const SourceRange& OpRangeForComplaining, QualType DestTypeForComplaining, unsigned DiagIDForComplaining) { - assert(SrcExpr->getType() == Context.OverloadTy); + assert(SrcExpr.get()->getType() == Context.OverloadTy); - OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr); + OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get()); DeclAccessPair found; ExprResult SingleFunctionExpression; if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( ovl.Expression, /*complain*/ false, &found)) { - if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin())) - return ExprError(); + if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getSourceRange().getBegin())) { + SrcExpr = ExprError(); + return true; + } // It is only correct to resolve to an instance method if we're // resolving a form that's permitted to be a pointer to member. @@ -7900,28 +8158,34 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( if (!ovl.HasFormOfMemberPointer && isa<CXXMethodDecl>(fn) && cast<CXXMethodDecl>(fn)->isInstance()) { - if (complain) { - Diag(ovl.Expression->getExprLoc(), - diag::err_invalid_use_of_bound_member_func) - << ovl.Expression->getSourceRange(); - // TODO: I believe we only end up here if there's a mix of - // static and non-static candidates (otherwise the expression - // would have 'bound member' type, not 'overload' type). - // Ideally we would note which candidate was chosen and why - // the static candidates were rejected. - } - - return ExprError(); + if (!complain) return false; + + Diag(ovl.Expression->getExprLoc(), + diag::err_bound_member_function) + << 0 << ovl.Expression->getSourceRange(); + + // TODO: I believe we only end up here if there's a mix of + // static and non-static candidates (otherwise the expression + // would have 'bound member' type, not 'overload' type). + // Ideally we would note which candidate was chosen and why + // the static candidates were rejected. + SrcExpr = ExprError(); + return true; } // Fix the expresion to refer to 'fn'. SingleFunctionExpression = - Owned(FixOverloadedFunctionReference(SrcExpr, found, fn)); + Owned(FixOverloadedFunctionReference(SrcExpr.take(), found, fn)); // If desired, do function-to-pointer decay. - if (doFunctionPointerConverion) + if (doFunctionPointerConverion) { SingleFunctionExpression = DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take()); + if (SingleFunctionExpression.isInvalid()) { + SrcExpr = ExprError(); + return true; + } + } } if (!SingleFunctionExpression.isUsable()) { @@ -7931,12 +8195,17 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( << DestTypeForComplaining << OpRangeForComplaining << ovl.Expression->getQualifierLoc().getSourceRange(); - NoteAllOverloadCandidates(SrcExpr); - } - return ExprError(); + NoteAllOverloadCandidates(SrcExpr.get()); + + SrcExpr = ExprError(); + return true; + } + + return false; } - return SingleFunctionExpression; + SrcExpr = SingleFunctionExpression; + return true; } /// \brief Add a single candidate to the overload set. @@ -8164,7 +8433,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, ExplicitTemplateArgs, Args, NumArgs) && (!EmptyLookup || - SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))) + SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression, + ExplicitTemplateArgs, Args, NumArgs))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -8214,7 +8484,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, if (ULE->decls_begin() + 1 == ULE->decls_end() && (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) && F->getBuiltinID() && F->isImplicit()) - assert(0 && "performing ADL for builtin"); + llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. assert(getLangOptions().CPlusPlus && "ADL enabled in C"); @@ -8232,9 +8502,22 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, // If we found nothing, try to recover. // BuildRecoveryCallExpr diagnoses the error itself, so we just bail // out if it fails. - if (CandidateSet.empty()) + if (CandidateSet.empty()) { + // In Microsoft mode, if we are inside a template class member function then + // create a type dependent CallExpr. The goal is to postpone name lookup + // to instantiation time to be able to search into type dependent base + // classes. + if (getLangOptions().MicrosoftExt && CurContext->isDependentContext() && + isa<CXXMethodDecl>(CurContext)) { + CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs, + Context.DependentTy, VK_RValue, + RParenLoc); + CE->setTypeDependent(true); + return Owned(CE); + } return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, RParenLoc, /*EmptyLookup=*/true); + } OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { @@ -8379,6 +8662,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -8423,7 +8708,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates); if (FnExpr.isInvalid()) return ExprError(); @@ -8468,8 +8754,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << Input->getType() << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - Args, NumArgs, + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -8479,7 +8764,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs, + UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -8627,6 +8913,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -8688,7 +8976,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -8774,7 +9063,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << BinaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, + BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -8837,6 +9127,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Add builtin operator candidates. AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, LLoc, Best)) { @@ -8883,7 +9175,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, DeclarationNameLoc LocInfo; LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding(); LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding(); - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates, + LLoc, LocInfo); if (FnExpr.isInvalid()) return ExprError(); @@ -9059,7 +9353,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Microsoft supports direct constructor calls. - if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) { + if (getLangOptions().MicrosoftExt && isa<CXXConstructorDecl>(Func)) { AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs, CandidateSet); } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) { @@ -9231,8 +9525,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, } // C++ [over.call.object]p2: - // In addition, for each conversion function declared in T of the - // form + // In addition, for each (non-explicit in C++0x) conversion function + // declared in T of the form // // operator conversion-type-id () cv-qualifier; // @@ -9262,18 +9556,23 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, continue; CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) - ConvType = ConvPtrType->getPointeeType(); - - if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object.get(), Args, NumArgs, CandidateSet); + if (!Conv->isExplicit()) { + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); + + if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) + { + AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, + Object.get(), Args, NumArgs, CandidateSet); + } + } } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(), @@ -9332,7 +9631,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Create an implicit member expr to refer to the conversion operator. // and then call it. - ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, Conv); + ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, + Conv, HadMultipleCandidates); if (Call.isInvalid()) return ExprError(); @@ -9368,7 +9668,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) MethodArgs[ArgIdx + 1] = Args[ArgIdx]; - ExprResult NewFn = CreateFunctionRefExpr(*this, Method); + ExprResult NewFn = CreateFunctionRefExpr(*this, Method, + HadMultipleCandidates); if (NewFn.isInvalid()) return true; @@ -9498,6 +9799,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -9545,7 +9848,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { Base = BaseResult.take(); // Build the operator call. - ExprResult FnExpr = CreateFunctionRefExpr(*this, Method); + ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, + HadMultipleCandidates); if (FnExpr.isInvalid()) return ExprError(); @@ -9648,14 +9952,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, TemplateArgs = &TemplateArgsBuffer; } - return DeclRefExpr::Create(Context, - ULE->getQualifierLoc(), - Fn, - ULE->getNameLoc(), - Fn->getType(), - VK_LValue, - Found.getDecl(), - TemplateArgs); + DeclRefExpr *DRE = DeclRefExpr::Create(Context, + ULE->getQualifierLoc(), + Fn, + ULE->getNameLoc(), + Fn->getType(), + VK_LValue, + Found.getDecl(), + TemplateArgs); + DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); + return DRE; } if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) { @@ -9672,14 +9978,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, // implicit member access, rewrite to a simple decl ref. if (MemExpr->isImplicitAccess()) { if (cast<CXXMethodDecl>(Fn)->isStatic()) { - return DeclRefExpr::Create(Context, - MemExpr->getQualifierLoc(), - Fn, - MemExpr->getMemberLoc(), - Fn->getType(), - VK_LValue, - Found.getDecl(), - TemplateArgs); + DeclRefExpr *DRE = DeclRefExpr::Create(Context, + MemExpr->getQualifierLoc(), + Fn, + MemExpr->getMemberLoc(), + Fn->getType(), + VK_LValue, + Found.getDecl(), + TemplateArgs); + DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); + return DRE; } else { SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) @@ -9701,14 +10009,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, type = Context.BoundMemberTy; } - return MemberExpr::Create(Context, Base, - MemExpr->isArrow(), - MemExpr->getQualifierLoc(), - Fn, - Found, - MemExpr->getMemberNameInfo(), - TemplateArgs, - type, valueKind, OK_Ordinary); + MemberExpr *ME = MemberExpr::Create(Context, Base, + MemExpr->isArrow(), + MemExpr->getQualifierLoc(), + Fn, + Found, + MemExpr->getMemberNameInfo(), + TemplateArgs, + type, valueKind, OK_Ordinary); + ME->setHadMultipleCandidates(true); + return ME; } llvm_unreachable("Invalid reference to overloaded function"); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 65f431d..5351896 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -47,8 +47,8 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) { StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, - SourceLocation LeadingEmptyMacroLoc) { - return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacroLoc)); + bool HasLeadingEmptyMacro) { + return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro)); } StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, @@ -92,6 +92,56 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { } } +/// \brief Diagnose unused '==' and '!=' as likely typos for '=' or '|='. +/// +/// Adding a cast to void (or other expression wrappers) will prevent the +/// warning from firing. +static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { + SourceLocation Loc; + bool IsNotEqual, CanAssign; + + if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { + if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE) + return false; + + Loc = Op->getOperatorLoc(); + IsNotEqual = Op->getOpcode() == BO_NE; + CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue(); + } else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { + if (Op->getOperator() != OO_EqualEqual && + Op->getOperator() != OO_ExclaimEqual) + return false; + + Loc = Op->getOperatorLoc(); + IsNotEqual = Op->getOperator() == OO_ExclaimEqual; + CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue(); + } else { + // Not a typo-prone comparison. + return false; + } + + // Suppress warnings when the operator, suspicious as it may be, comes from + // a macro expansion. + if (Loc.isMacroID()) + return false; + + S.Diag(Loc, diag::warn_unused_comparison) + << (unsigned)IsNotEqual << E->getSourceRange(); + + // If the LHS is a plausible entity to assign to, provide a fixit hint to + // correct common typos. + if (CanAssign) { + if (IsNotEqual) + S.Diag(Loc, diag::note_inequality_comparison_to_or_assign) + << FixItHint::CreateReplacement(Loc, "|="); + else + S.Diag(Loc, diag::note_equality_comparison_to_assign) + << FixItHint::CreateReplacement(Loc, "="); + } + + return true; +} + void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) return DiagnoseUnusedExprResult(Label->getSubStmt()); @@ -114,6 +164,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) E = TempExpr->getSubExpr(); + if (DiagnoseUnusedComparison(*this, E)) + return; + E = E->IgnoreParenImpCasts(); if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) @@ -123,7 +176,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // a more specific message to make it clear what is happening. if (const Decl *FD = CE->getCalleeDecl()) { if (FD->getAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + Diag(Loc, diag::warn_unused_result) << R1 << R2; return; } if (FD->getAttr<PureAttr>()) { @@ -142,7 +195,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + Diag(Loc, diag::warn_unused_result) << R1 << R2; return; } } else if (isa<ObjCPropertyRefExpr>(E)) { @@ -238,6 +291,8 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, /// ActOnCaseStmtBody - This installs a statement as the body of a case. void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) { + DiagnoseUnusedExprResult(SubStmt); + CaseStmt *CS = static_cast<CaseStmt*>(caseStmt); CS->setSubStmt(SubStmt); } @@ -245,6 +300,8 @@ void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) { StmtResult Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope) { + DiagnoseUnusedExprResult(SubStmt); + if (getCurFunction()->SwitchStack.empty()) { Diag(DefaultLoc, diag::err_default_not_in_switch); return Owned(SubStmt); @@ -407,13 +464,12 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs, /// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of /// potentially integral-promoted expression @p expr. -static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { - if (const CastExpr *ImplicitCast = dyn_cast<ImplicitCastExpr>(expr)) { - const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr(); - QualType TypeBeforePromotion = ExprBeforePromotion->getType(); - if (TypeBeforePromotion->isIntegralOrEnumerationType()) { - return TypeBeforePromotion; - } +static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) { + if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr)) + expr = cleanups->getSubExpr(); + while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) { + if (impcast->getCastKind() != CK_IntegralCast) break; + expr = impcast->getSubExpr(); } return expr->getType(); } @@ -449,6 +505,11 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + CondResult = UsualUnaryConversions(Cond); + if (CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); + if (!CondVar) { CheckImplicitConversions(Cond, SwitchLoc); CondResult = MaybeCreateExprWithCleanups(Cond); @@ -482,21 +543,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, SS->setBody(BodyStmt, SwitchLoc); getCurFunction()->SwitchStack.pop_back(); - if (SS->getCond() == 0) - return StmtError(); - Expr *CondExpr = SS->getCond(); - Expr *CondExprBeforePromotion = CondExpr; - QualType CondTypeBeforePromotion = - GetTypeBeforeIntegralPromotion(CondExpr); + if (!CondExpr) return StmtError(); - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - ExprResult CondResult = UsualUnaryConversions(CondExpr); - if (CondResult.isInvalid()) - return StmtError(); - CondExpr = CondResult.take(); QualType CondType = CondExpr->getType(); - SS->setCond(CondExpr); + + Expr *CondExprBeforePromotion = CondExpr; + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExprBeforePromotion); // C++ 6.4.2.p2: // Integral promotions are performed (on the switch condition). @@ -533,7 +587,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after // it has been converted to the condition type. - typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; + typedef SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; CaseValsTy CaseVals; // Keep track of any GNU case ranges we see. The APSInt is the low value. @@ -572,7 +626,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, break; } - llvm::APSInt LoVal = Lo->EvaluateAsInt(Context); + llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context); // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, @@ -651,7 +705,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); - llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); + llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context); // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, @@ -750,7 +804,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); - typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> + typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; @@ -791,7 +845,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, << ED->getDeclName(); } - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + llvm::APSInt Hi = + RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); while (EI != EIend && EI->first < Hi) EI++; @@ -806,7 +861,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, CaseRangesTy::const_iterator RI = CaseRanges.begin(); bool hasCasesNotInSwitch = false; - llvm::SmallVector<DeclarationName,8> UnhandledNames; + SmallVector<DeclarationName,8> UnhandledNames; for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){ // Drop unneeded case values @@ -819,7 +874,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Drop unneeded case ranges for (; RI != CaseRanges.end(); RI++) { - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + llvm::APSInt Hi = + RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); if (EI->first <= Hi) break; @@ -965,6 +1021,76 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { return Owned(static_cast<Stmt*>(Result.get())); } +ExprResult +Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { + assert(collection); + + // Bail out early if we've got a type-dependent expression. + if (collection->isTypeDependent()) return Owned(collection); + + // Perform normal l-value conversion. + ExprResult result = DefaultFunctionArrayLvalueConversion(collection); + if (result.isInvalid()) + return ExprError(); + collection = result.take(); + + // The operand needs to have object-pointer type. + // TODO: should we do a contextual conversion? + const ObjCObjectPointerType *pointerType = + collection->getType()->getAs<ObjCObjectPointerType>(); + if (!pointerType) + return Diag(forLoc, diag::err_collection_expr_type) + << collection->getType() << collection->getSourceRange(); + + // Check that the operand provides + // - countByEnumeratingWithState:objects:count: + const ObjCObjectType *objectType = pointerType->getObjectType(); + ObjCInterfaceDecl *iface = objectType->getInterface(); + + // If we have a forward-declared type, we can't do this check. + if (iface && iface->isForwardDecl()) { + // This is ill-formed under ARC. + if (getLangOptions().ObjCAutoRefCount) { + Diag(forLoc, diag::err_arc_collection_forward) + << pointerType->getPointeeType() << collection->getSourceRange(); + } + + // Otherwise, if we have any useful type information, check that + // the type declares the appropriate method. + } else if (iface || !objectType->qual_empty()) { + IdentifierInfo *selectorIdents[] = { + &Context.Idents.get("countByEnumeratingWithState"), + &Context.Idents.get("objects"), + &Context.Idents.get("count") + }; + Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]); + + ObjCMethodDecl *method = 0; + + // If there's an interface, look in both the public and private APIs. + if (iface) { + method = iface->lookupInstanceMethod(selector); + if (!method) method = LookupPrivateInstanceMethod(selector, iface); + } + + // Also check protocol qualifiers. + if (!method) + method = LookupMethodInQualifiedType(selector, pointerType, + /*instance*/ true); + + // If we didn't find it anywhere, give up. + if (!method) { + Diag(forLoc, diag::warn_collection_expr_type) + << collection->getType() << selector << collection->getSourceRange(); + } + + // TODO: check for an incompatible signature? + } + + // Wrap up any cleanups in the expression. + return Owned(MaybeCreateExprWithCleanups(collection)); +} + StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -1000,38 +1126,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second && !Second->isTypeDependent()) { - ExprResult Result = DefaultFunctionArrayLvalueConversion(Second); - if (Result.isInvalid()) - return StmtError(); - Second = Result.take(); - QualType SecondType = Second->getType(); - if (!SecondType->isObjCObjectPointerType()) - Diag(ForLoc, diag::err_collection_expr_type) - << SecondType << Second->getSourceRange(); - else if (const ObjCObjectPointerType *OPT = - SecondType->getAsObjCInterfacePointerType()) { - llvm::SmallVector<IdentifierInfo *, 4> KeyIdents; - IdentifierInfo* selIdent = - &Context.Idents.get("countByEnumeratingWithState"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("objects"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("count"); - KeyIdents.push_back(selIdent); - Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); - if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { - if (!IDecl->isForwardDecl() && - !IDecl->lookupInstanceMethod(CSelector) && - !LookupMethodInQualifiedType(CSelector, OPT, true)) { - // Must further look into private implementation methods. - if (!LookupPrivateInstanceMethod(CSelector, IDecl)) - Diag(ForLoc, diag::warn_collection_expr_type) - << SecondType << CSelector << Second->getSourceRange(); - } - } - } - } + return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc)); } @@ -1244,10 +1339,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { SourceLocation RangeLoc = RangeVar->getLocation(); - ExprResult RangeRef = BuildDeclRefExpr(RangeVar, - RangeVarType.getNonReferenceType(), - VK_LValue, ColonLoc); - if (RangeRef.isInvalid()) + const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); + + ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType, + VK_LValue, ColonLoc); + if (BeginRangeRef.isInvalid()) + return StmtError(); + + ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType, + VK_LValue, ColonLoc); + if (EndRangeRef.isInvalid()) return StmtError(); QualType AutoType = Context.getAutoDeductType(); @@ -1275,8 +1376,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, // the program is ill-formed; // begin-expr is __range. - BeginExpr = RangeRef; - if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc, + BeginExpr = BeginRangeRef; + if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); return StmtError(); @@ -1294,12 +1395,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since // UnqAT is not incomplete and Range is not type-dependent. - assert(0 && "Unexpected array type in for-range"); - return StmtError(); + llvm_unreachable("Unexpected array type in for-range"); } // end-expr is __range + __bound. - EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(), + EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(), BoundExpr.get()); if (EndExpr.isInvalid()) return StmtError(); @@ -1340,13 +1440,14 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar, BEF_begin, BeginNameInfo, - BeginMemberLookup, RangeRef.get()); + BeginMemberLookup, + BeginRangeRef.get()); if (BeginExpr.isInvalid()) return StmtError(); EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar, BEF_end, EndNameInfo, - EndMemberLookup, RangeRef.get()); + EndMemberLookup, EndRangeRef.get()); if (EndExpr.isInvalid()) return StmtError(); } @@ -1366,11 +1467,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false); BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); - ExprResult BeginRef = BuildDeclRefExpr(BeginVar, - BeginType.getNonReferenceType(), + const QualType BeginRefNonRefType = BeginType.getNonReferenceType(); + ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(), VK_LValue, ColonLoc); + if (EndRef.isInvalid()) + return StmtError(); // Build and check __begin != __end expression. NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal, @@ -1385,6 +1491,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, } // Build and check ++__begin expression. + BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, + VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { @@ -1393,6 +1504,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, } // Build and check *__begin expression. + BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, + VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get()); if (DerefExpr.isInvalid()) { NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); @@ -1651,54 +1767,49 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. - ReturnStmt *Result = 0; - if (CurBlock->ReturnType->isVoidType()) { - if (RetValExp && !RetValExp->isTypeDependent() && - (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) { + const VarDecl *NRVOCandidate = 0; + if (FnRetType->isDependentType()) { + // Delay processing for now. TODO: there are lots of dependent + // types we can conclusively prove aren't void. + } else if (FnRetType->isVoidType()) { + if (RetValExp && + !(getLangOptions().CPlusPlus && + (RetValExp->isTypeDependent() || + RetValExp->getType()->isVoidType()))) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp = 0; } - Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp) { - if (!CurBlock->ReturnType->isDependentType()) - return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); - - Result = new (Context) ReturnStmt(ReturnLoc, 0, 0); - } else { - const VarDecl *NRVOCandidate = 0; - - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void block with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, + return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + } else if (!RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, NRVOCandidate != 0); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, - FnRetType, RetValExp); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); - } - - if (RetValExp) { - CheckImplicitConversions(RetValExp, ReturnLoc); - RetValExp = MaybeCreateExprWithCleanups(RetValExp); - } - - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + FnRetType, RetValExp); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); } + RetValExp = Res.take(); + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } - Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); + if (RetValExp) { + CheckImplicitConversions(RetValExp, ReturnLoc); + RetValExp = MaybeCreateExprWithCleanups(RetValExp); } + ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, + NRVOCandidate); // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. @@ -1883,7 +1994,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { /// isOperandMentioned - Return true if the specified operand # is mentioned /// anywhere in the decomposed asm string. static bool isOperandMentioned(unsigned OpNo, - llvm::ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { + ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; if (!Piece.isOperand()) continue; @@ -1910,25 +2021,25 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get()); - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. - if (AsmString->isWide()) + if (!AsmString->isAscii()) return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) << AsmString->getSourceRange()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef OutputName; + StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); - if (!Context.Target.validateOutputConstraint(Info)) + if (!Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); @@ -1944,20 +2055,20 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, OutputConstraintInfos.push_back(Info); } - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef InputName; + StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); - if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(), + if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) @@ -1995,13 +2106,13 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef Clobber = Literal->getString(); + StringRef Clobber = Literal->getString(); - if (!Context.Target.isValidClobber(Clobber)) + if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } @@ -2012,7 +2123,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. - llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; + SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) @@ -2033,6 +2144,10 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; + + if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) + continue; + QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) @@ -2154,6 +2269,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { if (Throw) { + Throw = MaybeCreateExprWithCleanups(Throw); ExprResult Result = DefaultLvalueConversion(Throw); if (Result.isInvalid()) return StmtError(); @@ -2188,29 +2304,36 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); } - + return BuildObjCAtThrowStmt(AtLoc, Throw); } -StmtResult -Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, - Stmt *SyncBody) { - getCurFunction()->setHasBranchProtectedScope(); - - ExprResult Result = DefaultLvalueConversion(SyncExpr); - if (Result.isInvalid()) - return StmtError(); +ExprResult +Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) { + ExprResult result = DefaultLvalueConversion(operand); + if (result.isInvalid()) + return ExprError(); + operand = result.take(); - SyncExpr = Result.take(); // Make sure the expression type is an ObjC pointer or "void *". - if (!SyncExpr->getType()->isDependentType() && - !SyncExpr->getType()->isObjCObjectPointerType()) { - const PointerType *PT = SyncExpr->getType()->getAs<PointerType>(); - if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) - << SyncExpr->getType() << SyncExpr->getSourceRange()); + QualType type = operand->getType(); + if (!type->isDependentType() && + !type->isObjCObjectPointerType()) { + const PointerType *pointerType = type->getAs<PointerType>(); + if (!pointerType || !pointerType->getPointeeType()->isVoidType()) + return Diag(atLoc, diag::error_objc_synchronized_expects_object) + << type << operand->getSourceRange(); } + // The operand to @synchronized is a full-expression. + return MaybeCreateExprWithCleanups(operand); +} + +StmtResult +Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, + Stmt *SyncBody) { + // We can't jump into or indirect-jump out of a @synchronized block. + getCurFunction()->setHasBranchProtectedScope(); return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody)); } @@ -2278,10 +2401,10 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, "The parser shouldn't call this if there are no handlers."); Stmt **Handlers = RawHandlers.get(); - llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers; + SmallVector<TypeWithHandler, 8> TypesWithHandlers; for (unsigned i = 0; i < NumHandlers; ++i) { - CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]); + CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]); if (!Handler->getExceptionDecl()) { if (i < NumHandlers - 1) return StmtError(Diag(Handler->getLocStart(), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index 3ac190e..8dda34c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -344,10 +344,12 @@ void Sema::LookupTemplateName(LookupResult &Found, if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise - } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>()) { + } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() || + FoundOuter.isAmbiguous()) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise + FoundOuter.clear(); } else if (!Found.isSuppressingDiagnostics()) { // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, @@ -422,7 +424,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); // Microsoft Visual C++ permits template parameters to be shadowed. - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) return false; // C++ [temp.local]p4: @@ -712,7 +714,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, /// has been parsed. S is the current scope. Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, SourceLocation TmpLoc, - TemplateParamsTy *Params, + TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *Name, SourceLocation NameLoc, @@ -783,7 +785,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, /// ActOnTemplateParameterList - Builds a TemplateParameterList that /// contains the template parameters in Params/NumParams. -Sema::TemplateParamsTy * +TemplateParameterList * Sema::ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, @@ -809,7 +811,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, - AccessSpecifier AS, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList** OuterTemplateParamLists) { assert(TemplateParams && TemplateParams->size() > 0 && @@ -844,6 +846,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RequireCompleteDeclContext(SS, SemanticContext)) return true; + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (SemanticContext->isDependentContext()) { + ContextRAII SavedContext(*this, SemanticContext); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; @@ -943,7 +954,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // definition, as part of error recovery? return true; } - } + } } else if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); @@ -997,7 +1008,17 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclarationName(Name), TemplateParams, NewClass, PrevClassTemplate); NewClass->setDescribedClassTemplate(NewTemplate); - + + if (PrevClassTemplate && PrevClassTemplate->isModulePrivate()) { + NewTemplate->setModulePrivate(); + } else if (ModulePrivateLoc.isValid()) { + if (PrevClassTemplate && !PrevClassTemplate->isModulePrivate()) + diagnoseModulePrivateRedeclaration(NewTemplate, PrevClassTemplate, + ModulePrivateLoc); + else + NewTemplate->setModulePrivate(); + } + // Build the type for the class template declaration now. QualType T = NewTemplate->getInjectedClassNameSpecialization(); T = Context.getInjectedClassNameType(NewClass, T); @@ -1519,7 +1540,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // The sequence of nested types to which we will match up the template // parameter lists. We first build this list by starting with the type named // by the nested-name-specifier and walking out until we run out of types. - llvm::SmallVector<QualType, 4> NestedTypes; + SmallVector<QualType, 4> NestedTypes; QualType T; if (SS.getScopeRep()) { if (CXXRecordDecl *Record @@ -1888,7 +1909,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, Converted)) return QualType(); @@ -1995,7 +2016,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), - ClassTemplate->getLocation(), + ClassTemplate->getTemplatedDecl()->getLocStart(), ClassTemplate->getLocation(), ClassTemplate, Converted.data(), @@ -2129,7 +2150,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) - return TypeResult(); + return TypeResult(true); // Check the tag kind if (const RecordType *RT = Result->getAs<RecordType>()) { @@ -2311,7 +2332,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, return TNK_Dependent_template_name; case UnqualifiedId::IK_LiteralOperatorId: - assert(false && "We don't support these; Parse shouldn't have allowed propagation"); + llvm_unreachable( + "We don't support these; Parse shouldn't have allowed propagation"); default: break; @@ -2327,7 +2349,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgumentLoc &AL, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. @@ -2408,7 +2430,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based @@ -2461,7 +2483,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2507,7 +2529,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted, + SmallVectorImpl<TemplateArgument> &Converted, NestedNameSpecifierLoc &QualifierLoc) { TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2543,7 +2565,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { if (!TypeParm->hasDefaultArgument()) return TemplateArgumentLoc(); @@ -2629,7 +2651,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, - llvm::SmallVectorImpl<TemplateArgument> &Converted, + SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) @@ -2669,8 +2691,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - return true; + llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Expression: { TemplateArgument Result; @@ -2792,8 +2813,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - return true; + llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: @@ -2834,7 +2854,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); unsigned NumArgs = TemplateArgs.size(); @@ -2871,7 +2891,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // corresponding parameter declared by the template in its // template-parameter-list. bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); - llvm::SmallVector<TemplateArgument, 2> ArgumentPack; + SmallVector<TemplateArgument, 2> ArgumentPack; TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); unsigned ArgIdx = 0; @@ -3235,6 +3255,10 @@ bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType( return false; } +bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) { + return Visit(T->getValueType()); +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) @@ -3358,7 +3382,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } } - if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) { + if (S.getLangOptions().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) { Converted = TemplateArgument(ArgIn); return false; } @@ -3820,8 +3844,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } Converted = TemplateArgument(Value, - ParamType->isEnumeralType() ? ParamType - : IntegerType); + ParamType->isEnumeralType() + ? Context.getCanonicalType(ParamType) + : IntegerType); return Owned(Arg); } @@ -3892,7 +3917,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, bool ObjCLifetimeConversion; if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), false, ObjCLifetimeConversion)) { - Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, + Arg->getValueKind()).take(); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { // We can't perform this conversion. @@ -3963,7 +3989,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Types match exactly: nothing more to do here. } else if (IsQualificationConversion(ArgType, ParamType, false, ObjCLifetimeConversion)) { - Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, + Arg->getValueKind()).take(); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -4131,10 +4158,22 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, assert(Arg.getKind() == TemplateArgument::Integral && "Operation is only valid for integral template arguments"); QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) + if (T->isAnyCharacterType()) { + CharacterLiteral::CharacterKind Kind; + if (T->isWideCharType()) + Kind = CharacterLiteral::Wide; + else if (T->isChar16Type()) + Kind = CharacterLiteral::UTF16; + else if (T->isChar32Type()) + Kind = CharacterLiteral::UTF32; + else + Kind = CharacterLiteral::Ascii; + return Owned(new (Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), T, Loc)); + Arg.getAsIntegral()->getZExtValue(), + Kind, T, Loc)); + } + if (T->isBooleanType()) return Owned(new (Context) CXXBoolLiteralExpr( Arg.getAsIntegral()->getBoolValue(), @@ -4496,9 +4535,18 @@ static bool CheckTemplateSpecializationScope(Sema &S, } if (S.CurContext->isRecord() && !IsPartialSpecialization) { - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; + if (S.getLangOptions().MicrosoftExt) { + // Do not warn for class scope explicit specialization during + // instantiation, warning was already emitted during pattern + // semantic analysis. + if (!S.ActiveTemplateInstantiations.size()) + S.Diag(Loc, diag::ext_function_specialization_in_class) + << Specialized; + } else { + S.Diag(Loc, diag::err_template_spec_decl_class_scope) + << Specialized; + return true; + } } // C++ [temp.class.spec]p6: @@ -4653,7 +4701,7 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, /// \returns true if there was an error, false otherwise. static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, TemplateParameterList *TemplateParams, - llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) { + SmallVectorImpl<TemplateArgument> &TemplateArgs) { const TemplateArgument *ArgList = TemplateArgs.data(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -4691,6 +4739,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, @@ -4821,7 +4870,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; @@ -4907,14 +4956,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // -- The argument list of the specialization shall not be identical // to the implicit argument list of the primary template. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) - << (TUK == TUK_Definition) - << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); + << (TUK == TUK_Definition) + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, Attr, TemplateParams, - AS_none, + AS_none, /*ModulePrivateLoc=*/SourceLocation(), TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); } @@ -4956,7 +5005,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // partial specialization are deducible from the template // arguments. If not, this class template partial specialization // will never be used. - llvm::SmallVector<bool, 8> DeducibleParams; + SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, TemplateParams->getDepth(), @@ -5056,6 +5105,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (ModulePrivateLoc.isValid()) + Diag(Specialization->getLocation(), diag::err_module_private_specialization) + << (isPartialSpecialization? 1 : 0) + << FixItHint::CreateRemoval(ModulePrivateLoc); + // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -5105,7 +5159,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Decl *Sema::ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { - return HandleDeclarator(S, D, move(TemplateParameterLists), false); + return HandleDeclarator(S, D, move(TemplateParameterLists)); } Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, @@ -5120,9 +5174,9 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, Scope *ParentScope = FnBodyScope->getParent(); + D.setFunctionDefinition(true); Decl *DP = HandleDeclarator(ParentScope, D, - move(TemplateParameterLists), - /*IsFunctionDefinition=*/true); + move(TemplateParameterLists)); if (FunctionTemplateDecl *FunctionTemplate = dyn_cast_or_null<FunctionTemplateDecl>(DP)) return ActOnStartOfFunctionDef(FnBodyScope, @@ -5176,8 +5230,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, switch (NewTSK) { case TSK_Undeclared: case TSK_ImplicitInstantiation: - assert(false && "Don't check implicit instantiations here"); - return false; + llvm_unreachable("Don't check implicit instantiations here"); case TSK_ExplicitSpecialization: switch (PrevTSK) { @@ -5309,9 +5362,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, break; } - assert(false && "Missing specialization/instantiation case?"); - - return false; + llvm_unreachable("Missing specialization/instantiation case?"); } /// \brief Perform semantic analysis for the given dependent function @@ -5482,12 +5533,10 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Take copies of (semantic and syntactic) template argument lists. const TemplateArgumentList* TemplArgs = new (Context) TemplateArgumentList(Specialization->getTemplateSpecializationArgs()); - const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs - ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0; FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/0, SpecInfo->getTemplateSpecializationKind(), - TemplArgsAsWritten); + ExplicitTemplateArgs); FD->setStorageClass(Specialization->getStorageClass()); // The "previous declaration" for this function template specialization is @@ -5793,7 +5842,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; @@ -5949,6 +5998,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, bool IsDependent = false; Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none, + /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(*this, 0, 0), Owned, IsDependent, false, false, TypeResult()); @@ -6114,9 +6164,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - - // FIXME: check for constexpr specifier. + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + if (D.getDeclSpec().isConstexprSpecified()) + // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is + // not already specified. + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_explicit_instantiation_constexpr); // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation @@ -6658,6 +6711,45 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { return false; } +/// \brief Rebuild the template parameters now that we know we're in a current +/// instantiation. +bool Sema::RebuildTemplateParamsInCurrentInstantiation( + TemplateParameterList *Params) { + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + Decl *Param = Params->getParam(I); + + // There is nothing to rebuild in a type parameter. + if (isa<TemplateTypeParmDecl>(Param)) + continue; + + // Rebuild the template parameter list of a template template parameter. + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Param)) { + if (RebuildTemplateParamsInCurrentInstantiation( + TTP->getTemplateParameters())) + return true; + + continue; + } + + // Rebuild the type of a non-type template parameter. + NonTypeTemplateParmDecl *NTTP = cast<NonTypeTemplateParmDecl>(Param); + TypeSourceInfo *NewTSI + = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), + NTTP->getLocation(), + NTTP->getDeclName()); + if (!NewTSI) + return true; + + if (NewTSI != NTTP->getTypeSourceInfo()) { + NTTP->setTypeSourceInfo(NewTSI); + NTTP->setType(NewTSI->getType()); + } + } + + return false; +} + /// \brief Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string @@ -6692,7 +6784,7 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } Out << " = "; - Args[I].print(Context.PrintingPolicy, Out); + Args[I].print(getPrintingPolicy(), Out); } Out << ']'; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index dcb4ff2..93ea89d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -85,7 +85,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, TemplateArgument Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced); + SmallVectorImpl<DeducedTemplateArgument> &Deduced); /// \brief Whether template argument deduction for two reference parameters /// resulted in the argument type, parameter type, or neither type being more @@ -117,10 +117,10 @@ DeduceTemplateArguments(Sema &S, QualType Param, QualType Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering = false, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + SmallVectorImpl<RefParamPartialOrderingComparison> * RefParamComparisons = 0); static Sema::TemplateDeductionResult @@ -129,7 +129,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch = true); /// \brief If the given expression is of a form that permits the deduction @@ -288,7 +288,7 @@ DeduceNonTypeTemplateArgument(Sema &S, llvm::APSInt Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -316,7 +316,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Expr *Value, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && @@ -347,7 +347,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Decl *D, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -372,7 +372,7 @@ DeduceTemplateArguments(Sema &S, TemplateName Param, TemplateName Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -431,7 +431,7 @@ DeduceTemplateArguments(Sema &S, const TemplateSpecializationType *Param, QualType Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. @@ -546,11 +546,11 @@ static TemplateParameter makeTemplateParameter(Decl *D) { /// \brief Prepare to perform template argument deduction for all of the /// arguments in a set of argument packs. static void PrepareArgumentPackDeduction(Sema &S, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - const llvm::SmallVectorImpl<unsigned> &PackIndices, - llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, - llvm::SmallVectorImpl< - llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const SmallVectorImpl<unsigned> &PackIndices, + SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + SmallVectorImpl< + SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) { // Save the deduced template arguments for each parameter pack expanded // by this pack expansion, then clear out the deduction. for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { @@ -581,11 +581,11 @@ static Sema::TemplateDeductionResult FinishArgumentPackDeduction(Sema &S, TemplateParameterList *TemplateParams, bool HasAnyArguments, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - const llvm::SmallVectorImpl<unsigned> &PackIndices, - llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, - llvm::SmallVectorImpl< - llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const SmallVectorImpl<unsigned> &PackIndices, + SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + SmallVectorImpl< + SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks, TemplateDeductionInfo &Info) { // Build argument packs for each of the parameter packs expanded by this // pack expansion. @@ -668,10 +668,10 @@ DeduceTemplateArguments(Sema &S, const QualType *Params, unsigned NumParams, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering = false, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + SmallVectorImpl<RefParamPartialOrderingComparison> * RefParamComparisons = 0) { // Fast-path check to see if we have too many/too few arguments. if (NumParams != NumArgs && @@ -733,11 +733,11 @@ DeduceTemplateArguments(Sema &S, // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; QualType Pattern = Expansion->getPattern(); { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -753,9 +753,9 @@ DeduceTemplateArguments(Sema &S, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -862,10 +862,10 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { + SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. QualType Param = S.Context.getCanonicalType(ParamIn); @@ -977,6 +977,10 @@ DeduceTemplateArguments(Sema &S, // cv-list T if (const TemplateTypeParmType *TemplateTypeParm = Param->getAs<TemplateTypeParmType>()) { + // Just skip any attempts to deduce from a placeholder type. + if (Arg->isPlaceholderType()) + return Sema::TDK_Success; + unsigned Index = TemplateTypeParm->getIndex(); bool RecanonicalizeArg = false; @@ -1018,6 +1022,17 @@ DeduceTemplateArguments(Sema &S, DeducedQs.removeObjCLifetime(); // Objective-C ARC: + // If template deduction would produce a lifetime qualifier on a type + // that is not a lifetime type, template argument deduction fails. + if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() && + !DeducedType->isDependentType()) { + Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); + return Sema::TDK_Underqualified; + } + + // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. if (S.getLangOptions().ObjCAutoRefCount && @@ -1101,7 +1116,17 @@ DeduceTemplateArguments(Sema &S, Info, Deduced, TDF); return Sema::TDK_NonDeducedMismatch; - + + // _Atomic T [extension] + case Type::Atomic: + if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>()) + return DeduceTemplateArguments(S, TemplateParams, + cast<AtomicType>(Param)->getValueType(), + AtomicArg->getValueType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; + // T * case Type::Pointer: { QualType PointeeType; @@ -1306,10 +1331,10 @@ DeduceTemplateArguments(Sema &S, // Visited contains the set of nodes we have already visited, while // ToVisit is our stack of records that we still need to visit. llvm::SmallPtrSet<const RecordType *, 8> Visited; - llvm::SmallVector<const RecordType *, 8> ToVisit; + SmallVector<const RecordType *, 8> ToVisit; ToVisit.push_back(RecordT); bool Successful = false; - llvm::SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0); + SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0); DeducedOrig = Deduced; while (!ToVisit.empty()) { // Retrieve the next class in the inheritance hierarchy. @@ -1515,7 +1540,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, TemplateArgument Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { // If the template argument is a pack expansion, perform template argument // deduction against the pattern of that expansion. This only occurs during // partial ordering. @@ -1524,8 +1549,7 @@ DeduceTemplateArguments(Sema &S, switch (Param.getKind()) { case TemplateArgument::Null: - assert(false && "Null template argument in parameter list"); - break; + llvm_unreachable("Null template argument in parameter list"); case TemplateArgument::Type: if (Arg.getKind() == TemplateArgument::Type) @@ -1667,7 +1691,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch) { // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not @@ -1720,10 +1744,10 @@ DeduceTemplateArguments(Sema &S, // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -1742,9 +1766,9 @@ DeduceTemplateArguments(Sema &S, // Save the deduced template arguments for each parameter pack expanded // by this pack expansion, then clear out the deduction. - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -1799,7 +1823,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { return DeduceTemplateArguments(S, TemplateParams, ParamList.data(), ParamList.size(), ArgList.data(), ArgList.size(), @@ -1815,8 +1839,7 @@ static bool isSameTemplateArg(ASTContext &Context, switch (X.getKind()) { case TemplateArgument::Null: - assert(false && "Comparing NULL template argument"); - break; + llvm_unreachable("Comparing NULL template argument"); case TemplateArgument::Type: return Context.getCanonicalType(X.getAsType()) == @@ -1940,11 +1963,11 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, unsigned ArgumentPackIndex, TemplateDeductionInfo &Info, bool InFunctionTemplate, - llvm::SmallVectorImpl<TemplateArgument> &Output) { + SmallVectorImpl<TemplateArgument> &Output) { if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. - llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder; + SmallVector<TemplateArgument, 2> PackedArgsBuilder; for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), PAEnd = Arg.pack_end(); PA != PAEnd; ++PA) { @@ -1996,7 +2019,7 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(Sema &S, ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info) { // Trap errors. Sema::SFINAETrap Trap(S); @@ -2006,7 +2029,7 @@ FinishTemplateArgumentDeduction(Sema &S, // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; TemplateParameterList *PartialParams = Partial->getTemplateParameters(); for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { NamedDecl *Param = PartialParams->getParam(I); @@ -2089,7 +2112,7 @@ FinishTemplateArgumentDeduction(Sema &S, return Sema::TDK_SubstitutionFailure; } - llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs; + SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; @@ -2125,7 +2148,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // specialization can be deduced from the actual template argument // list (14.8.2). SFINAETrap Trap(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, @@ -2183,8 +2206,8 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - llvm::SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info) { FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); @@ -2214,7 +2237,7 @@ Sema::SubstituteExplicitTemplateArguments( // declaration order of their corresponding template-parameters. The // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -2420,11 +2443,11 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, /// which the deduced argument types should be compared. Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) { + SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -2446,7 +2469,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NamedDecl *Param = TemplateParams->getParam(I); @@ -2566,7 +2589,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Specialization = cast_or_null<FunctionDecl>( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, MultiLevelTemplateArgumentList(*DeducedArgumentList))); - if (!Specialization) + if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == @@ -2578,6 +2601,14 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, !Trap.hasErrorOccurred()) Info.take(); + // There may have been an error that did not prevent us from constructing a + // declaration. Mark the declaration invalid and return with a substitution + // failure. + if (Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return TDK_SubstitutionFailure; + } + if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument @@ -2596,20 +2627,12 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } } - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; - } - // If we suppressed any diagnostics while performing template argument // deduction, and if we haven't already instantiated this declaration, // keep track of these diagnostics. They'll be emitted if this specialization // is actually used. if (Info.diag_begin() != Info.diag_end()) { - llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl()); if (Pos == SuppressedDiagnostics.end()) SuppressedDiagnostics[Specialization->getCanonicalDecl()] @@ -2710,7 +2733,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector<DeducedTemplateArgument, 8> + SmallVector<DeducedTemplateArgument, 8> Deduced(TemplateParams->size()); TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); Sema::TemplateDeductionResult Result @@ -2900,8 +2923,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, LocalInstantiationScope InstScope(*this); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; - llvm::SmallVector<QualType, 4> ParamTypes; + SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<QualType, 4> ParamTypes; unsigned NumExplicitlySpecified = 0; if (ExplicitTemplateArgs) { TemplateDeductionResult Result = @@ -2924,7 +2947,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); unsigned ArgIdx = 0; - llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs; + SmallVector<OriginalCallArg, 4> OriginalCallArgs; for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); ParamIdx != NumParams; ++ParamIdx) { QualType OrigParamType = ParamTypes[ParamIdx]; @@ -2946,16 +2969,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TDF)) continue; + // If we have nothing to deduce, we're done. + if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + continue; + // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. - if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, - ArgType)); + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, + ArgType)); if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, TemplateParams, - ParamType, ArgType, Info, Deduced, - TDF)) + = ::DeduceTemplateArguments(*this, TemplateParams, + ParamType, ArgType, Info, Deduced, + TDF)) return Result; continue; @@ -2974,10 +3000,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, break; QualType ParamPattern = ParamExpansion->getPattern(); - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(ParamPattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -2993,9 +3019,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -3095,9 +3121,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; unsigned NumExplicitlySpecified = 0; - llvm::SmallVector<QualType, 4> ParamTypes; + SmallVector<QualType, 4> ParamTypes; if (ExplicitTemplateArgs) { if (TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, @@ -3205,7 +3231,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // A) as described in 14.8.2.4. TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.conv]p4: @@ -3226,7 +3252,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // both P and A are pointers or member pointers. In this case, we // just ignore cv-qualifiers completely). if ((P->isPointerType() && A->isPointerType()) || - (P->isMemberPointerType() && P->isMemberPointerType())) + (P->isMemberPointerType() && A->isMemberPointerType())) TDF |= TDF_IgnoreQualifiers; if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, @@ -3342,7 +3368,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init, QualType FuncParam = FuncParamInfo->getType(); // Deduce type of TemplParam in Func(Init) - llvm::SmallVector<DeducedTemplateArgument, 1> Deduced; + SmallVector<DeducedTemplateArgument, 1> Deduced; Deduced.resize(1); QualType InitType = Init->getType(); unsigned TDF = 0; @@ -3380,12 +3406,12 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, unsigned Level, - llvm::SmallVectorImpl<bool> &Deduced); + SmallVectorImpl<bool> &Deduced); /// \brief If this is a non-static member function, static void MaybeAddImplicitObjectParameterType(ASTContext &Context, CXXMethodDecl *Method, - llvm::SmallVectorImpl<QualType> &ArgTypes) { + SmallVectorImpl<QualType> &ArgTypes) { if (Method->isStatic()) return; @@ -3414,7 +3440,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { + SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); @@ -3422,7 +3448,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, assert(Proto1 && Proto2 && "Function templates must have prototypes"); TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.partial]p3: @@ -3454,7 +3480,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // C++98/03 doesn't have this provision, so instead we drop the // first argument of the free function or static member, which // seems to match existing practice. - llvm::SmallVector<QualType, 4> Args1; + SmallVector<QualType, 4> Args1; unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1; if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) @@ -3462,7 +3488,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.insert(Args1.end(), Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); - llvm::SmallVector<QualType, 4> Args2; + SmallVector<QualType, 4> Args2; Skip2 = !S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2; if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) @@ -3524,7 +3550,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, } // Figure out which template parameters were used. - llvm::SmallVector<bool, 4> UsedParameters; + SmallVector<bool, 4> UsedParameters; UsedParameters.resize(TemplateParams->size()); switch (TPOC) { case TPOC_Call: { @@ -3605,7 +3631,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments) { - llvm::SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons; + SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons; bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments, 0); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, @@ -3853,7 +3879,7 @@ Sema::getMoreSpecializedPartialSpecialization( // know that every template parameter is deducible from the class // template partial specialization's template arguments, for // example. - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; TemplateDeductionInfo Info(Context, Loc); QualType PT1 = PS1->getInjectedSpecializationType(); @@ -3899,7 +3925,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used); + SmallVectorImpl<bool> &Used); /// \brief Mark the template parameters that are used by the given /// expression. @@ -3908,7 +3934,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const Expr *E, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { // We can deduce from a pack expansion. if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); @@ -3939,7 +3965,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, NestedNameSpecifier *NNS, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (!NNS) return; @@ -3956,7 +3982,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, TemplateName Name, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) { @@ -3980,7 +4006,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (T.isNull()) return; @@ -4113,6 +4139,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::Atomic: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<AtomicType>(T)->getValueType(), + OnlyDeduced, Depth, Used); + break; + case Type::DependentName: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, @@ -4206,7 +4239,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: @@ -4251,7 +4284,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a @@ -4269,7 +4302,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, /// call to the given function template. void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<bool> &Deduced) { + SmallVectorImpl<bool> &Deduced) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); @@ -4289,7 +4322,7 @@ bool hasDeducibleTemplateParameters(Sema &S, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<bool, 4> Deduced; + SmallVector<bool, 4> Deduced; Deduced.resize(TemplateParams->size()); ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(), Deduced); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index 1988f14..301bf6a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -98,8 +98,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { if (!RelativeToPrimary && - Function->getTemplateSpecializationKind() - == TSK_ExplicitSpecialization) + (Function->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization && + !Function->getClassScopeSpecializationPattern())) break; if (const TemplateArgumentList *TemplateArgs @@ -428,7 +429,7 @@ void Sema::PrintInstantiationStack() { // FIXME: In all of these cases, we need to show the template arguments unsigned InstantiationIdx = 0; - for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator + for (SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; @@ -483,7 +484,7 @@ void Sema::PrintInstantiationStack() { = TemplateSpecializationType::PrintTemplateArgumentList( Active->TemplateArgs, Active->NumTemplateArgs, - Context.PrintingPolicy); + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << (Template->getNameAsString() + TemplateArgsStr) @@ -537,7 +538,7 @@ void Sema::PrintInstantiationStack() { = TemplateSpecializationType::PrintTemplateArgumentList( Active->TemplateArgs, Active->NumTemplateArgs, - Context.PrintingPolicy); + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << (FD->getNameAsString() + TemplateArgsStr) @@ -591,7 +592,6 @@ void Sema::PrintInstantiationStack() { } llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { - using llvm::SmallVector; if (InNonInstantiationSFINAEContext) return llvm::Optional<TemplateDeductionInfo *>(0); @@ -681,14 +681,12 @@ namespace { bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, llvm::Optional<unsigned> &NumExpansions) { return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, - NumUnexpanded, TemplateArgs, ShouldExpand, RetainExpansion, @@ -1535,8 +1533,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, bool Sema::SubstParmTypes(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<QualType> &ParamTypes, - llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) { + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -1558,7 +1556,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { bool Invalid = false; - llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; + SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; for (ClassTemplateSpecializationDecl::base_class_iterator Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { @@ -1572,7 +1570,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, if (Base->isPackExpansion()) { // This is a pack expansion. See whether we should expand it now, or // wait until later. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(), Unexpanded); bool ShouldExpand = false; @@ -1580,7 +1578,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, llvm::Optional<unsigned> NumExpansions; if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(), Base->getSourceRange(), - Unexpanded.data(), Unexpanded.size(), + Unexpanded, TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -1755,8 +1753,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Invalid = true; TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); - llvm::SmallVector<Decl*, 4> Fields; - llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> + SmallVector<Decl*, 4> Fields; + SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> FieldsWithMemberInitializers; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); @@ -1796,9 +1794,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, } // Finish checking fields. - ActOnFields(0, Instantiation->getLocation(), Instantiation, - Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), - 0); + ActOnFields(0, Instantiation->getLocation(), Instantiation, Fields, + SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Instantiation); // Attach any in-class member initializers now the class is complete. @@ -1806,39 +1803,24 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, FieldDecl *OldField = FieldsWithMemberInitializers[I].first; FieldDecl *NewField = FieldsWithMemberInitializers[I].second; Expr *OldInit = OldField->getInClassInitializer(); - ExprResult NewInit = SubstExpr(OldInit, TemplateArgs); - - // If the initialization is no longer dependent, check it now. - if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() || - OldInit->isValueDependent()) && - !NewField->getType()->isDependentType() && - !NewInit.get()->isTypeDependent() && - !NewInit.get()->isValueDependent()) { - // FIXME: handle list-initialization - SourceLocation EqualLoc = NewField->getLocation(); - NewInit = PerformCopyInitialization( - InitializedEntity::InitializeMember(NewField), EqualLoc, - NewInit.release()); - - if (!NewInit.isInvalid()) { - CheckImplicitConversions(NewInit.get(), EqualLoc); - - // C++0x [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - NewInit = MaybeCreateExprWithCleanups(NewInit); - } - } - if (NewInit.isInvalid()) + SourceLocation LParenLoc, RParenLoc; + ASTOwningVector<Expr*> NewArgs(*this); + if (InstantiateInitializer(OldInit, TemplateArgs, LParenLoc, NewArgs, + RParenLoc)) NewField->setInvalidDecl(); - else - NewField->setInClassInitializer(NewInit.release()); + else { + assert(NewArgs.size() == 1 && "wrong number of in-class initializers"); + ActOnCXXInClassMemberInitializer(NewField, LParenLoc, NewArgs[0]); + } } if (!FieldsWithMemberInitializers.empty()) ActOnFinishDelayedMemberInitializers(Instantiation); + if (TSK == TSK_ImplicitInstantiation) + Instantiation->setRBraceLoc(Pattern->getRBraceLoc()); + if (Instantiation->isInvalidDecl()) Invalid = true; else { @@ -1931,8 +1913,8 @@ Sema::InstantiateClassTemplateSpecialization( // specialization with the template argument lists of the partial // specializations. typedef PartialSpecMatchResult MatchResult; - llvm::SmallVector<MatchResult, 4> Matched; - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + SmallVector<MatchResult, 4> Matched; + SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; Template->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; @@ -1954,10 +1936,10 @@ Sema::InstantiateClassTemplateSpecialization( // If we're dealing with a member template where the template parameters // have been instantiated, this provides the original template parameters // from which the member template's parameters were instantiated. - llvm::SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; if (Matched.size() >= 1) { - llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); + SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); if (Matched.size() == 1) { // -- If exactly one matching specialization is found, the // instantiation is generated from that specialization. @@ -1970,7 +1952,7 @@ Sema::InstantiateClassTemplateSpecialization( // specialized than all of the other matching // specializations, then the use of the class template is // ambiguous and the program is ill-formed. - for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, + for (SmallVector<MatchResult, 4>::iterator P = Best + 1, PEnd = Matched.end(); P != PEnd; ++P) { if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, @@ -1982,7 +1964,7 @@ Sema::InstantiateClassTemplateSpecialization( // Determine if the best partial specialization is more specialized than // the others. bool Ambiguous = false; - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); P != PEnd; ++P) { if (P != Best && @@ -2001,7 +1983,7 @@ Sema::InstantiateClassTemplateSpecialization( << ClassTemplateSpec; // Print the matching partial specializations. - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); P != PEnd; ++P) Diag(P->Partial->getLocation(), diag::note_partial_spec_match) @@ -2240,7 +2222,7 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<Expr *> &Outputs) { + SmallVectorImpl<Expr *> &Outputs) { if (NumExprs == 0) return false; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 29385e5..02a05d5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -29,14 +29,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, DeclaratorDecl *NewDecl) { if (!OldDecl->getQualifierLoc()) return false; - + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), TemplateArgs); - + if (!NewQualifierLoc) return true; - + NewDecl->setQualifierInfo(NewQualifierLoc); return false; } @@ -45,14 +45,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl) { if (!OldDecl->getQualifierLoc()) return false; - + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), TemplateArgs); - + if (!NewQualifierLoc) return true; - + NewDecl->setQualifierInfo(NewQualifierLoc); return false; } @@ -79,7 +79,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, else { TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(), TemplateArgs, - Aligned->getLocation(), + Aligned->getLocation(), DeclarationName()); if (Result) AddAlignedAttr(Aligned->getLocation(), New, Result); @@ -96,8 +96,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, Decl * TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - assert(false && "Translation units cannot be instantiated"); - return D; + llvm_unreachable("Translation units cannot be instantiated"); } Decl * @@ -110,8 +109,7 @@ TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { Decl * TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { - assert(false && "Namespaces cannot be instantiated"); - return D; + llvm_unreachable("Namespaces cannot be instantiated"); } Decl * @@ -165,13 +163,13 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, newTag->setTypedefNameForAnonDecl(Typedef); } } - + if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); if (!InstPrev) return 0; - + Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev)); } @@ -230,7 +228,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { if (!PrevAliasTemplate) Inst->setInstantiatedFromMemberTemplate(D); - + Owner->addDecl(Inst); return Inst; @@ -239,8 +237,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { /// \brief Instantiate an initializer, breaking it into separate /// initialization arguments. /// -/// \param S The semantic analysis object. -/// /// \param Init The initializer to instantiate. /// /// \param TemplateArgs Template arguments to be substituted into the @@ -249,11 +245,11 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { /// \param NewArgs Will be filled in with the instantiation arguments. /// /// \returns true if an error occurred, false otherwise -static bool InstantiateInitializer(Sema &S, Expr *Init, +bool Sema::InstantiateInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation &LParenLoc, - ASTOwningVector<Expr*> &NewArgs, - SourceLocation &RParenLoc) { + SourceLocation &LParenLoc, + ASTOwningVector<Expr*> &NewArgs, + SourceLocation &RParenLoc) { NewArgs.clear(); LParenLoc = SourceLocation(); RParenLoc = SourceLocation(); @@ -273,24 +269,24 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { LParenLoc = ParenList->getLParenLoc(); RParenLoc = ParenList->getRParenLoc(); - return S.SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), - true, TemplateArgs, NewArgs); + return SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), + true, TemplateArgs, NewArgs); } if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) { if (!isa<CXXTemporaryObjectExpr>(Construct)) { - if (S.SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, - TemplateArgs, NewArgs)) + if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, + TemplateArgs, NewArgs)) return true; // FIXME: Fake locations! - LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); + LParenLoc = PP.getLocForEndOfToken(Init->getLocStart()); RParenLoc = LParenLoc; return false; } } - - ExprResult Result = S.SubstExpr(Init, TemplateArgs); + + ExprResult Result = SubstExpr(Init, TemplateArgs); if (Result.isInvalid()) return true; @@ -319,7 +315,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { << D->isStaticDataMember() << DI->getType(); return 0; } - + // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), @@ -342,21 +338,20 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setAccess(D->getAccess()); - + if (!D->isStaticDataMember()) { Var->setUsed(D->isUsed(false)); Var->setReferenced(D->isReferenced()); } - + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. - bool Redeclaration = false; // FIXME: having to fake up a LookupResult is dumb. LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); if (D->isStaticDataMember()) SemaRef.LookupQualifiedName(Previous, Owner, false); - SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); + SemaRef.CheckVariableDeclaration(Var, Previous); if (D->isOutOfLine()) { if (!D->isStaticDataMember()) @@ -368,13 +363,13 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); } SemaRef.InstantiateAttrs(TemplateArgs, D, Var); - + // Link instantiations of static data members back to the template from // which they were instantiated. if (Var->isStaticDataMember()) - SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, + SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, TSK_ImplicitInstantiation); - + if (Var->getAnyInitializer()) { // We already have an initializer in the class. } else if (D->getInit()) { @@ -386,8 +381,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Instantiate the initializer. SourceLocation LParenLoc, RParenLoc; ASTOwningVector<Expr*> InitArgs(SemaRef); - if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc, - InitArgs, RParenLoc)) { + if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc, + InitArgs, RParenLoc)) { bool TypeMayContainAuto = true; // Attach the initializer to the declaration, if we have one. if (InitArgs.size() == 0) @@ -409,7 +404,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // because of a bogus initializer. Var->setInvalidDecl(); } - + SemaRef.PopExpressionEvaluationContext(); } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && !Var->isCXXForRangeDecl()) @@ -489,14 +484,14 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } SemaRef.InstantiateAttrs(TemplateArgs, D, Field); - + if (Invalid) Field->setInvalidDecl(); if (!Field->getDeclName()) { // Keep track of where this decl came from. SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D); - } + } if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) { if (Parent->isAnonymousStructOrUnion() && Parent->getRedeclContext()->isFunctionOrMethod()) @@ -518,11 +513,11 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), PE = D->chain_end(); PI != PE; ++PI) { - NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI, + NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI, TemplateArgs); if (!Next) return 0; - + NamedChain[i++] = Next; } @@ -560,13 +555,13 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); if (!FD) return 0; - + FD->setAccess(AS_public); FD->setUnsupportedFriend(D->isUnsupportedFriend()); Owner->addDecl(FD); return FD; - } - + } + NamedDecl *ND = D->getFriendDecl(); assert(ND && "friend decl must be a decl or a type!"); @@ -578,7 +573,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { if (!NewND) return 0; FriendDecl *FD = - FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); FD->setUnsupportedFriend(D->isUnsupportedFriend()); @@ -620,7 +615,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { TemplateArgs, UnderlyingLoc, DeclarationName())); - + if (!Enum->getIntegerTypeSourceInfo()) Enum->setIntegerType(SemaRef.Context.IntTy); } @@ -641,8 +636,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { if (D->getDeclContext()->isFunctionOrMethod()) SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); - - llvm::SmallVector<Decl*, 4> Enumerators; + + SmallVector<Decl*, 4> Enumerators; EnumConstantDecl *LastEnumConst = 0; for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(), @@ -683,7 +678,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { Enum->addDecl(EnumConst); Enumerators.push_back(EnumConst); LastEnumConst = EnumConst; - + if (D->getDeclContext()->isFunctionOrMethod()) { // If the enumeration is within a function or method, record the enum // constant as a local. @@ -703,8 +698,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { - assert(false && "EnumConstantDecls can only occur within EnumDecls."); - return 0; + llvm_unreachable("EnumConstantDecls can only occur within EnumDecls."); } Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { @@ -789,7 +783,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // template parameters of the original declaration. In this one // case, we don't complain about the ill-formed friend // declaration. - if (isFriend && Pattern->getIdentifier() && + if (isFriend && Pattern->getIdentifier() && Pattern->getIdentifier()->isStr("_Map_base") && DC->isNamespace() && cast<NamespaceDecl>(DC)->getIdentifier() && @@ -812,7 +806,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Make sure the parameter lists match. if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, - Complain, + Complain, Sema::TPL_TemplateMatch)) { if (Complain) return 0; @@ -859,7 +853,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (!PrevClassTemplate) Inst->setInstantiatedFromMemberTemplate(D); } - + // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization()); @@ -869,14 +863,14 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } - + Owner->addDecl(Inst); if (!PrevClassTemplate) { // Queue up any out-of-line partial specializations of this member // class template; the client will force their instantiation once // the enclosing class has been instantiated. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; D->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) if (PartialSpecs[I]->isOutOfLine()) @@ -890,19 +884,19 @@ Decl * TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate(); - + // Lookup the already-instantiated declaration in the instantiation // of the class template and return that. DeclContext::lookup_result Found = Owner->lookup(ClassTemplate->getDeclName()); if (Found.first == Found.second) return 0; - + ClassTemplateDecl *InstClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first); if (!InstClassTemplate) return 0; - + if (ClassTemplatePartialSpecializationDecl *Result = InstClassTemplate->findPartialSpecInstantiatedFromMember(D)) return Result; @@ -914,7 +908,7 @@ Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Create a local instantiation scope for this function template, which // will contain the instantiations of the template parameters and then get - // merged with the local instantiation scope for the function template + // merged with the local instantiation scope for the function template // itself. LocalInstantiationScope Scope(SemaRef); @@ -922,16 +916,16 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - + FunctionDecl *Instantiated = 0; if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl())) - Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, + Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, InstParams)); else Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl( - D->getTemplatedDecl(), + D->getTemplatedDecl(), InstParams)); - + if (!Instantiated) return 0; @@ -939,10 +933,10 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Link the instantiated function template declaration to the function // template from which it was instantiated. - FunctionTemplateDecl *InstTemplate + FunctionTemplateDecl *InstTemplate = Instantiated->getDescribedFunctionTemplate(); InstTemplate->setAccess(D->getAccess()); - assert(InstTemplate && + assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None); @@ -952,7 +946,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!InstTemplate->getInstantiatedFromMemberTemplate() && !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); - + // Make declarations visible in the appropriate context. if (!isFriend) Owner->addDecl(InstTemplate); @@ -1018,7 +1012,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; if (FunctionTemplate && !TemplateParams) { - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); FunctionDecl *SpecFunc @@ -1038,11 +1032,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool MergeWithParentScope = (TemplateParams != 0) || Owner->isFunctionOrMethod() || - !(isa<Decl>(Owner) && + !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); - llvm::SmallVector<ParmVarDecl *, 4> Params; + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = D->getTypeSourceInfo(); TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1068,7 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, DC = SemaRef.computeDeclContext(SS); if (!DC) return 0; } else { - DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), + DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), TemplateArgs); } @@ -1076,7 +1070,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getLocation(), D->getDeclName(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), - D->isInlineSpecified(), D->hasWrittenPrototype()); + D->isInlineSpecified(), D->hasWrittenPrototype(), + /*isConstexpr*/ false); if (QualifierLoc) Function->setQualifierInfo(QualifierLoc); @@ -1110,7 +1105,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params.push_back(Param); } } - Function->setParams(Params.data(), Params.size()); + Function->setParams(Params); SourceLocation InstantiateAtPOI; if (TemplateParams) { @@ -1124,7 +1119,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // // X<int> x; // - // We are instantiating the friend function template "f" within X<int>, + // We are instantiating the friend function template "f" within X<int>, // which means substituting int for T, but leaving "f" as a friend function // template. // Build the function template itself. @@ -1144,25 +1139,28 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost.first, Innermost.second), InsertPos); - } else if (isFriend && D->isThisDeclarationADefinition()) { - // TODO: should we remember this connection regardless of whether - // the friend declaration provided a body? + } else if (isFriend) { + // Note, we need this connection even if the friend doesn't have a body. + // Its body may exist but not have been attached yet due to deferred + // parsing. + // FIXME: It might be cleaner to set this when attaching the body to the + // friend function declaration, however that would require finding all the + // instantiations and modifying them. Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - + if (InitFunctionInstantiation(Function, D)) Function->setInvalidDecl(); - bool Redeclaration = false; bool isExplicitSpecialization = false; - + LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); @@ -1194,15 +1192,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, &ExplicitArgs, Previous)) Function->setInvalidDecl(); - + isExplicitSpecialization = true; } else if (TemplateParams || !FunctionTemplate) { - // Look only into the namespace where the friend would be declared to - // find a previous declaration. This is the innermost enclosing namespace, + // Look only into the namespace where the friend would be declared to + // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. SemaRef.LookupQualifiedName(Previous, DC); - + // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a @@ -1210,9 +1208,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (Previous.isSingleTagDecl()) Previous.clear(); } - + SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - isExplicitSpecialization, Redeclaration); + isExplicitSpecialization); NamedDecl *PrincipalDecl = (TemplateParams ? cast<NamedDecl>(FunctionTemplate) @@ -1238,11 +1236,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, const FunctionDecl *Definition = 0; if (Function->isDefined(Definition) && Definition->getTemplateSpecializationKind() == TSK_Undeclared) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); - Function->setInvalidDecl(); - } + Function->setInvalidDecl(); + } // Check for redefinitions due to other instantiations of this or // a similar friend function. else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(), @@ -1269,7 +1267,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (const FunctionDecl *RPattern = R->getTemplateInstantiationPattern()) if (RPattern->isDefined(RPattern)) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(R->getLocation(), diag::note_previous_definition); Function->setInvalidDecl(); @@ -1290,14 +1288,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Decl * TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams) { + TemplateParameterList *TemplateParams, + bool IsClassScopeSpecialization) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function // template. Check whether there is already a function template // specialization for this particular set of template arguments. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); FunctionDecl *SpecFunc @@ -1316,12 +1315,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, isFriend = (D->getFriendObjectKind() != Decl::FOK_None); bool MergeWithParentScope = (TemplateParams != 0) || - !(isa<Decl>(Owner) && + !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); // Instantiate enclosing template arguments for friends. - llvm::SmallVector<TemplateParameterList *, 4> TempParamLists; + SmallVector<TemplateParameterList *, 4> TempParamLists; unsigned NumTempParamLists = 0; if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) { TempParamLists.set_size(NumTempParamLists); @@ -1334,7 +1333,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } } - llvm::SmallVector<ParmVarDecl *, 4> Params; + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = D->getTypeSourceInfo(); TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1352,18 +1351,18 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // synthesized in the method declaration. if (!isa<FunctionProtoType>(T.IgnoreParens())) { assert(!Params.size() && "Instantiating type could not yield parameters"); - llvm::SmallVector<QualType, 4> ParamTypes; - if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), - D->getNumParams(), TemplateArgs, ParamTypes, + SmallVector<QualType, 4> ParamTypes; + if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), + D->getNumParams(), TemplateArgs, ParamTypes, &Params)) - return 0; + return 0; } NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); - if (!QualifierLoc) + if (!QualifierLoc) return 0; } @@ -1396,7 +1395,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), - false); + false, /*isConstexpr*/ false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1407,6 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit(), + /*isConstexpr*/ false, Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, @@ -1414,7 +1414,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, D->isStatic(), D->getStorageClassAsWritten(), D->isInlineSpecified(), - D->getLocEnd()); + /*isConstexpr*/ false, D->getLocEnd()); } if (QualifierLoc) @@ -1446,7 +1446,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, @@ -1457,7 +1457,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - + // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -1475,7 +1475,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Method); - Method->setParams(Params.data(), Params.size()); + Method->setParams(Params); if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); @@ -1494,8 +1494,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Previous.clear(); } - bool Redeclaration = false; - SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration); + if (!IsClassScopeSpecialization) + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -1514,7 +1514,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, : Method); if (isFriend) Record->makeDeclVisibleInContext(DeclToAdd); - else + else if (!IsClassScopeSpecialization) Owner->addDecl(DeclToAdd); } @@ -1558,14 +1558,14 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->wasDeclaredWithTypename(), D->isParameterPack()); Inst->setAccess(AS_public); - + if (D->hasDefaultArgument()) - Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); + Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); - // Introduce this template parameter's instantiation into the instantiation + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); - + return Inst; } @@ -1573,26 +1573,26 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc(); - llvm::SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; - llvm::SmallVector<QualType, 4> ExpandedParameterPackTypes; + SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; + SmallVector<QualType, 4> ExpandedParameterPackTypes; bool IsExpandedParameterPack = false; - TypeSourceInfo *DI; + TypeSourceInfo *DI; QualType T; bool Invalid = false; if (D->isExpandedParameterPack()) { - // The non-type template parameter pack is an already-expanded pack + // The non-type template parameter pack is an already-expanded pack // expansion of types. Substitute into each of the expanded types. ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes()); ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes()); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewDI) return 0; - + ExpandedParameterPackTypesAsWritten.push_back(NewDI); QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(), D->getLocation()); @@ -1600,7 +1600,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return 0; ExpandedParameterPackTypes.push_back(NewT); } - + IsExpandedParameterPack = true; DI = D->getTypeSourceInfo(); T = DI->getType(); @@ -1610,9 +1610,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( // types. PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL); TypeLoc Pattern = Expansion.getPatternLoc(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); - + // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; @@ -1622,22 +1622,21 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(), Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, TemplateArgs, - Expand, RetainExpansion, + Expand, RetainExpansion, NumExpansions)) return 0; - + if (Expand) { for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewDI) return 0; - + ExpandedParameterPackTypesAsWritten.push_back(NewDI); QualType NewT = SemaRef.CheckNonTypeTemplateParameterType( NewDI->getType(), @@ -1646,7 +1645,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return 0; ExpandedParameterPackTypes.push_back(NewT); } - + // Note that we have an expanded parameter pack. The "type" of this // expanded parameter pack is the original expansion type, but callers // will end up using the expanded parameter pack types for type-checking. @@ -1658,62 +1657,62 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( // pattern and create a new pack expansion type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewPattern) return 0; - + DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(), NumExpansions); if (!DI) return 0; - + T = DI->getType(); } } else { // Simple case: substitution into a parameter that is not a parameter pack. - DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) return 0; - + // Check that this type is acceptable for a non-type template parameter. - T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), + T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), D->getLocation()); if (T.isNull()) { T = SemaRef.Context.IntTy; Invalid = true; } } - + NonTypeTemplateParmDecl *Param; if (IsExpandedParameterPack) - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes.data(), ExpandedParameterPackTypes.size(), ExpandedParameterPackTypesAsWritten.data()); else - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), T, + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), T, D->isParameterPack(), DI); - + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); - + Param->setDefaultArgument(D->getDefaultArgument(), false); - - // Introduce this template parameter's instantiation into the instantiation + + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); return Param; @@ -1732,34 +1731,34 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - } - + } + // Build the template template parameter. TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->isParameterPack(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); Param->setAccess(AS_public); - - // Introduce this template parameter's instantiation into the instantiation + + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); - + return Param; } Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { // Using directives are never dependent (and never contain any types or // expressions), so they require no explicit instantiation work. - + UsingDirectiveDecl *Inst = UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getNamespaceKeyLocation(), + D->getNamespaceKeyLocation(), D->getQualifierLoc(), - D->getIdentLocation(), - D->getNominatedNamespace(), + D->getIdentLocation(), + D->getNominatedNamespace(), D->getCommonAncestor()); Owner->addDecl(Inst); return Inst; @@ -1863,7 +1862,7 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); if (!QualifierLoc) return 0; @@ -1891,7 +1890,7 @@ Decl * TemplateDeclInstantiator = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); if (!QualifierLoc) return 0; - + CXXScopeSpec SS; SS.Adopt(QualifierLoc); @@ -1909,6 +1908,29 @@ Decl * TemplateDeclInstantiator return UD; } + +Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *Decl) { + CXXMethodDecl *OldFD = Decl->getSpecialization(); + CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, 0, true)); + + LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, + Sema::ForRedeclaration); + + SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext); + if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, 0, Previous)) { + NewFD->setInvalidDecl(); + return NewFD; + } + + // Associate the specialization with the pattern. + FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl()); + assert(Specialization && "Class scope Specialization is null"); + SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); + + return NewFD; +} + Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); @@ -1930,7 +1952,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { bool Invalid = false; unsigned N = L->size(); - typedef llvm::SmallVector<NamedDecl *, 8> ParamVector; + typedef SmallVector<NamedDecl *, 8> ParamVector; ParamVector Params; Params.reserve(N); for (TemplateParameterList::iterator PI = L->begin(), PE = L->end(); @@ -1951,13 +1973,13 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { return InstL; } -/// \brief Instantiate the declaration of a class template partial +/// \brief Instantiate the declaration of a class template partial /// specialization. /// /// \param ClassTemplate the (instantiated) class template that is partially // specialized by the instantiation of \p PartialSpec. /// -/// \param PartialSpec the (uninstantiated) class template partial +/// \param PartialSpec the (uninstantiated) class template partial /// specialization that we are instantiating. /// /// \returns The instantiated partial specialization, if successful; otherwise, @@ -1970,28 +1992,28 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // specialization, which will contain the instantiations of the template // parameters. LocalInstantiationScope Scope(SemaRef); - + // Substitute into the template parameters of the class template partial // specialization. TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return 0; - + // Substitute into the template arguments of the class template partial // specialization. TemplateArgumentListInfo InstTemplateArgs; // no angle locations - if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), - PartialSpec->getNumTemplateArgsAsWritten(), + if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), + PartialSpec->getNumTemplateArgsAsWritten(), InstTemplateArgs, TemplateArgs)) return 0; - + // Check that the template argument list is well-formed for this // class template. - llvm::SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList(ClassTemplate, + SmallVector<TemplateArgument, 4> Converted; + if (SemaRef.CheckTemplateArgumentList(ClassTemplate, PartialSpec->getLocation(), - InstTemplateArgs, + InstTemplateArgs, false, Converted)) return 0; @@ -2002,10 +2024,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplateSpecializationDecl *PrevDecl = ClassTemplate->findPartialSpecialization(Converted.data(), Converted.size(), InsertPos); - + // Build the canonical type that describes the converted template // arguments of the class template partial specialization. - QualType CanonType + QualType CanonType = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), Converted.data(), Converted.size()); @@ -2023,7 +2045,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( PartialSpec->getLocation(), InstTemplateArgs, CanonType); - + if (PrevDecl) { // We've already seen a partial specialization with the same template // parameters and template arguments. This can happen, for example, when @@ -2046,17 +2068,17 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( << SemaRef.Context.getTypeDeclType(PrevDecl); return 0; } - - + + // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec - = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, PartialSpec->getTagKind(), - Owner, + Owner, PartialSpec->getLocStart(), PartialSpec->getLocation(), InstParams, - ClassTemplate, + ClassTemplate, Converted.data(), Converted.size(), InstTemplateArgs, @@ -2069,7 +2091,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - + // Add this partial specialization to the set of class template partial // specializations. ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos); @@ -2078,7 +2100,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl<ParmVarDecl *> &Params) { + SmallVectorImpl<ParmVarDecl *> &Params) { TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); @@ -2104,7 +2126,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, if (!OldParam->isParameterPack() || (NewIdx < NumNewParams && NewProtoLoc->getArg(NewIdx)->isParameterPack())) { - // Simple case: normal parameter, or a parameter pack that's + // Simple case: normal parameter, or a parameter pack that's // instantiated to a (still-dependent) parameter pack. ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); Params.push_back(NewParam); @@ -2112,7 +2134,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, NewParam); continue; } - + // Parameter pack: make the instantiation an argument pack. SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack( OldParam); @@ -2184,43 +2206,42 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) { // The function has an exception specification or a "noreturn" // attribute. Substitute into each of the exception types. - llvm::SmallVector<QualType, 4> Exceptions; + SmallVector<QualType, 4> Exceptions; for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { // FIXME: Poor location information! if (const PackExpansionType *PackExpansion = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { // We have a pack expansion. Instantiate it. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), Unexpanded); - assert(!Unexpanded.empty() && + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); bool Expand = false; bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), SourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, TemplateArgs, - Expand, + Expand, RetainExpansion, NumExpansions)) break; if (!Expand) { // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion + // just substitute into the pattern and create a new pack expansion // type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), TemplateArgs, New->getLocation(), New->getDeclName()); if (T.isNull()) break; - + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); Exceptions.push_back(T); continue; @@ -2230,8 +2251,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, bool Invalid = false; for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), TemplateArgs, New->getLocation(), New->getDeclName()); if (T.isNull()) { @@ -2247,11 +2268,11 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, continue; } - + QualType T = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, New->getLocation(), New->getDeclName()); - if (T.isNull() || + if (T.isNull() || SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) continue; @@ -2262,10 +2283,24 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); if (E.isUsable()) + E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); + + if (E.isUsable()) { + SourceLocation ErrLoc; + llvm::APSInt NoexceptVal; NoexceptExpr = E.take(); + if (!NoexceptExpr->isTypeDependent() && + !NoexceptExpr->isValueDependent() && + !NoexceptExpr->isIntegerConstantExpr(NoexceptVal, SemaRef.Context, + &ErrLoc, /*evaluated=*/false)){ + SemaRef.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) + << NoexceptExpr->getSourceRange(); + NoexceptExpr = 0; + } + } } - // Rebuild the function type + // Rebuild the function type FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.ExceptionSpecType = Proto->getExceptionSpecType(); @@ -2283,6 +2318,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI)); } + // C++0x [dcl.constexpr]p6: If the instantiated template specialization of + // a constexpr function template satisfies the requirements for a constexpr + // function, then it is a constexpr function. + if (Tmpl->isConstexpr() && + SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation)) + New->setConstexpr(true); + const FunctionDecl* Definition = Tmpl; // Get the definition. Leaves the variable unchanged if undefined. @@ -2337,8 +2379,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Function->isInvalidDecl() || Function->isDefined()) return; - // Never instantiate an explicit specialization. - if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + // Never instantiate an explicit specialization except if it is a class scope + // explicit specialization. + if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + !Function->getClassScopeSpecializationPattern()) return; // Find the function body that we'll be substituting. @@ -2362,7 +2406,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } // Call the LateTemplateParser callback if there a need to late parse - // a templated function definition. + // a templated function definition. if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser) { LateTemplateParser(OpaqueParser, PatternDecl); @@ -2372,16 +2416,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_func_template) << Function->getPrimaryTemplate(); else - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 1 << Function->getDeclName() << Function->getDeclContext(); - + if (PatternDecl) - Diag(PatternDecl->getLocation(), + Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); Function->setInvalidDecl(); } else if (Function->getTemplateSpecializationKind() @@ -2404,19 +2448,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) - return; - + return; + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. - llvm::SmallVector<VTableUse, 16> SavedVTableUses; + SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; if (Recursive) { VTableUses.swap(SavedVTableUses); PendingInstantiations.swap(SavedPendingInstantiations); } - EnterExpressionEvaluationContext EvalContext(*this, + EnterExpressionEvaluationContext EvalContext(*this, Sema::PotentiallyEvaluated); ActOnStartOfFunctionDef(0, Function); @@ -2445,11 +2489,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ++FParamIdx; continue; } - + // Expand the parameter pack. Scope.MakeInstantiatedLocalArgPack(PatternParam); - for (unsigned NumFParams = Function->getNumParams(); - FParamIdx < NumFParams; + for (unsigned NumFParams = Function->getNumParams(); + FParamIdx < NumFParams; ++FParamIdx) { ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); FunctionParam->setDeclName(PatternParam->getDeclName()); @@ -2481,7 +2525,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Body.isInvalid()) Function->setInvalidDecl(); - + ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); } @@ -2545,7 +2589,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // Find the out-of-line definition of this static data member. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); Def = Def->getOutOfLineDefinition(); if (!Def) { @@ -2555,7 +2599,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // another translation unit. if (DefinitionRequired) { Def = Var->getInstantiatedFromStaticDataMember(); - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 2 << Var->getDeclName() << Var->getDeclContext(); Diag(Def->getLocation(), diag::note_explicit_instantiation_here); @@ -2571,12 +2615,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // Never instantiate an explicit specialization. if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; - + // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. - if (Var->getTemplateSpecializationKind() + if (Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return; @@ -2591,7 +2635,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. - llvm::SmallVector<VTableUse, 16> SavedVTableUses; + SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; if (Recursive) { VTableUses.swap(SavedVTableUses); @@ -2639,14 +2683,26 @@ void Sema::InstantiateStaticDataMemberDefinition( } } +static MultiInitializer CreateMultiInitializer(SmallVectorImpl<Expr*> &Args, + const CXXCtorInitializer *Init) { + // FIXME: This is a hack that will do slightly the wrong thing for an + // initializer of the form foo({...}). + // The right thing to do would be to modify InstantiateInitializer to create + // the MultiInitializer. + if (Args.size() == 1 && isa<InitListExpr>(Args[0])) + return MultiInitializer(Args[0]); + return MultiInitializer(Init->getLParenLoc(), Args.data(), + Args.size(), Init->getRParenLoc()); +} + void Sema::InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs) { - llvm::SmallVector<MemInitTy*, 4> NewInits; + SmallVector<CXXCtorInitializer*, 4> NewInits; bool AnyErrors = false; - + // Instantiate all the initializers. for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), InitsEnd = Tmpl->init_end(); @@ -2662,20 +2718,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, ASTOwningVector<Expr*> NewArgs(*this); SourceLocation EllipsisLoc; - + if (Init->isPackExpansion()) { // This is a pack expansion. We should expand it now. TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(BaseTL, Unexpanded); bool ShouldExpand = false; bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions; - if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), + if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), BaseTL.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), - TemplateArgs, ShouldExpand, + Unexpanded, + TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions)) { AnyErrors = true; @@ -2683,22 +2738,22 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } assert(ShouldExpand && "Partial instantiation of base initializer?"); - - // Loop over all of the arguments in the argument pack(s), + + // Loop over all of the arguments in the argument pack(s), for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); // Instantiate the initializer. - if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + if (InstantiateInitializer(Init->getInit(), TemplateArgs, LParenLoc, NewArgs, RParenLoc)) { AnyErrors = true; break; } // Instantiate the base type. - TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), - TemplateArgs, - Init->getSourceLocation(), + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), New->getDeclName()); if (!BaseTInfo) { AnyErrors = true; @@ -2706,52 +2761,45 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, } // Build the initializer. - MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), - BaseTInfo, - (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getLParenLoc(), - Init->getRParenLoc(), + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), + BaseTInfo, MultiInit, New->getParent(), SourceLocation()); if (NewInit.isInvalid()) { AnyErrors = true; break; } - + NewInits.push_back(NewInit.get()); NewArgs.clear(); } - + continue; } // Instantiate the initializer. - if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + if (InstantiateInitializer(Init->getInit(), TemplateArgs, LParenLoc, NewArgs, RParenLoc)) { AnyErrors = true; continue; } - + MemInitResult NewInit; if (Init->isBaseInitializer()) { - TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), - TemplateArgs, - Init->getSourceLocation(), + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), New->getDeclName()); if (!BaseTInfo) { AnyErrors = true; New->setInvalidDecl(); continue; } - - NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, - (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getLParenLoc(), - Init->getRParenLoc(), - New->getParent(), - EllipsisLoc); + + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, MultiInit, + New->getParent(), EllipsisLoc); } else if (Init->isMemberInitializer()) { FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl( Init->getMemberLocation(), @@ -2763,11 +2811,9 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } - NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getSourceLocation(), - Init->getLParenLoc(), - Init->getRParenLoc()); + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildMemberInitializer(Member, MultiInit, + Init->getSourceLocation()); } else if (Init->isIndirectMemberInitializer()) { IndirectFieldDecl *IndirectMember = cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl( @@ -2777,14 +2823,12 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, if (!IndirectMember) { AnyErrors = true; New->setInvalidDecl(); - continue; + continue; } - - NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getSourceLocation(), - Init->getLParenLoc(), - Init->getRParenLoc()); + + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildMemberInitializer(IndirectMember, MultiInit, + Init->getSourceLocation()); } if (NewInit.isInvalid()) { @@ -2794,7 +2838,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, // FIXME: It would be nice if ASTOwningVector had a release function. NewArgs.take(); - NewInits.push_back((MemInitTy *)NewInit.get()); + NewInits.push_back(NewInit.get()); } } @@ -2824,20 +2868,20 @@ static bool isInstantiationOf(ClassTemplateDecl *Pattern, static bool isInstantiationOf(FunctionTemplateDecl *Pattern, FunctionTemplateDecl *Instance) { Pattern = Pattern->getCanonicalDecl(); - + do { Instance = Instance->getCanonicalDecl(); if (Pattern == Instance) return true; Instance = Instance->getInstantiatedFromMemberTemplate(); } while (Instance); - + return false; } -static bool +static bool isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, ClassTemplatePartialSpecializationDecl *Instance) { - Pattern + Pattern = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl()); do { Instance = cast<ClassTemplatePartialSpecializationDecl>( @@ -2846,7 +2890,7 @@ isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, return true; Instance = Instance->getInstantiatedFromMember(); } while (Instance); - + return false; } @@ -3052,11 +3096,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found = CurrentInstantiationScope->findInstantiationOf(D); - + if (Found) { if (Decl *FD = Found->dyn_cast<Decl *>()) return cast<NamedDecl>(FD); - + unsigned PackIdx = ArgumentPackSubstitutionIndex; return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); } @@ -3064,10 +3108,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // If we didn't find the decl, then we must have a label decl that hasn't // been found yet. Lazily instantiate it and return it now. assert(isa<LabelDecl>(D)); - + Decl *Inst = SubstDecl(D, CurContext, TemplateArgs); assert(Inst && "Failed to instantiate label??"); - + CurrentInstantiationScope->InstantiatedLocal(D, Inst); return cast<LabelDecl>(Inst); } @@ -3075,7 +3119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { if (!Record->isDependentContext()) return D; - + // If the RecordDecl is actually the injected-class-name or a // "templated" declaration for a class template, class template // partial specialization, or a member class of a class template, @@ -3083,7 +3127,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // or partial specialization to find the new DeclContext. QualType T; ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); - + if (ClassTemplate) { T = ClassTemplate->getInjectedClassNameSpecialization(); } else if (ClassTemplatePartialSpecializationDecl *PartialSpec @@ -3096,26 +3140,26 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, assert(isa<InjectedClassNameType>(T) && "type of partial specialization is not an InjectedClassNameType"); T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); - } - + } + if (!T.isNull()) { // Substitute into the injected-class-name to get the type // corresponding to the instantiation we want, which may also be // the current instantiation (if we're in a template // definition). This substitution should never fail, since we // know we can instantiate the injected-class-name or we - // wouldn't have gotten to the injected-class-name! + // wouldn't have gotten to the injected-class-name! // FIXME: Can we use the CurrentInstantiationScope to avoid this // extra instantiation in the common case? T = SubstType(T, TemplateArgs, Loc, DeclarationName()); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); - + if (!T->isDependentType()) { assert(T->isRecordType() && "Instantiation must produce a record type"); return T->getAs<RecordType>()->getDecl(); } - + // We are performing "partial" template instantiation to create // the member declarations for the members of a class template // specialization. Therefore, D is actually referring to something @@ -3128,7 +3172,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, DC = DC->getParent()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) - if (isInstantiationOf(ClassTemplate, + if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate())) return Spec; @@ -3139,10 +3183,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // We're performing "instantiation" of a member of the current // instantiation while we are type-checking the // definition. Compute the declaration context and return that. - assert(!SawNonDependentContext && + assert(!SawNonDependentContext && "No dependent context while instantiating record"); DeclContext *DC = computeDeclContext(T); - assert(DC && + assert(DC && "Unable to find declaration for the current instantiation"); return cast<CXXRecordDecl>(DC); } @@ -3153,7 +3197,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!ParentDC->isDependentContext()) return D; - + ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs); if (!ParentDC) return 0; @@ -3207,7 +3251,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // declaration failed to instantiate. There's no point in complaining // further, since this is normal in invalid code. } else if (IsBeingInstantiated) { - // The class in which this member exists is currently being + // The class in which this member exists is currently being // instantiated, and we haven't gotten around to instantiating this // member yet. This can happen when the code uses forward declarations // of member classes, and introduces ordering dependencies via @@ -3221,7 +3265,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, llvm_unreachable("Unable to find instantiation of declaration!"); } } - + D = Result; } @@ -3231,6 +3275,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. void Sema::PerformPendingInstantiations(bool LocalOnly) { + // Load pending instantiations from the external source. + if (!LocalOnly && ExternalSource) { + SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending; + ExternalSource->ReadPendingInstantiations(Pending); + PendingInstantiations.insert(PendingInstantiations.begin(), + Pending.begin(), Pending.end()); + } + while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3267,7 +3319,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // and removed the need for implicit instantiation. switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) { case TSK_Undeclared: - assert(false && "Cannot instantitiate an undeclared specialization."); + llvm_unreachable("Cannot instantitiate an undeclared specialization."); case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitSpecialization: continue; // No longer need to instantiate this type. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index daa1523..e383db9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -32,11 +32,11 @@ namespace { typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor> inherited; - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; public: explicit CollectUnexpandedParameterPacksVisitor( - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) : Unexpanded(Unexpanded) { } bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -158,9 +158,9 @@ namespace { static void DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, Sema::UnexpandedParameterPackContext UPPC, - const llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { - llvm::SmallVector<SourceLocation, 4> Locations; - llvm::SmallVector<IdentifierInfo *, 4> Names; + const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVector<SourceLocation, 4> Locations; + SmallVector<IdentifierInfo *, 4> Names; llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown; for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { @@ -201,7 +201,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, if (!T->getType()->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc( T->getTypeLoc()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -217,7 +217,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, if (!E->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded); @@ -233,7 +233,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, !SS.getScopeRep()->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseNestedNameSpecifier(SS.getScopeRep()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -270,7 +270,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, break; } - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseType(NameInfo.getName().getCXXNameType()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -285,7 +285,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, if (Template.isNull() || !Template.containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateName(Template); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -299,7 +299,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, !Arg.getArgument().containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgumentLoc(Arg); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -308,24 +308,24 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, } void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgument(Arg); } void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgumentLoc(Arg); } void Sema::collectUnexpandedParameterPacks(QualType T, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); } void Sema::collectUnexpandedParameterPacks(TypeLoc TL, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); } @@ -462,8 +462,7 @@ getDepthAndIndex(NamedDecl *ND) { bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + ArrayRef<UnexpandedParameterPack> Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, @@ -473,19 +472,21 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, std::pair<IdentifierInfo *, SourceLocation> FirstPack; bool HaveFirstPack = false; - for (unsigned I = 0; I != NumUnexpanded; ++I) { + for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(), + end = Unexpanded.end(); + i != end; ++i) { // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; bool IsFunctionParameterPack = false; if (const TemplateTypeParmType *TTP - = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + = i->first.dyn_cast<const TemplateTypeParmType *>()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); Name = TTP->getIdentifier(); } else { - NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + NamedDecl *ND = i->first.get<NamedDecl *>(); if (isa<ParmVarDecl>(ND)) IsFunctionParameterPack = true; else @@ -502,7 +503,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = CurrentInstantiationScope->findInstantiationOf( - Unexpanded[I].first.get<NamedDecl *>()); + i->first.get<NamedDecl *>()); if (Instantiation->is<DeclArgumentPack *>()) { // We could expand this function parameter pack. NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); @@ -545,7 +546,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, // Record it. NumExpansions = NewPackSize; FirstPack.first = Name; - FirstPack.second = Unexpanded[I].second; + FirstPack.second = i->second; HaveFirstPack = true; continue; } @@ -557,11 +558,11 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, if (HaveFirstPack) Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) << FirstPack.first << Name << *NumExpansions << NewPackSize - << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second); + << SourceRange(FirstPack.second) << SourceRange(i->second); else Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) << Name << *NumExpansions << NewPackSize - << SourceRange(Unexpanded[I].second); + << SourceRange(i->second); return true; } } @@ -572,7 +573,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, unsigned Sema::getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs) { QualType Pattern = cast<PackExpansionType>(T)->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { @@ -618,7 +619,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlyingType: { + case TST_underlyingType: + case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; @@ -639,6 +641,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_char16: case TST_char32: case TST_int: + case TST_half: case TST_float: case TST_double: case TST_bool: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index f3e73ec..2b563a5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -52,18 +52,18 @@ static bool isOmittedBlockReturnType(const Declarator &D) { /// doesn't apply to the given type. static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, QualType type) { - bool useInstantiationLoc = false; + bool useExpansionLoc = false; unsigned diagID = 0; switch (attr.getKind()) { case AttributeList::AT_objc_gc: diagID = diag::warn_pointer_attribute_wrong_type; - useInstantiationLoc = true; + useExpansionLoc = true; break; case AttributeList::AT_objc_ownership: diagID = diag::warn_objc_object_attribute_wrong_type; - useInstantiationLoc = true; + useExpansionLoc = true; break; default: @@ -73,10 +73,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, } SourceLocation loc = attr.getLoc(); - llvm::StringRef name = attr.getName()->getName(); + StringRef name = attr.getName()->getName(); // The GC attributes are usually written with macros; special-case them. - if (useInstantiationLoc && loc.isMacroID() && attr.getParameterName()) { + if (useExpansionLoc && loc.isMacroID() && attr.getParameterName()) { if (attr.getParameterName()->isStr("strong")) { if (S.findMacroSpelling(loc, "__strong")) name = "__strong"; } else if (attr.getParameterName()->isStr("weak")) { @@ -125,11 +125,11 @@ namespace { bool hasSavedAttrs; /// The original set of attributes on the DeclSpec. - llvm::SmallVector<AttributeList*, 2> savedAttrs; + SmallVector<AttributeList*, 2> savedAttrs; /// A list of attributes to diagnose the uselessness of when the /// processing is complete. - llvm::SmallVector<AttributeList*, 2> ignoredTypeAttrs; + SmallVector<AttributeList*, 2> ignoredTypeAttrs; public: TypeProcessingState(Sema &sema, Declarator &declarator) @@ -183,7 +183,7 @@ namespace { /// Diagnose all the ignored type attributes, given that the /// declarator worked out to the given type. void diagnoseIgnoredTypeAttrs(QualType type) const { - for (llvm::SmallVectorImpl<AttributeList*>::const_iterator + for (SmallVectorImpl<AttributeList*>::const_iterator i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); i != e; ++i) diagnoseBadTypeAttribute(getSema(), **i, type); @@ -664,7 +664,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? if (S.getLangOptions().CPlusPlus && - !S.getLangOptions().Microsoft) { + !S.getLangOptions().MicrosoftExt) { S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); @@ -711,6 +711,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } + case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) @@ -856,6 +857,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.UnknownAnyTy; break; + case DeclSpec::TST_atomic: + Result = S.GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for _Atomic?"); + Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); @@ -1038,6 +1049,11 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type, } else if (type->isObjCARCImplicitlyUnretainedType()) { implicitLifetime = Qualifiers::OCL_ExplicitNone; + // If we are in an unevaluated context, like sizeof, assume ExplicitNone and + // don't give error. + } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + // If that failed, give an error and recover using __autoreleasing. } else { // These types can show up in private ivars in system headers, so @@ -1419,13 +1435,26 @@ QualType Sema::BuildFunctionType(QualType T, << T->isFunctionType() << T; return QualType(); } - + + // Functions cannot return half FP. + if (T->isHalfType()) { + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << + FixItHint::CreateInsertion(Loc, "*"); + return QualType(); + } + bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { + // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; + } else if (ParamType->isHalfType()) { + // Disallow half FP arguments. + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << + FixItHint::CreateInsertion(Loc, "*"); + Invalid = true; } ParamTypes[Idx] = ParamType; @@ -1492,7 +1521,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // type. In such cases, the compiler makes a worst-case assumption. // We make no such assumption right now, so emit an error if the // class isn't a complete type. - if (Context.Target.getCXXABI() == CXXABI_Microsoft && + if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft && RequireCompleteType(Loc, Class, diag::err_incomplete_type)) return QualType(); @@ -1745,9 +1774,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, switch (D.getContext()) { case Declarator::KNRTypeListContext: - assert(0 && "K&R type lists aren't allowed in C++"); + llvm_unreachable("K&R type lists aren't allowed in C++"); break; - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::PrototypeContext: Error = 0; // Function prototype break; @@ -1755,7 +1785,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { - case TTK_Enum: assert(0 && "unhandled tag kind"); break; + case TTK_Enum: llvm_unreachable("unhandled tag kind"); case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; case TTK_Class: Error = 3; /* Class member */ break; @@ -1825,7 +1855,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } if (SemaRef.getLangOptions().CPlusPlus && - OwnedTagDecl && OwnedTagDecl->isDefinition()) { + OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) { // Check the contexts where C++ forbids the declaration of a new class // or enumeration in a type-specifier-seq. switch (D.getContext()) { @@ -1856,7 +1886,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::PrototypeContext: - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::KNRTypeListContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. @@ -1916,7 +1947,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, state.setCurrentChunkIndex(chunkIndex); DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); switch (DeclType.Kind) { - default: assert(0 && "Unknown decltype!"); + default: llvm_unreachable("Unknown decltype!"); case DeclaratorChunk::Paren: T = S.BuildParenType(T); break; @@ -2045,6 +2076,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); } + // Do not allow returning half FP value. + // FIXME: This really should be in BuildFunctionType. + if (T->isHalfType()) { + S.Diag(D.getIdentifierLoc(), + diag::err_parameters_retval_cannot_have_fp16_type) << 1 + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); + D.setInvalidType(true); + } + // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && @@ -2077,7 +2117,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); - if (Tag->isDefinition()) + if (Tag->isCompleteDefinition()) S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) << Context.getTypeDeclType(Tag); } @@ -2127,10 +2167,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Otherwise, we have a function with an argument list that is // potentially variadic. - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.reserve(FTI.NumArgs); - llvm::SmallVector<bool, 16> ConsumedArguments; + SmallVector<bool, 16> ConsumedArguments; ConsumedArguments.reserve(FTI.NumArgs); bool HasAnyConsumedArguments = false; @@ -2168,6 +2208,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Do not add 'void' to the ArgTys list. break; } + } else if (ArgTy->isHalfType()) { + // Disallow half FP arguments. + // FIXME: This really should be in BuildFunctionType. + S.Diag(Param->getLocation(), + diag::err_parameters_retval_cannot_have_fp16_type) << 0 + << FixItHint::CreateInsertion(Param->getLocation(), "*"); + D.setInvalidType(); } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); @@ -2192,7 +2239,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (HasAnyConsumedArguments) EPI.ConsumedArguments = ConsumedArguments.data(); - llvm::SmallVector<QualType, 4> Exceptions; + SmallVector<QualType, 4> Exceptions; EPI.ExceptionSpecType = FTI.getExceptionSpecType(); if (FTI.getExceptionSpecType() == EST_Dynamic) { Exceptions.reserve(FTI.NumExceptions); @@ -2320,6 +2367,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FreeFunction = (DC && !DC->isRecord()); } + // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that function to be const. + if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction && + D.getName().getKind() != UnqualifiedId::IK_ConstructorName && + D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId && + !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) { + // Rebuild function type adding a 'const' qualifier. + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + EPI.TypeQuals |= DeclSpec::TQ_const; + T = Context.getFunctionType(FnTy->getResultType(), + FnTy->arg_type_begin(), + FnTy->getNumArgs(), EPI); + } + // C++0x [dcl.fct]p6: // A ref-qualifier shall only be part of the function type for a // non-static member function, the function type to which a pointer to @@ -2457,13 +2518,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); - else if (!LangOpts.CPlusPlus0x) - S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); + else + S.Diag(D.getEllipsisLoc(), + LangOpts.CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); break; case Declarator::FileContext: case Declarator::KNRTypeListContext: - case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? + case Declarator::ObjCParameterContext: // FIXME: special diagnostic here? + case Declarator::ObjCResultContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::CXXNewContext: case Declarator::AliasDeclContext: @@ -2850,6 +2915,14 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } + void VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. @@ -3030,7 +3103,7 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { void LocInfoType::getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const { - assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*" + llvm_unreachable("LocInfoType leaked into the type system; an opaque TypeTy*" " was used directly instead of getting the QualType through" " GetTypeFromParser"); } @@ -3045,6 +3118,12 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { if (D.isInvalidType()) return true; + // Make sure there are no unused decl attributes on the declarator. + // We don't want to do this for ObjC parameters because we're going + // to apply them to the actual parameter declaration. + if (D.getContext() != Declarator::ObjCParameterContext) + checkUnusedDeclAttributes(D); + if (getLangOptions().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); @@ -3053,6 +3132,13 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { return CreateParsedType(T, TInfo); } +ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { + QualType T = Context.getObjCInstanceType(); + TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + return CreateParsedType(T, TInfo); +} + + //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// @@ -3064,14 +3150,22 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ // If this type is already address space qualified, reject it. - // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers - // for two or more different address spaces." + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by + // qualifiers for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); Attr.setInvalid(); return; } + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be + // qualified by an address-space qualifier." + if (Type->isFunctionType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_function_type); + Attr.setInvalid(); + return; + } + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -3122,15 +3216,18 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, return false; Sema &S = state.getSema(); + SourceLocation AttrLoc = attr.getLoc(); + if (AttrLoc.isMacroID()) + AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first; if (type.getQualifiers().getObjCLifetime()) { - S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant) + S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant) << type; return true; } if (!attr.getParameterName()) { - S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string) << "objc_ownership" << 1; attr.setInvalid(); return true; @@ -3146,7 +3243,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, else if (attr.getParameterName()->isStr("autoreleasing")) lifetime = Qualifiers::OCL_Autoreleasing; else { - S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) + S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << "objc_ownership" << attr.getParameterName(); attr.setInvalid(); return true; @@ -3164,7 +3261,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // If we have a valid source location for the attribute, use an // AttributedType instead. - if (attr.getLoc().isValid()) + if (AttrLoc.isValid()) type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, origType, type); @@ -3175,10 +3272,11 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // Actually, delay this until we know what we're parsing. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( - sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(), + sema::DelayedDiagnostic::makeForbiddenType( + S.getSourceManager().getExpansionLoc(AttrLoc), diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); } else { - S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime); + S.Diag(AttrLoc, diag::err_arc_weak_no_runtime); } attr.setInvalid(); @@ -3194,7 +3292,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); if (Class->isArcWeakrefUnavailable()) { - S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class); + S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); S.Diag(ObjT->getInterfaceDecl()->getLocation(), diag::note_class_declared); } @@ -3283,7 +3381,7 @@ namespace { QualType Original; const FunctionType *Fn; - llvm::SmallVector<unsigned char /*WrapKind*/, 8> Stack; + SmallVector<unsigned char /*WrapKind*/, 8> Stack; FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { while (true) { @@ -3474,7 +3572,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } - if (CCOld != CC_Default) { + if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) { // Should we diagnose reapplications of the same convention? S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) @@ -3718,32 +3816,44 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, switch (attr.getKind()) { default: break; + case AttributeList::AT_may_alias: + // FIXME: This attribute needs to actually be handled, but if we ignore + // it it breaks large amounts of Linux software. + attr.setUsedAsTypeAttr(); + break; case AttributeList::AT_address_space: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) distributeObjCPointerTypeAttr(state, attr, type); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_vector_size: HandleVectorSizeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ext_vector_type: if (state.getDeclarator().getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) HandleExtVectorTypeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_vector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector, "neon_vector_type"); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_polyvector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonPolyVector, "neon_polyvector_type"); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_opencl_image_access: HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ns_returns_retained: @@ -3752,6 +3862,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // fallthrough into the function attrs FUNCTION_TYPE_ATTRS_CASELIST: + attr.setUsedAsTypeAttr(); + // Never process function type attributes as part of the // declaration-specifiers. if (isDeclSpec) @@ -3954,6 +4066,121 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, std::make_pair(SourceLocation(), PDiag(0))); } +/// @brief Ensure that the type T is a literal type. +/// +/// This routine checks whether the type @p T is a literal type. If @p T is an +/// incomplete type, an attempt is made to complete it. If @p T is a literal +/// type, or @p AllowIncompleteType is true and @p T is an incomplete type, +/// returns false. Otherwise, this routine issues the diagnostic @p PD (giving +/// it the type @p T), along with notes explaining why the type is not a +/// literal type, and returns true. +/// +/// @param Loc The location in the source that the non-literal type +/// diagnostic should refer to. +/// +/// @param T The type that this routine is examining for literalness. +/// +/// @param PD The partial diagnostic that will be printed out if T is not a +/// literal type. +/// +/// @param AllowIncompleteType If true, an incomplete type will be considered +/// acceptable. +/// +/// @returns @c true if @p T is not a literal type and a diagnostic was emitted, +/// @c false otherwise. +bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + bool AllowIncompleteType) { + assert(!T->isDependentType() && "type should not be dependent"); + + bool Incomplete = RequireCompleteType(Loc, T, 0); + if (T->isLiteralType() || (AllowIncompleteType && Incomplete)) + return false; + + if (PD.getDiagID() == 0) + return true; + + Diag(Loc, PD) << T; + + if (T->isVariableArrayType()) + return true; + + const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>(); + if (!RT) + return true; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + // If the class has virtual base classes, then it's not an aggregate, and + // cannot have any constexpr constructors, so is non-literal. This is better + // to diagnose than the resulting absence of constexpr constructors. + if (RD->getNumVBases()) { + Diag(RD->getLocation(), diag::note_non_literal_virtual_base) + << RD->isStruct() << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getSourceRange().getBegin(), + diag::note_constexpr_virtual_base_here) << I->getSourceRange(); + } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) { + Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD; + + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + break; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // If the base template had constexpr constructors which were + // instantiated as non-constexpr constructors, explain why. + for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), + E = RD->ctor_end(); I != E; ++I) { + if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor()) + continue; + + FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction(); + if (Base && Base->isConstexpr()) + CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation); + } + } + } else if (RD->hasNonLiteralTypeFieldsOrBases()) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (!I->getType()->isLiteralType()) { + Diag(I->getSourceRange().getBegin(), + diag::note_non_literal_base_class) + << RD << I->getType() << I->getSourceRange(); + return true; + } + } + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) { + if (!(*I)->getType()->isLiteralType()) { + Diag((*I)->getLocation(), diag::note_non_literal_field) + << RD << (*I) << (*I)->getType(); + return true; + } else if ((*I)->isMutable()) { + Diag((*I)->getLocation(), diag::note_non_literal_mutable_field) << RD; + return true; + } + } + } else if (!RD->hasTrivialDestructor()) { + // All fields and bases are of literal types, so have trivial destructors. + // If this class's destructor is non-trivial it must be user-declared. + CXXDestructorDecl *Dtor = RD->getDestructor(); + assert(Dtor && "class has literal fields and bases but no dtor?"); + if (!Dtor) + return true; + + Diag(Dtor->getLocation(), Dtor->isUserProvided() ? + diag::note_non_literal_user_provided_dtor : + diag::note_non_literal_nontrivial_dtor) << RD; + } + + return true; +} + /// \brief Retrieve a version of the type 'T' that is elaborated by Keyword /// and qualified by the nested-name-specifier contained in SS. QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, @@ -4015,3 +4242,36 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, } llvm_unreachable("unknown unary transform type"); } + +QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { + if (!T->isDependentType()) { + int DisallowedKind = -1; + if (T->isIncompleteType()) + // FIXME: It isn't entirely clear whether incomplete atomic types + // are allowed or not; for simplicity, ban them for the moment. + DisallowedKind = 0; + else if (T->isArrayType()) + DisallowedKind = 1; + else if (T->isFunctionType()) + DisallowedKind = 2; + else if (T->isReferenceType()) + DisallowedKind = 3; + else if (T->isAtomicType()) + DisallowedKind = 4; + else if (T.hasQualifiers()) + DisallowedKind = 5; + else if (!T.isTriviallyCopyableType(Context)) + // Some other non-trivially-copyable type (probably a C++ class) + DisallowedKind = 6; + + if (DisallowedKind != -1) { + Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; + return QualType(); + } + + // FIXME: Do we need any handling for ARC here? + } + + // Build the pointer type. + return Context.getAtomicType(T); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp index ab697ee..aa0bc08 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp @@ -147,7 +147,8 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, return; } - D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), + S.Context)); } static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -168,7 +169,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Apparently Visual C++ thinks it is okay to not emit a warning // in this case, so only emit a warning when -fms-extensions is not // specified. - if (!S.getLangOptions().Microsoft) + if (!S.getLangOptions().MicrosoftExt) S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -236,7 +237,7 @@ namespace { X86AttributesSema() { } bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) const { - const llvm::Triple &Triple(S.Context.Target.getTriple()); + const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple()); if (Triple.getOS() == llvm::Triple::Win32 || Triple.getOS() == llvm::Triple::MinGW32) { switch (Attr.getKind()) { @@ -247,8 +248,9 @@ namespace { default: break; } } - if (Attr.getName()->getName() == "force_align_arg_pointer" || - Attr.getName()->getName() == "__force_align_arg_pointer__") { + if (Triple.getArch() != llvm::Triple::x86_64 && + (Attr.getName()->getName() == "force_align_arg_pointer" || + Attr.getName()->getName() == "__force_align_arg_pointer__")) { HandleX86ForceAlignArgPointerAttr(D, Attr, S); return true; } @@ -261,16 +263,16 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const { if (TheTargetAttributesSema) return *TheTargetAttributesSema; - const llvm::Triple &Triple(Context.Target.getTriple()); + const llvm::Triple &Triple(Context.getTargetInfo().getTriple()); switch (Triple.getArch()) { - default: - return *(TheTargetAttributesSema = new TargetAttributesSema); - case llvm::Triple::msp430: return *(TheTargetAttributesSema = new MSP430AttributesSema); case llvm::Triple::mblaze: return *(TheTargetAttributesSema = new MBlazeAttributesSema); case llvm::Triple::x86: + case llvm::Triple::x86_64: return *(TheTargetAttributesSema = new X86AttributesSema); + default: + return *(TheTargetAttributesSema = new TargetAttributesSema); } } diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index fa87217..bb49eee 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -31,6 +31,7 @@ #include "clang/Sema/Ownership.h" #include "clang/Sema/Designator.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include "TypeLocBuilder.h" #include <algorithm> @@ -244,8 +245,7 @@ public: /// must be set. bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, llvm::Optional<unsigned> &NumExpansions) { @@ -345,7 +345,7 @@ public: /// /// \returns true if an error occurred, false otherwise. bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall, - llvm::SmallVectorImpl<Expr *> &Outputs, + SmallVectorImpl<Expr *> &Outputs, bool *ArgChanged = 0); /// \brief Transform the given declaration, which is referenced from a type @@ -520,8 +520,8 @@ public: bool TransformFunctionTypeParams(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const QualType *ParamTypes, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> *PVars); + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl*> *PVars); /// \brief Transforms a single function-type parameter. Return null /// on error. @@ -905,6 +905,12 @@ public: NumExpansions); } + /// \brief Build a new atomic type given its value type. + /// + /// By default, performs semantic analysis when building the atomic type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -1181,15 +1187,22 @@ public: return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } + /// \brief Rebuild the operand to an Objective-C @synchronized statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCAtSynchronizedOperand(SourceLocation atLoc, + Expr *object) { + return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object); + } + /// \brief Build a new Objective-C @synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, - Expr *Object, - Stmt *Body) { - return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, - Body); + Expr *Object, Stmt *Body) { + return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body); } /// \brief Build a new Objective-C @autoreleasepool statement. @@ -1200,7 +1213,16 @@ public: Stmt *Body) { return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); } - + + /// \brief Build the collection operand to a new Objective-C fast + /// enumeration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection) { + return getSema().ActOnObjCForCollectionOperand(forLoc, collection); + } /// \brief Build a new Objective-C fast enumeration statement. /// @@ -1712,8 +1734,7 @@ public: SubExpr, RParenLoc); default: - assert(false && "Invalid C++ named cast"); - break; + llvm_unreachable("Invalid C++ named cast"); } return ExprError(); @@ -2016,13 +2037,14 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXConstructExpr(QualType T, - SourceLocation Loc, - CXXConstructorDecl *Constructor, - bool IsElidable, - MultiExprArg Args, - bool RequiresZeroInit, + SourceLocation Loc, + CXXConstructorDecl *Constructor, + bool IsElidable, + MultiExprArg Args, + bool HadMultipleCandidates, + bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, - SourceRange ParenRange) { + SourceRange ParenRange) { ASTOwningVector<Expr*> ConvertedArgs(SemaRef); if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, ConvertedArgs)) @@ -2030,6 +2052,7 @@ public: return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, move_arg(ConvertedArgs), + HadMultipleCandidates, RequiresZeroInit, ConstructKind, ParenRange); } @@ -2117,10 +2140,15 @@ public: ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, SourceLocation RParenLoc, - unsigned Length) { + llvm::Optional<unsigned> Length) { + if (Length) + return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), + OperatorLoc, Pack, PackLoc, + RParenLoc, *Length); + return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), OperatorLoc, Pack, PackLoc, - RParenLoc, Length); + RParenLoc); } /// \brief Build a new Objective-C @encode expression. @@ -2137,7 +2165,7 @@ public: /// \brief Build a new Objective-C class message. ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -2145,14 +2173,14 @@ public: return SemaRef.BuildClassMessage(ReceiverTypeInfo, ReceiverTypeInfo->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, SelectorLoc, + Sel, Method, LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build a new Objective-C instance message. ExprResult RebuildObjCMessageExpr(Expr *Receiver, Selector Sel, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -2160,7 +2188,7 @@ public: return SemaRef.BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, SelectorLoc, + Sel, Method, LBracLoc, SelectorLocs, RBracLoc, move(Args)); } @@ -2357,7 +2385,26 @@ public: llvm::Optional<unsigned> NumExpansions) { return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } - + + /// \brief Build a new atomic operation expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, + MultiExprArg SubExprs, + QualType RetTy, + AtomicExpr::AtomicOp Op, + SourceLocation RParenLoc) { + // Just create the expression; there is not any interesting semantic + // analysis here because we can't actually build an AtomicExpr until + // we are sure it is semantically sound. + unsigned NumSubExprs = SubExprs.size(); + Expr **Subs = (Expr **)SubExprs.release(); + return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs, + NumSubExprs, RetTy, Op, + RParenLoc); + } + private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, @@ -2424,7 +2471,7 @@ template<typename Derived> bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall, - llvm::SmallVectorImpl<Expr *> &Outputs, + SmallVectorImpl<Expr *> &Outputs, bool *ArgChanged) { for (unsigned I = 0; I != NumInputs; ++I) { // If requested, drop call arguments that need to be dropped. @@ -2438,7 +2485,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) { Expr *Pattern = Expansion->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); @@ -2451,8 +2498,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), Pattern->getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; @@ -2522,7 +2568,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, QualType ObjectType, NamedDecl *FirstQualifierInScope) { - llvm::SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; + SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; Qualifier = Qualifier.getPrefix()) Qualifiers.push_back(Qualifier); @@ -2666,8 +2712,7 @@ TreeTransform<Derived> } } - assert(0 && "Unknown name kind."); - return DeclarationNameInfo(); + llvm_unreachable("Unknown name kind."); } template<typename Derived> @@ -2887,7 +2932,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( } case TemplateArgument::Pack: { - llvm::SmallVector<TemplateArgument, 4> TransformedArgs; + SmallVector<TemplateArgument, 4> TransformedArgs; TransformedArgs.reserve(Arg.pack_size()); for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); @@ -3016,7 +3061,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions, getSema().Context); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); @@ -3027,8 +3072,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Ellipsis, Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) @@ -3809,8 +3853,8 @@ bool TreeTransform<Derived>:: TransformFunctionTypeParams(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const QualType *ParamTypes, - llvm::SmallVectorImpl<QualType> &OutParamTypes, - llvm::SmallVectorImpl<ParmVarDecl*> *PVars) { + SmallVectorImpl<QualType> &OutParamTypes, + SmallVectorImpl<ParmVarDecl*> *PVars) { int indexAdjustment = 0; for (unsigned i = 0; i != NumParams; ++i) { @@ -3821,7 +3865,7 @@ bool TreeTransform<Derived>:: ParmVarDecl *NewParm = 0; if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; // Find the parameter packs that could be expanded. TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc(); @@ -3838,8 +3882,7 @@ bool TreeTransform<Derived>:: NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -3921,15 +3964,14 @@ bool TreeTransform<Derived>:: = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; if (getDerived().TryExpandParameterPacks(Loc, SourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -4014,8 +4056,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, // parameters before the return type, since the return type can then refer // to the parameters themselves (via decltype, sizeof, etc.). // - llvm::SmallVector<QualType, 4> ParamTypes; - llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + SmallVector<QualType, 4> ParamTypes; + SmallVector<ParmVarDecl*, 4> ParamDecls; const FunctionProtoType *T = TL.getTypePtr(); QualType ResultType; @@ -4387,6 +4429,29 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); } +template<typename Derived> +QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB, + AtomicTypeLoc TL) { + QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); + if (ValueType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ValueType != TL.getValueLoc().getType()) { + Result = getDerived().RebuildAtomicType(ValueType, TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + AtomicTypeLoc NewTL = TLB.push<AtomicTypeLoc>(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + + return Result; +} + namespace { /// \brief Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. @@ -5256,7 +5321,7 @@ template<typename Derived> StmtResult TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { bool DeclChanged = false; - llvm::SmallVector<Decl *, 4> Decls; + SmallVector<Decl *, 4> Decls; for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(), @@ -5283,7 +5348,7 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { ASTOwningVector<Expr*> Constraints(getSema()); ASTOwningVector<Expr*> Exprs(getSema()); - llvm::SmallVector<IdentifierInfo *, 4> Names; + SmallVector<IdentifierInfo *, 4> Names; ExprResult AsmString; ASTOwningVector<Expr*> Clobbers(getSema()); @@ -5470,6 +5535,11 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( ExprResult Object = getDerived().TransformExpr(S->getSynchExpr()); if (Object.isInvalid()) return StmtError(); + Object = + getDerived().RebuildObjCAtSynchronizedOperand(S->getAtSynchronizedLoc(), + Object.get()); + if (Object.isInvalid()) + return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getSynchBody()); @@ -5519,6 +5589,10 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt( ExprResult Collection = getDerived().TransformExpr(S->getCollection()); if (Collection.isInvalid()) return StmtError(); + Collection = getDerived().RebuildObjCForCollectionOperand(S->getForLoc(), + Collection.take()); + if (Collection.isInvalid()) + return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -5813,8 +5887,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { if (ControllingExpr.isInvalid()) return ExprError(); - llvm::SmallVector<Expr *, 4> AssocExprs; - llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes; + SmallVector<Expr *, 4> AssocExprs; + SmallVector<TypeSourceInfo *, 4> AssocTypes; for (unsigned i = 0; i != E->getNumAssocs(); ++i) { TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); if (TS) { @@ -5887,7 +5961,7 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { bool ExprChanged = false; typedef Sema::OffsetOfComponent Component; typedef OffsetOfExpr::OffsetOfNode Node; - llvm::SmallVector<Component, 4> Components; + SmallVector<Component, 4> Components; for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { const Node &ON = E->getComponent(I); Component Comp; @@ -6902,6 +6976,19 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew); if (OperatorDelete) SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); + + if (E->isArray() && Constructor && + !E->getAllocatedType()->isDependentType()) { + QualType ElementType + = SemaRef.Context.getBaseElementType(E->getAllocatedType()); + if (const RecordType *RecordT = ElementType->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl()); + if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor); + } + } + } + return SemaRef.Owned(E); } @@ -7313,6 +7400,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), move_arg(Args), + E->hadMultipleCandidates(), E->requiresZeroInitialization(), E->getConstructionKind(), E->getParenRange()); @@ -7640,19 +7728,28 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions; if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), - &Unexpanded, 1, + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) return ExprError(); - if (!ShouldExpand || RetainExpansion) + if (RetainExpansion) return SemaRef.Owned(E); + + NamedDecl *Pack = E->getPack(); + if (!ShouldExpand) { + Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(), + Pack)); + if (!Pack) + return ExprError(); + } + // We now know the length of the parameter pack, so build a new expression // that stores that length. - return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), + return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(), - *NumExpansions); + NumExpansions); } template<typename Derived> @@ -7762,9 +7859,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { return SemaRef.Owned(E); // Build a new class message send. + SmallVector<SourceLocation, 16> SelLocs; + E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, E->getSelector(), - E->getSelectorLoc(), + SelLocs, E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -7785,9 +7884,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { return SemaRef.Owned(E); // Build a new instance message send. + SmallVector<SourceLocation, 16> SelLocs; + E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(Receiver.get(), E->getSelector(), - E->getSelectorLoc(), + SelLocs, E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -7908,8 +8009,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { // expression. blockScope->CapturesCXXThis = oldBlock->capturesCXXThis(); - llvm::SmallVector<ParmVarDecl*, 4> params; - llvm::SmallVector<QualType, 4> paramTypes; + SmallVector<ParmVarDecl*, 4> params; + SmallVector<QualType, 4> paramTypes; // Parameter substitution. if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(), @@ -7951,7 +8052,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { // Set the parameters on the block decl. if (!params.empty()) - blockScope->TheDecl->setParams(params.data(), params.size()); + blockScope->TheDecl->setParams(params); // If the return type wasn't explicitly set, it will have been marked as a // dependent type (DependentTy); clear out the return type setting so @@ -8015,8 +8116,26 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) { - assert(false && "Cannot transform asType expressions yet"); - return SemaRef.Owned(E); + llvm_unreachable("Cannot transform asType expressions yet"); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { + QualType RetTy = getDerived().TransformType(E->getType()); + bool ArgumentChanged = false; + ASTOwningVector<Expr*> SubExprs(SemaRef); + SubExprs.reserve(E->getNumSubExprs()); + if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, + SubExprs, &ArgumentChanged)) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + !ArgumentChanged) + return SemaRef.Owned(E); + + return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs), + RetTy, E->getOp(), E->getRParenLoc()); } //===----------------------------------------------------------------------===// @@ -8239,6 +8358,12 @@ QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( } template<typename Derived> +QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType, + SourceLocation KWLoc) { + return SemaRef.BuildAtomicType(ValueType, KWLoc); +} + +template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp index 782e5c6..445e750 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp @@ -43,6 +43,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break; case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break; case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break; + case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break; case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break; case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break; case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h index 838df13..367f57f 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H #include "clang/Serialization/ASTBitCodes.h" +#include "clang/AST/ASTContext.h" namespace clang { @@ -31,7 +32,7 @@ enum DeclUpdateKind { TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT); template <typename IdxForTypeTy> -TypeID MakeTypeID(QualType T, IdxForTypeTy IdxForType) { +TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) { if (T.isNull()) return PREDEF_TYPE_NULL_ID; @@ -46,6 +47,11 @@ TypeID MakeTypeID(QualType T, IdxForTypeTy IdxForType) { if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) return TypeIdxFromBuiltin(BT).asTypeID(FastQuals); + if (T == Context.AutoDeductTy) + return TypeIdx(PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals); + if (T == Context.AutoRRefDeductTy) + return TypeIdx(PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals); + return IdxForType(T).asTypeID(FastQuals); } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index a4ed5f4..fe1cc30 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -13,7 +13,9 @@ #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ModuleManager.h" #include "ASTCommon.h" +#include "ASTReaderInternals.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Sema/Sema.h" @@ -52,6 +54,7 @@ using namespace clang; using namespace clang::serialization; +using namespace clang::serialization::reader; //===----------------------------------------------------------------------===// // PCH validator implementation @@ -62,103 +65,36 @@ ASTReaderListener::~ASTReaderListener() {} bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { const LangOptions &PPLangOpts = PP.getLangOptions(); -#define PARSE_LANGOPT_BENIGN(Option) -#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ - if (PPLangOpts.Option != LangOpts.Option) { \ - Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \ - return true; \ - } - - PARSE_LANGOPT_BENIGN(Trigraphs); - PARSE_LANGOPT_BENIGN(BCPLComment); - PARSE_LANGOPT_BENIGN(DollarIdents); - PARSE_LANGOPT_BENIGN(AsmPreprocessor); - PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); - PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords); - PARSE_LANGOPT_BENIGN(ImplicitInt); - PARSE_LANGOPT_BENIGN(Digraphs); - PARSE_LANGOPT_BENIGN(HexFloats); - PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); - PARSE_LANGOPT_IMPORTANT(C1X, diag::warn_pch_c1x); - PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); - PARSE_LANGOPT_BENIGN(MSCVersion); - PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); - PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); - PARSE_LANGOPT_BENIGN(CXXOperatorName); - PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); - PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); - PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); - PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2); - PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext); - PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties, - diag::warn_pch_objc_auto_properties); - PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType) - PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings, - diag::warn_pch_no_constant_cfstrings); - PARSE_LANGOPT_BENIGN(PascalStrings); - PARSE_LANGOPT_BENIGN(WritableStrings); - PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, - diag::warn_pch_lax_vector_conversions); - PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec); - PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); - PARSE_LANGOPT_IMPORTANT(ObjCExceptions, diag::warn_pch_objc_exceptions); - PARSE_LANGOPT_IMPORTANT(CXXExceptions, diag::warn_pch_cxx_exceptions); - PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions); - PARSE_LANGOPT_IMPORTANT(MSBitfields, diag::warn_pch_ms_bitfields); - PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); - PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); - PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); - PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, - diag::warn_pch_thread_safe_statics); - PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads); - PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); - PARSE_LANGOPT_BENIGN(EmitAllDecls); - PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); - PARSE_LANGOPT_BENIGN(getSignedOverflowBehavior()); - PARSE_LANGOPT_IMPORTANT(HeinousExtensions, - diag::warn_pch_heinous_extensions); - // FIXME: Most of the options below are benign if the macro wasn't - // used. Unfortunately, this means that a PCH compiled without - // optimization can't be used with optimization turned on, even - // though the only thing that changes is whether __OPTIMIZE__ was - // defined... but if __OPTIMIZE__ never showed up in the header, it - // doesn't matter. We could consider making this some special kind - // of check. - PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); - PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); - PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); - PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); - PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); - PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); - PARSE_LANGOPT_IMPORTANT(Deprecated, diag::warn_pch_deprecated); - PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); - PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); - PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); - PARSE_LANGOPT_IMPORTANT(ShortEnums, diag::warn_pch_short_enums); - if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { - Reader.Diag(diag::warn_pch_gc_mode) - << LangOpts.getGCMode() << PPLangOpts.getGCMode(); - return true; + +#define LANGOPT(Name, Bits, Default, Description) \ + if (PPLangOpts.Name != LangOpts.Name) { \ + Reader.Diag(diag::err_pch_langopt_mismatch) \ + << Description << LangOpts.Name << PPLangOpts.Name; \ + return true; \ + } + +#define VALUE_LANGOPT(Name, Bits, Default, Description) \ + if (PPLangOpts.Name != LangOpts.Name) { \ + Reader.Diag(diag::err_pch_langopt_value_mismatch) \ + << Description; \ + return true; \ +} + +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \ + Reader.Diag(diag::err_pch_langopt_value_mismatch) \ + << Description; \ + return true; \ } - PARSE_LANGOPT_BENIGN(getVisibilityMode()); - PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(), - diag::warn_pch_stack_protector); - PARSE_LANGOPT_BENIGN(InstantiationDepth); - PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); - PARSE_LANGOPT_IMPORTANT(CUDA, diag::warn_pch_cuda); - PARSE_LANGOPT_BENIGN(CatchUndefined); - PARSE_LANGOPT_BENIGN(DefaultFPContract); - PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); - PARSE_LANGOPT_BENIGN(SpellChecking); - PARSE_LANGOPT_IMPORTANT(ObjCAutoRefCount, diag::warn_pch_auto_ref_count); - PARSE_LANGOPT_BENIGN(ObjCInferRelatedReturnType); -#undef PARSE_LANGOPT_IMPORTANT -#undef PARSE_LANGOPT_BENIGN +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + return false; } -bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { +bool PCHValidator::ReadTargetTriple(StringRef Triple) { if (Triple == PP.getTargetInfo().getTriple().str()) return false; @@ -169,14 +105,14 @@ bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { namespace { struct EmptyStringRef { - bool operator ()(llvm::StringRef r) const { return r.empty(); } + bool operator ()(StringRef r) const { return r.empty(); } }; struct EmptyBlock { bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();} }; } -static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L, +static bool EqualConcatenations(SmallVector<StringRef, 2> L, PCHPredefinesBlocks R) { // First, sum up the lengths. unsigned LL = 0, RL = 0; @@ -196,7 +132,7 @@ static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L, R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end()); // Do it the hard way. At this point, both vectors must be non-empty. - llvm::StringRef LR = L[0], RR = R[0].Data; + StringRef LR = L[0], RR = R[0].Data; unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size(); (void) RN; for (;;) { @@ -236,12 +172,12 @@ static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L, } } -static std::pair<FileID, llvm::StringRef::size_type> -FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) { - std::pair<FileID, llvm::StringRef::size_type> Res; +static std::pair<FileID, StringRef::size_type> +FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) { + std::pair<FileID, StringRef::size_type> Res; for (unsigned I = 0, N = Buffers.size(); I != N; ++I) { Res.second = Buffers[I].Data.find(MacroDef); - if (Res.second != llvm::StringRef::npos) { + if (Res.second != StringRef::npos) { Res.first = Buffers[I].BufferID; break; } @@ -250,7 +186,7 @@ FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) { } bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - llvm::StringRef OriginalFileName, + StringRef OriginalFileName, std::string &SuggestedPredefines, FileManager &FileMgr) { // We are in the context of an implicit include, so the predefines buffer will @@ -261,9 +197,9 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, PCHInclude += "#include \""; PCHInclude += NormalizeDashIncludePath(OriginalFileName, FileMgr); PCHInclude += "\"\n"; - std::pair<llvm::StringRef,llvm::StringRef> Split = - llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); - llvm::StringRef Left = Split.first, Right = Split.second; + std::pair<StringRef,StringRef> Split = + StringRef(PP.getPredefines()).split(PCHInclude.str()); + StringRef Left = Split.first, Right = Split.second; if (Left == PP.getPredefines()) { Error("Missing PCH include entry!"); return true; @@ -271,7 +207,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, // If the concatenation of all the PCH buffers is equal to the adjusted // command line, we're done. - llvm::SmallVector<llvm::StringRef, 2> CommandLine; + SmallVector<StringRef, 2> CommandLine; CommandLine.push_back(Left); CommandLine.push_back(Right); if (EqualConcatenations(CommandLine, Buffers)) @@ -281,18 +217,18 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, // The predefines buffers are different. Determine what the differences are, // and whether they require us to reject the PCH file. - llvm::SmallVector<llvm::StringRef, 8> PCHLines; + SmallVector<StringRef, 8> PCHLines; for (unsigned I = 0, N = Buffers.size(); I != N; ++I) Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - llvm::SmallVector<llvm::StringRef, 8> CmdLineLines; + SmallVector<StringRef, 8> CmdLineLines; Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); // Pick out implicit #includes after the PCH and don't consider them for // validation; we will insert them into SuggestedPredefines so that the // preprocessor includes them. std::string IncludesAfterPCH; - llvm::SmallVector<llvm::StringRef, 8> AfterPCHLines; + SmallVector<StringRef, 8> AfterPCHLines; Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) { if (AfterPCHLines[i].startswith("#include ")) { @@ -325,7 +261,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, // Determine which predefines that were used to build the PCH file are missing // from the command line. - std::vector<llvm::StringRef> MissingPredefines; + std::vector<StringRef> MissingPredefines; std::set_difference(PCHLines.begin(), PCHLines.end(), CmdLineLines.begin(), CmdLineLines.end(), std::back_inserter(MissingPredefines)); @@ -333,7 +269,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, bool MissingDefines = false; bool ConflictingDefines = false; for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - llvm::StringRef Missing = MissingPredefines[I]; + StringRef Missing = MissingPredefines[I]; if (Missing.startswith("#include ")) { // An -include was specified when generating the PCH; it is included in // the PCH, just ignore it. @@ -351,13 +287,13 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, = Missing.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); + StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); // Determine whether this macro was given a different definition on the // command line. std::string MacroDefStart = "#define " + MacroName.str(); std::string::size_type MacroDefLen = MacroDefStart.size(); - llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos + SmallVector<StringRef, 8>::iterator ConflictPos = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), MacroDefStart); for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { @@ -382,12 +318,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, << MacroName; // Show the definition of this macro within the PCH file. - std::pair<FileID, llvm::StringRef::size_type> MacroLoc = + std::pair<FileID, StringRef::size_type> MacroLoc = FindMacro(Buffers, Missing); - assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); + assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getFileLocWithOffset(MacroLoc.second); + .getLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; ConflictingDefines = true; @@ -405,12 +341,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, } // Show the definition of this macro within the PCH file. - std::pair<FileID, llvm::StringRef::size_type> MacroLoc = + std::pair<FileID, StringRef::size_type> MacroLoc = FindMacro(Buffers, Missing); - assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); + assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getFileLocWithOffset(MacroLoc.second); + .getLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); } @@ -421,12 +357,12 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, // parameters that were not present when building the PCH // file. Extra #defines are okay, so long as the identifiers being // defined were not used within the precompiled header. - std::vector<llvm::StringRef> ExtraPredefines; + std::vector<StringRef> ExtraPredefines; std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), PCHLines.begin(), PCHLines.end(), std::back_inserter(ExtraPredefines)); for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - llvm::StringRef &Extra = ExtraPredefines[I]; + StringRef &Extra = ExtraPredefines[I]; if (!Extra.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; @@ -439,7 +375,7 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, = Extra.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); + StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); // Check whether this name was used somewhere in the PCH file. If // so, defining it as a macro could change behavior, so we reject @@ -479,440 +415,321 @@ ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { } -namespace { -class ASTSelectorLookupTrait { - ASTReader &Reader; -public: - struct data_type { - SelectorID ID; - ObjCMethodList Instance, Factory; - }; +unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { + return serialization::ComputeHash(Sel); +} - typedef Selector external_key_type; - typedef external_key_type internal_key_type; - explicit ASTSelectorLookupTrait(ASTReader &Reader) : Reader(Reader) { } +std::pair<unsigned, unsigned> +ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a == b; - } +ASTSelectorLookupTrait::internal_key_type +ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext().Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + if (N == 0) + return SelTable.getNullarySelector(FirstII); + else if (N == 1) + return SelTable.getUnarySelector(FirstII); - static unsigned ComputeHash(Selector Sel) { - return serialization::ComputeHash(Sel); - } + SmallVector<IdentifierInfo *, 16> Args; + Args.push_back(FirstII); + for (unsigned I = 1; I != N; ++I) + Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d))); - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } + return SelTable.getSelector(N, Args.data()); +} - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } +ASTSelectorLookupTrait::data_type +ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; - internal_key_type ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; - SelectorTable &SelTable = Reader.getContext()->Selectors; - unsigned N = ReadUnalignedLE16(d); - IdentifierInfo *FirstII - = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); - if (N == 0) - return SelTable.getNullarySelector(FirstII); - else if (N == 1) - return SelTable.getUnarySelector(FirstII); + data_type Result; - llvm::SmallVector<IdentifierInfo *, 16> Args; - Args.push_back(FirstII); - for (unsigned I = 1; I != N; ++I) - Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d))); + Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); - return SelTable.getSelector(N, Args.data()); + // Load instance methods + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) + Result.Instance.push_back(Method); } - data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { - using namespace clang::io; - - data_type Result; - - Result.ID = ReadUnalignedLE32(d); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); - - // Load instance methods - ObjCMethodList *Prev = 0; - for (unsigned I = 0; I != NumInstanceMethods; ++I) { - ObjCMethodDecl *Method - = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); - if (!Result.Instance.Method) { - // This is the first method, which is the easy case. - Result.Instance.Method = Method; - Prev = &Result.Instance; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; - } - - // Load factory methods - Prev = 0; - for (unsigned I = 0; I != NumFactoryMethods; ++I) { - ObjCMethodDecl *Method - = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); - if (!Result.Factory.Method) { - // This is the first method, which is the easy case. - Result.Factory.Method = Method; - Prev = &Result.Factory; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; - } - - return Result; + // Load factory methods + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) + Result.Factory.push_back(Method); } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used for the global method pool. -typedef OnDiskChainedHashTable<ASTSelectorLookupTrait> - ASTSelectorLookupTable; - -namespace clang { -class ASTIdentifierLookupTrait { - ASTReader &Reader; - ASTReader::PerFileData &F; - - // If we know the IdentifierInfo in advance, it is here and we will - // not build a new one. Used when deserializing information about an - // identifier that was constructed before the AST file was read. - IdentifierInfo *KnownII; - -public: - typedef IdentifierInfo * data_type; - - typedef const std::pair<const char*, unsigned> external_key_type; - - typedef external_key_type internal_key_type; - ASTIdentifierLookupTrait(ASTReader &Reader, ASTReader::PerFileData &F, - IdentifierInfo *II = 0) - : Reader(Reader), F(F), KnownII(II) { } + return Result; +} - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 - : false; - } +unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { + return llvm::HashString(StringRef(a.first, a.second)); +} - static unsigned ComputeHash(const internal_key_type& a) { - return llvm::HashString(llvm::StringRef(a.first, a.second)); - } +std::pair<unsigned, unsigned> +ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned DataLen = ReadUnalignedLE16(d); + unsigned KeyLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } +std::pair<const char*, unsigned> +ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { + assert(n >= 2 && d[n-1] == '\0'); + return std::make_pair((const char*) d, n-1); +} - // This hopefully will just get inlined and removed by the optimizer. - static const external_key_type& - GetExternalKey(const internal_key_type& x) { return x; } +IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned RawID = ReadUnalignedLE32(d); + bool IsInteresting = RawID & 0x01; - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned DataLen = ReadUnalignedLE16(d); - unsigned KeyLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } + // Wipe out the "is interesting" bit. + RawID = RawID >> 1; - static std::pair<const char*, unsigned> - ReadKey(const unsigned char* d, unsigned n) { - assert(n >= 2 && d[n-1] == '\0'); - return std::make_pair((const char*) d, n-1); - } - - IdentifierInfo *ReadData(const internal_key_type& k, - const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - IdentID ID = ReadUnalignedLE32(d); - bool IsInteresting = ID & 0x01; - - // Wipe out the "is interesting" bit. - ID = ID >> 1; - - if (!IsInteresting) { - // For uninteresting identifiers, just build the IdentifierInfo - // and associate it with the persistent ID. - IdentifierInfo *II = KnownII; - if (!II) - II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first, - k.second)); - Reader.SetIdentifierInfo(ID, II); - II->setIsFromAST(); - return II; - } - - unsigned Bits = ReadUnalignedLE16(d); - bool CPlusPlusOperatorKeyword = Bits & 0x01; - Bits >>= 1; - bool HasRevertedTokenIDToIdentifier = Bits & 0x01; - Bits >>= 1; - bool Poisoned = Bits & 0x01; - Bits >>= 1; - bool ExtensionToken = Bits & 0x01; - Bits >>= 1; - bool hasMacroDefinition = Bits & 0x01; - Bits >>= 1; - unsigned ObjCOrBuiltinID = Bits & 0x3FF; - Bits >>= 10; - - assert(Bits == 0 && "Extra bits in the identifier?"); - DataLen -= 6; - - // Build the IdentifierInfo itself and link the identifier ID with - // the new IdentifierInfo. + IdentID ID = Reader.getGlobalIdentifierID(F, RawID); + if (!IsInteresting) { + // For uninteresting identifiers, just build the IdentifierInfo + // and associate it with the persistent ID. IdentifierInfo *II = KnownII; if (!II) - II = &Reader.getIdentifierTable().getOwn(llvm::StringRef(k.first, - k.second)); + II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); Reader.SetIdentifierInfo(ID, II); - - // Set or check the various bits in the IdentifierInfo structure. - // Token IDs are read-only. - if (HasRevertedTokenIDToIdentifier) - II->RevertTokenIDToIdentifier(); - II->setObjCOrBuiltinID(ObjCOrBuiltinID); - assert(II->isExtensionToken() == ExtensionToken && - "Incorrect extension token flag"); - (void)ExtensionToken; - II->setIsPoisoned(Poisoned); - assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && - "Incorrect C++ operator keyword flag"); - (void)CPlusPlusOperatorKeyword; - - // If this identifier is a macro, deserialize the macro - // definition. - if (hasMacroDefinition) { - uint32_t Offset = ReadUnalignedLE32(d); - Reader.SetIdentifierIsMacro(II, F, Offset); - DataLen -= 4; - } - - // Read all of the declarations visible at global scope with this - // name. - if (Reader.getContext() == 0) return II; - if (DataLen > 0) { - llvm::SmallVector<uint32_t, 4> DeclIDs; - for (; DataLen > 0; DataLen -= 4) - DeclIDs.push_back(ReadUnalignedLE32(d)); - Reader.SetGloballyVisibleDecls(II, DeclIDs); - } - II->setIsFromAST(); return II; } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used to contain information about -/// all of the identifiers in the program. -typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait> - ASTIdentifierLookupTable; - -namespace { -class ASTDeclContextNameLookupTrait { - ASTReader &Reader; - -public: - /// \brief Pair of begin/end iterators for DeclIDs. - typedef std::pair<DeclID *, DeclID *> data_type; - - /// \brief Special internal key for declaration names. - /// The hash table creates keys for comparison; we do not create - /// a DeclarationName for the internal key to avoid deserializing types. - struct DeclNameKey { - DeclarationName::NameKind Kind; - uint64_t Data; - DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { } - }; - - typedef DeclarationName external_key_type; - typedef DeclNameKey internal_key_type; - - explicit ASTDeclContextNameLookupTrait(ASTReader &Reader) : Reader(Reader) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a.Kind == b.Kind && a.Data == b.Data; - } - - unsigned ComputeHash(const DeclNameKey &Key) const { - llvm::FoldingSetNodeID ID; - ID.AddInteger(Key.Kind); - switch (Key.Kind) { - case DeclarationName::Identifier: - case DeclarationName::CXXLiteralOperatorName: - ID.AddString(((IdentifierInfo*)Key.Data)->getName()); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - ID.AddInteger((TypeID)Key.Data); - break; - case DeclarationName::CXXOperatorName: - ID.AddInteger((OverloadedOperatorKind)Key.Data); - break; - case DeclarationName::CXXUsingDirective: - break; - } - - return ID.ComputeHash(); + unsigned Bits = ReadUnalignedLE16(d); + bool CPlusPlusOperatorKeyword = Bits & 0x01; + Bits >>= 1; + bool HasRevertedTokenIDToIdentifier = Bits & 0x01; + Bits >>= 1; + bool Poisoned = Bits & 0x01; + Bits >>= 1; + bool ExtensionToken = Bits & 0x01; + Bits >>= 1; + bool hasMacroDefinition = Bits & 0x01; + Bits >>= 1; + unsigned ObjCOrBuiltinID = Bits & 0x3FF; + Bits >>= 10; + + assert(Bits == 0 && "Extra bits in the identifier?"); + DataLen -= 6; + + // Build the IdentifierInfo itself and link the identifier ID with + // the new IdentifierInfo. + IdentifierInfo *II = KnownII; + if (!II) + II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + Reader.SetIdentifierInfo(ID, II); + + // Set or check the various bits in the IdentifierInfo structure. + // Token IDs are read-only. + if (HasRevertedTokenIDToIdentifier) + II->RevertTokenIDToIdentifier(); + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + assert(II->isExtensionToken() == ExtensionToken && + "Incorrect extension token flag"); + (void)ExtensionToken; + if (Poisoned) + II->setIsPoisoned(true); + assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && + "Incorrect C++ operator keyword flag"); + (void)CPlusPlusOperatorKeyword; + + // If this identifier is a macro, deserialize the macro + // definition. + if (hasMacroDefinition) { + // FIXME: Check for conflicts? + uint32_t Offset = ReadUnalignedLE32(d); + Reader.SetIdentifierIsMacro(II, F, Offset); + DataLen -= 4; + } + + // Read all of the declarations visible at global scope with this + // name. + if (DataLen > 0) { + SmallVector<uint32_t, 4> DeclIDs; + for (; DataLen > 0; DataLen -= 4) + DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d))); + Reader.SetGloballyVisibleDecls(II, DeclIDs); + } + + II->setIsFromAST(); + return II; +} + +unsigned +ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(Key.Kind); + + switch (Key.Kind) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + ID.AddString(((IdentifierInfo*)Key.Data)->getName()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); + break; + case DeclarationName::CXXOperatorName: + ID.AddInteger((OverloadedOperatorKind)Key.Data); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + break; } - internal_key_type GetInternalKey(const external_key_type& Name) const { - DeclNameKey Key; - Key.Kind = Name.getNameKind(); - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Name.getAsIdentifierInfo(); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - Key.Data = Reader.GetTypeID(Name.getCXXNameType()); - break; - case DeclarationName::CXXOperatorName: - Key.Data = Name.getCXXOverloadedOperator(); - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); - break; - case DeclarationName::CXXUsingDirective: - break; - } + return ID.ComputeHash(); +} - return Key; +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::GetInternalKey( + const external_key_type& Name) const { + DeclNameKey Key; + Key.Kind = Name.getNameKind(); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Name.getAsIdentifierInfo(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = Name.getCXXOverloadedOperator(); + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; } - external_key_type GetExternalKey(const internal_key_type& Key) const { - ASTContext *Context = Reader.getContext(); - switch (Key.Kind) { - case DeclarationName::Identifier: - return DeclarationName((IdentifierInfo*)Key.Data); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(Selector(Key.Data)); + return Key; +} - case DeclarationName::CXXConstructorName: - return Context->DeclarationNames.getCXXConstructorName( - Context->getCanonicalType(Reader.GetType(Key.Data))); +ASTDeclContextNameLookupTrait::external_key_type +ASTDeclContextNameLookupTrait::GetExternalKey( + const internal_key_type& Key) const { + ASTContext &Context = Reader.getContext(); + switch (Key.Kind) { + case DeclarationName::Identifier: + return DeclarationName((IdentifierInfo*)Key.Data); - case DeclarationName::CXXDestructorName: - return Context->DeclarationNames.getCXXDestructorName( - Context->getCanonicalType(Reader.GetType(Key.Data))); + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return DeclarationName(Selector(Key.Data)); - case DeclarationName::CXXConversionFunctionName: - return Context->DeclarationNames.getCXXConversionFunctionName( - Context->getCanonicalType(Reader.GetType(Key.Data))); + case DeclarationName::CXXConstructorName: + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXOperatorName: - return Context->DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Key.Data); + case DeclarationName::CXXDestructorName: + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXLiteralOperatorName: - return Context->DeclarationNames.getCXXLiteralOperatorName( - (IdentifierInfo*)Key.Data); + case DeclarationName::CXXConversionFunctionName: + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } + case DeclarationName::CXXOperatorName: + return Context.DeclarationNames.getCXXOperatorName( + (OverloadedOperatorKind)Key.Data); - llvm_unreachable("Invalid Name Kind ?"); - } + case DeclarationName::CXXLiteralOperatorName: + return Context.DeclarationNames.getCXXLiteralOperatorName( + (IdentifierInfo*)Key.Data); - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); + case DeclarationName::CXXUsingDirective: + return DeclarationName::getUsingDirectiveName(); } - internal_key_type ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; + llvm_unreachable("Invalid Name Kind ?"); +} - DeclNameKey Key; - Key.Kind = (DeclarationName::NameKind)*d++; - switch (Key.Kind) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = - (uint64_t)Reader.DecodeSelector(ReadUnalignedLE32(d)).getAsOpaquePtr(); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - Key.Data = ReadUnalignedLE32(d); // TypeID - break; - case DeclarationName::CXXOperatorName: - Key.Data = *d++; // OverloadedOperatorKind - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); - break; - case DeclarationName::CXXUsingDirective: - break; - } +std::pair<unsigned, unsigned> +ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - return Key; - } +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; - data_type ReadData(internal_key_type, const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - unsigned NumDecls = ReadUnalignedLE16(d); - DeclID *Start = (DeclID *)d; - return std::make_pair(Start, Start + NumDecls); + DeclNameKey Key; + Key.Kind = (DeclarationName::NameKind)*d++; + switch (Key.Kind) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = + (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) + .getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = *d++; // OverloadedOperatorKind + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; } -}; -} // end anonymous namespace + return Key; +} -/// \brief The on-disk hash table used for the DeclContext's Name lookup table. -typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait> - ASTDeclContextNameLookupTable; +ASTDeclContextNameLookupTrait::data_type +ASTDeclContextNameLookupTrait::ReadData(internal_key_type, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned NumDecls = ReadUnalignedLE16(d); + DeclID *Start = (DeclID *)d; + return std::make_pair(Start, Start + NumDecls); +} -bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor, +bool ASTReader::ReadDeclContextStorage(Module &M, + llvm::BitstreamCursor &Cursor, const std::pair<uint64_t, uint64_t> &Offsets, DeclContextInfo &Info) { SavedStreamPosition SavedPosition(Cursor); @@ -932,9 +749,6 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor, Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob); Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair); - } else { - Info.LexicalDecls = 0; - Info.NumLexicalDecls = 0; } // Now the lookup table. @@ -954,20 +768,18 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor, = ASTDeclContextNameLookupTable::Create( (const unsigned char *)Blob + Record[0], (const unsigned char *)Blob, - ASTDeclContextNameLookupTrait(*this)); - } else { - Info.NameLookupTableData = 0; + ASTDeclContextNameLookupTrait(*this, M)); } return false; } -void ASTReader::Error(llvm::StringRef Msg) { +void ASTReader::Error(StringRef Msg) { Error(diag::err_fe_pch_malformed, Msg); } void ASTReader::Error(unsigned DiagID, - llvm::StringRef Arg1, llvm::StringRef Arg2) { + StringRef Arg1, StringRef Arg2) { if (Diags.isDiagnosticInFlight()) Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); else @@ -990,8 +802,8 @@ bool ASTReader::CheckPredefinesBuffers() { /// \brief Read the line table in the source manager block. /// \returns true if there was an error. -bool ASTReader::ParseLineTable(PerFileData &F, - llvm::SmallVectorImpl<uint64_t> &Record) { +bool ASTReader::ParseLineTable(Module &F, + SmallVectorImpl<uint64_t> &Record) { unsigned Idx = 0; LineTableInfo &LineTable = SourceMgr.getLineTable(); @@ -1010,6 +822,9 @@ bool ASTReader::ParseLineTable(PerFileData &F, std::vector<LineEntry> Entries; while (Idx < Record.size()) { int FID = Record[Idx++]; + assert(FID >= 0 && "Serialized line entries for non-local file."); + // Remap FileID from 1-based old view. + FID += F.SLocEntryBaseID - 1; // Extract the line entries unsigned NumEntries = Record[Idx++]; @@ -1131,7 +946,7 @@ public: /// \brief Read a source manager block -ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) { +ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(Module &F) { using namespace SrcMgr; llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; @@ -1188,11 +1003,6 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) { default: // Default behavior: ignore. break; - case SM_LINE_TABLE: - if (ParseLineTable(F, Record)) - return Failure; - break; - case SM_SLOC_FILE_ENTRY: case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: @@ -1235,38 +1045,20 @@ resolveFileRelativeToOriginalDir(const std::string &Filename, return currPCHPath.str(); } -/// \brief Get a cursor that's correctly positioned for reading the source -/// location entry with the given ID. -ASTReader::PerFileData *ASTReader::SLocCursorForID(unsigned ID) { - assert(ID != 0 && ID <= TotalNumSLocEntries && - "SLocCursorForID should only be called for real IDs."); - - ID -= 1; - PerFileData *F = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - F = Chain[N - I - 1]; - if (ID < F->LocalNumSLocEntries) - break; - ID -= F->LocalNumSLocEntries; - } - assert(F && F->LocalNumSLocEntries > ID && "Chain corrupted"); - - F->SLocEntryCursor.JumpToBit(F->SLocOffsets[ID]); - return F; -} - /// \brief Read in the source location entry with the given ID. -ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { +ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { if (ID == 0) return Success; - if (ID > TotalNumSLocEntries) { + if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return Failure; } - PerFileData *F = SLocCursorForID(ID); + Module *F = GlobalSLocEntryMap.find(-ID)->second; + F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; + unsigned BaseOffset = F->SLocEntryBaseOffset; ++NumSLocEntriesRead; unsigned Code = SLocEntryCursor.ReadCode(); @@ -1326,12 +1118,19 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } - FileID FID = SourceMgr.createFileID(File, ReadSourceLocation(*F, Record[1]), + SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); + if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { + // This is the module's main file. + IncludeLoc = getImportLocation(F); + } + FileID FID = SourceMgr.createFileID(File, IncludeLoc, (SrcMgr::CharacteristicKind)Record[2], - ID, Record[0]); + ID, BaseOffset + Record[0]); + SrcMgr::FileInfo &FileInfo = + const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()); + FileInfo.NumCreatedFIDs = Record[6]; if (Record[3]) - const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()) - .setHasLineDirectives(); + FileInfo.setHasLineDirectives(); break; } @@ -1350,14 +1149,15 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { } llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(BlobStart, BlobLen - 1), + = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), Name); - FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset); + FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, + BaseOffset + Offset); if (strcmp(Name, "<built-in>") == 0) { PCHPredefinesBlock Block = { BufferID, - llvm::StringRef(BlobStart, BlobLen - 1) + StringRef(BlobStart, BlobLen - 1) }; PCHPredefinesBuffers.push_back(Block); } @@ -1367,12 +1167,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { case SM_SLOC_EXPANSION_ENTRY: { SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]); - SourceMgr.createInstantiationLoc(SpellingLoc, + SourceMgr.createExpansionLoc(SpellingLoc, ReadSourceLocation(*F, Record[2]), ReadSourceLocation(*F, Record[3]), Record[4], ID, - Record[0]); + BaseOffset + Record[0]); break; } } @@ -1380,6 +1180,25 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { return Success; } +/// \brief Find the location where the module F is imported. +SourceLocation ASTReader::getImportLocation(Module *F) { + if (F->ImportLoc.isValid()) + return F->ImportLoc; + + // Otherwise we have a PCH. It's considered to be "imported" at the first + // location of its includer. + if (F->ImportedBy.empty() || !F->ImportedBy[0]) { + // Main file is the importer. We assume that it is the first entry in the + // entry table. We can't ask the manager, because at the time of PCH loading + // the main file entry doesn't exist yet. + // The very first entry is the invalid instantiation loc, which takes up + // offsets 0 and 1. + return SourceLocation::getFromRawEncoding(2U); + } + //return F->Loaders[0]->FirstLoc; + return F->ImportedBy[0]->FirstLoc; +} + /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. @@ -1403,8 +1222,7 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, } } -PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { - assert(PP && "Forgot to set Preprocessor ?"); +void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) { llvm::BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there @@ -1413,21 +1231,21 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) Stream.JumpToBit(Offset); RecordData Record; - llvm::SmallVector<IdentifierInfo*, 16> MacroArgs; + SmallVector<IdentifierInfo*, 16> MacroArgs; MacroInfo *Macro = 0; while (true) { unsigned Code = Stream.ReadCode(); switch (Code) { case llvm::bitc::END_BLOCK: - return 0; + return; case llvm::bitc::ENTER_SUBBLOCK: // No known subblocks, always skip them. Stream.ReadSubBlockID(); if (Stream.SkipBlock()) { Error("malformed block record in AST file"); - return 0; + return; } continue; @@ -1451,50 +1269,55 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) // of the definition of the macro we were looking for. We're // done. if (Macro) - return 0; + return; - IdentifierInfo *II = DecodeIdentifierInfo(Record[0]); + IdentifierInfo *II = getLocalIdentifier(F, Record[0]); if (II == 0) { Error("macro must have a name in AST file"); - return 0; + return; } SourceLocation Loc = ReadSourceLocation(F, Record[1]); bool isUsed = Record[2]; - MacroInfo *MI = PP->AllocateMacroInfo(Loc); + MacroInfo *MI = PP.AllocateMacroInfo(Loc); MI->setIsUsed(isUsed); MI->setIsFromAST(); unsigned NextIndex = 3; + MI->setExportLocation(ReadSourceLocation(F, Record, NextIndex)); + if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. - bool isC99VarArgs = Record[3]; - bool isGNUVarArgs = Record[4]; + bool isC99VarArgs = Record[NextIndex++]; + bool isGNUVarArgs = Record[NextIndex++]; MacroArgs.clear(); - unsigned NumArgs = Record[5]; - NextIndex = 6 + NumArgs; + unsigned NumArgs = Record[NextIndex++]; for (unsigned i = 0; i != NumArgs; ++i) - MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i])); + MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++])); // Install function-like macro info. MI->setIsFunctionLike(); if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), - PP->getPreprocessorAllocator()); + PP.getPreprocessorAllocator()); } // Finally, install the macro. - PP->setMacroInfo(II, MI); + PP.setMacroInfo(II, MI); // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; - if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) { - // We have a macro definition. Load it now. - PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro, - getMacroDefinition(Record[NextIndex])); + if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() && + Record[NextIndex]) { + // We have a macro definition. Register the association + PreprocessedEntityID + GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]); + PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); + PPRec.RegisterMacroDefinition(Macro, + PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true)); } ++NumMacrosRead; @@ -1510,7 +1333,7 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) Tok.startToken(); Tok.setLocation(ReadSourceLocation(F, Record[0])); Tok.setLength(Record[1]); - if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2])) + if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[3]); Tok.setFlag((Token::TokenFlags)Record[4]); @@ -1520,234 +1343,98 @@ PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) } } - return 0; + return; } -PreprocessedEntity *ASTReader::LoadPreprocessedEntity(PerFileData &F) { - assert(PP && "Forgot to set Preprocessor ?"); - unsigned Code = F.PreprocessorDetailCursor.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return 0; - - case llvm::bitc::ENTER_SUBBLOCK: - Error("unexpected subblock record in preprocessor detail block"); - return 0; - - case llvm::bitc::DEFINE_ABBREV: - Error("unexpected abbrevation record in preprocessor detail block"); - return 0; - - default: - break; - } - - if (!PP->getPreprocessingRecord()) { - Error("no preprocessing record"); - return 0; - } - - // Read the record. - PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - RecordData Record; - PreprocessorDetailRecordTypes RecType = - (PreprocessorDetailRecordTypes)F.PreprocessorDetailCursor.ReadRecord( - Code, Record, BlobStart, BlobLen); - switch (RecType) { - case PPD_MACRO_EXPANSION: { - if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) - return PE; - - MacroExpansion *ME = - new (PPRec) MacroExpansion(DecodeIdentifierInfo(Record[3]), - SourceRange(ReadSourceLocation(F, Record[1]), - ReadSourceLocation(F, Record[2])), - getMacroDefinition(Record[4])); - PPRec.SetPreallocatedEntity(Record[0], ME); - return ME; - } - - case PPD_MACRO_DEFINITION: { - if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) - return PE; - - if (Record[1] > MacroDefinitionsLoaded.size()) { - Error("out-of-bounds macro definition record"); - return 0; - } - - // Decode the identifier info and then check again; if the macro is - // still defined and associated with the identifier, - IdentifierInfo *II = DecodeIdentifierInfo(Record[4]); - if (!MacroDefinitionsLoaded[Record[1] - 1]) { - MacroDefinition *MD - = new (PPRec) MacroDefinition(II, - ReadSourceLocation(F, Record[5]), - SourceRange( - ReadSourceLocation(F, Record[2]), - ReadSourceLocation(F, Record[3]))); - - PPRec.SetPreallocatedEntity(Record[0], MD); - MacroDefinitionsLoaded[Record[1] - 1] = MD; - - if (DeserializationListener) - DeserializationListener->MacroDefinitionRead(Record[1], MD); - } - - return MacroDefinitionsLoaded[Record[1] - 1]; - } - - case PPD_INCLUSION_DIRECTIVE: { - if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) - return PE; - - const char *FullFileNameStart = BlobStart + Record[3]; - const FileEntry *File - = PP->getFileManager().getFile(llvm::StringRef(FullFileNameStart, - BlobLen - Record[3])); - - // FIXME: Stable encoding - InclusionDirective::InclusionKind Kind - = static_cast<InclusionDirective::InclusionKind>(Record[5]); - InclusionDirective *ID - = new (PPRec) InclusionDirective(PPRec, Kind, - llvm::StringRef(BlobStart, Record[3]), - Record[4], - File, - SourceRange(ReadSourceLocation(F, Record[1]), - ReadSourceLocation(F, Record[2]))); - PPRec.SetPreallocatedEntity(Record[0], ID); - return ID; - } - } +PreprocessedEntityID +ASTReader::getGlobalPreprocessedEntityID(Module &M, unsigned LocalID) const { + ContinuousRangeMap<uint32_t, int, 2>::const_iterator + I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); + assert(I != M.PreprocessedEntityRemap.end() + && "Invalid index into preprocessed entity index remap"); - Error("invalid offset in preprocessor detail block"); - return 0; + return LocalID + I->second; } -namespace { - /// \brief Trait class used to search the on-disk hash table containing all of - /// the header search information. - /// - /// The on-disk hash table contains a mapping from each header path to - /// information about that header (how many times it has been included, its - /// controlling macro, etc.). Note that we actually hash based on the - /// filename, and support "deep" comparisons of file names based on current - /// inode numbers, so that the search can cope with non-normalized path names - /// and symlinks. - class HeaderFileInfoTrait { - const char *SearchPath; - struct stat SearchPathStatBuf; - llvm::Optional<int> SearchPathStatResult; - - int StatSimpleCache(const char *Path, struct stat *StatBuf) { - if (Path == SearchPath) { - if (!SearchPathStatResult) - SearchPathStatResult = stat(Path, &SearchPathStatBuf); - - *StatBuf = SearchPathStatBuf; - return *SearchPathStatResult; - } - - return stat(Path, StatBuf); - } - - public: - typedef const char *external_key_type; - typedef const char *internal_key_type; - - typedef HeaderFileInfo data_type; - - HeaderFileInfoTrait(const char *SearchPath = 0) : SearchPath(SearchPath) { } - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(llvm::sys::path::filename(path)); - } +unsigned HeaderFileInfoTrait::ComputeHash(const char *path) { + return llvm::HashString(llvm::sys::path::filename(path)); +} - static internal_key_type GetInternalKey(const char *path) { return path; } +HeaderFileInfoTrait::internal_key_type +HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } - bool EqualKey(internal_key_type a, internal_key_type b) { - if (strcmp(a, b) == 0) - return true; - - if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) - return false; - - // The file names match, but the path names don't. stat() the files to - // see if they are the same. - struct stat StatBufA, StatBufB; - if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB)) - return false; - - return StatBufA.st_ino == StatBufB.st_ino; - } - - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d) { - unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); - unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); - } +bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { + if (strcmp(a, b) == 0) + return true; + + if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) + return false; + + // The file names match, but the path names don't. stat() the files to + // see if they are the same. + struct stat StatBufA, StatBufB; + if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB)) + return false; + + return StatBufA.st_ino == StatBufB.st_ino; +} - static internal_key_type ReadKey(const unsigned char *d, unsigned) { - return (const char *)d; - } +std::pair<unsigned, unsigned> +HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { + unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); + unsigned DataLen = (unsigned) *d++; + return std::make_pair(KeyLen + 1, DataLen); +} - static data_type ReadData(const internal_key_type, const unsigned char *d, +HeaderFileInfoTrait::data_type +HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, unsigned DataLen) { - const unsigned char *End = d + DataLen; - using namespace clang::io; - HeaderFileInfo HFI; - unsigned Flags = *d++; - HFI.isImport = (Flags >> 4) & 0x01; - HFI.isPragmaOnce = (Flags >> 3) & 0x01; - HFI.DirInfo = (Flags >> 1) & 0x03; - HFI.Resolved = Flags & 0x01; - HFI.NumIncludes = ReadUnalignedLE16(d); - HFI.ControllingMacroID = ReadUnalignedLE32(d); - assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); - (void)End; - - // This HeaderFileInfo was externally loaded. - HFI.External = true; - return HFI; - } - }; + const unsigned char *End = d + DataLen; + using namespace clang::io; + HeaderFileInfo HFI; + unsigned Flags = *d++; + HFI.isImport = (Flags >> 5) & 0x01; + HFI.isPragmaOnce = (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 2) & 0x03; + HFI.Resolved = (Flags >> 1) & 0x01; + HFI.IndexHeaderMapHeader = Flags & 0x01; + HFI.NumIncludes = ReadUnalignedLE16(d); + HFI.ControllingMacroID = Reader.getGlobalDeclID(M, ReadUnalignedLE32(d)); + if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) { + // The framework offset is 1 greater than the actual offset, + // since 0 is used as an indicator for "no framework name". + StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); + HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); + } + + assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); + (void)End; + + // This HeaderFileInfo was externally loaded. + HFI.External = true; + return HFI; } -/// \brief The on-disk hash table used for the global method pool. -typedef OnDiskChainedHashTable<HeaderFileInfoTrait> - HeaderFileInfoLookupTable; - -void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F, - uint64_t Offset) { +void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, Module &F, + uint64_t LocalOffset) { // Note that this identifier has a macro definition. II->setHasMacroDefinition(true); - // Adjust the offset based on our position in the chain. - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Chain[I] == &F) - break; - - Offset += Chain[I]->SizeInBits; - } - - UnreadMacroRecordOffsets[II] = Offset; + // Adjust the offset to a global offset. + UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset; } void ASTReader::ReadDefinedMacros() { - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[N - I - 1]; - llvm::BitstreamCursor &MacroCursor = F.MacroCursor; + for (ModuleReverseIterator I = ModuleMgr.rbegin(), + E = ModuleMgr.rend(); I != E; ++I) { + llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; // If there was no preprocessor block, skip this file. if (!MacroCursor.getBitStreamReader()) continue; llvm::BitstreamCursor Cursor = MacroCursor; - Cursor.JumpToBit(F.MacroStartOffset); + Cursor.JumpToBit((*I)->MacroStartOffset); RecordData Record; while (true) { @@ -1780,7 +1467,7 @@ void ASTReader::ReadDefinedMacros() { case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: - DecodeIdentifierInfo(Record[0]); + getLocalIdentifier(**I, Record[0]); break; case PP_TOKEN: @@ -1798,24 +1485,11 @@ void ASTReader::ReadDefinedMacros() { void ASTReader::LoadMacroDefinition( llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) { assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition"); - PerFileData *F = 0; uint64_t Offset = Pos->second; UnreadMacroRecordOffsets.erase(Pos); - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Offset < Chain[I]->SizeInBits) { - F = Chain[I]; - break; - } - - Offset -= Chain[I]->SizeInBits; - } - if (!F) { - Error("Malformed macro record offset"); - return; - } - - ReadMacroRecord(*F, Offset); + RecordLocation Loc = getLocalBitOffset(Offset); + ReadMacroRecord(*Loc.F, Loc.Offset); } void ASTReader::LoadMacroDefinition(IdentifierInfo *II) { @@ -1824,29 +1498,7 @@ void ASTReader::LoadMacroDefinition(IdentifierInfo *II) { LoadMacroDefinition(Pos); } -MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) { - if (ID == 0 || ID > MacroDefinitionsLoaded.size()) - return 0; - - if (!MacroDefinitionsLoaded[ID - 1]) { - unsigned Index = ID - 1; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[N - I - 1]; - if (Index < F.LocalNumMacroDefinitions) { - SavedStreamPosition SavedPosition(F.PreprocessorDetailCursor); - F.PreprocessorDetailCursor.JumpToBit(F.MacroDefinitionOffsets[Index]); - LoadPreprocessedEntity(F); - break; - } - Index -= F.LocalNumMacroDefinitions; - } - assert(MacroDefinitionsLoaded[ID - 1] && "Broken chain"); - } - - return MacroDefinitionsLoaded[ID - 1]; -} - -const FileEntry *ASTReader::getFileEntry(llvm::StringRef filenameStrRef) { +const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { std::string Filename = filenameStrRef; MaybeAddSystemRootToFilename(Filename); const FileEntry *File = FileMgr.getFile(Filename); @@ -1873,21 +1525,21 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) return; - if (isysroot == 0) { + if (isysroot.empty()) { // If no system root was given, default to '/' Filename.insert(Filename.begin(), '/'); return; } - unsigned Length = strlen(isysroot); + unsigned Length = isysroot.size(); if (isysroot[Length - 1] != '/') Filename.insert(Filename.begin(), '/'); - Filename.insert(Filename.begin(), isysroot, isysroot + Length); + Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end()); } ASTReader::ASTReadResult -ASTReader::ReadASTBlock(PerFileData &F) { +ASTReader::ReadASTBlock(Module &F) { llvm::BitstreamCursor &Stream = F.Stream; if (Stream.EnterSubBlock(AST_BLOCK_ID)) { @@ -1897,7 +1549,6 @@ ASTReader::ReadASTBlock(PerFileData &F) { // Read all of the records and blocks for the ASt file. RecordData Record; - bool First = true; while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { @@ -1934,8 +1585,8 @@ ASTReader::ReadASTBlock(PerFileData &F) { case PREPROCESSOR_BLOCK_ID: F.MacroCursor = Stream; - if (PP) - PP->setExternalSource(this); + if (!PP.getExternalSource()) + PP.setExternalSource(this); if (Stream.SkipBlock() || ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { @@ -1955,6 +1606,11 @@ ASTReader::ReadASTBlock(PerFileData &F) { } F.PreprocessorDetailStartOffset = F.PreprocessorDetailCursor.GetCurrentBitNo(); + + if (!PP.getPreprocessingRecord()) + PP.createPreprocessingRecord(true); + if (!PP.getPreprocessingRecord()->getExternalSource()) + PP.getPreprocessingRecord()->SetExternalSource(*this); break; case SOURCE_MANAGER_BLOCK_ID: @@ -1971,7 +1627,6 @@ ASTReader::ReadASTBlock(PerFileData &F) { } break; } - First = false; continue; } @@ -2005,79 +1660,108 @@ ASTReader::ReadASTBlock(PerFileData &F) { break; } - case CHAINED_METADATA: { - if (!First) { - Error("CHAINED_METADATA is not first record in block"); - return Failure; - } - if (Record[0] != VERSION_MAJOR && !DisableValidation) { - Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - // Load the chained file, which is always a PCH file. - switch(ReadASTCore(llvm::StringRef(BlobStart, BlobLen), PCH)) { - case Failure: return Failure; - // If we have to ignore the dependency, we'll have to ignore this too. - case IgnorePCH: return IgnorePCH; - case Success: break; + case IMPORTS: { + // Load each of the imported PCH files. + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + unsigned Length = Record[Idx++]; + llvm::SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + + // Load the AST file. + switch(ReadASTCore(ImportedFile, ImportedKind, &F)) { + case Failure: return Failure; + // If we have to ignore the dependency, we'll have to ignore this too. + case IgnorePCH: return IgnorePCH; + case Success: break; + } } break; } - case TYPE_OFFSET: + case TYPE_OFFSET: { if (F.LocalNumTypes != 0) { Error("duplicate TYPE_OFFSET record in AST file"); return Failure; } F.TypeOffsets = (const uint32_t *)BlobStart; F.LocalNumTypes = Record[0]; + unsigned LocalBaseTypeIndex = Record[1]; + F.BaseTypeIndex = getTotalNumTypes(); + + if (F.LocalNumTypes > 0) { + // Introduce the global -> local mapping for types within this module. + GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F)); + + // Introduce the local -> global mapping for types within this module. + F.TypeRemap.insert(std::make_pair(LocalBaseTypeIndex, + F.BaseTypeIndex - LocalBaseTypeIndex)); + + TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); + } break; - - case DECL_OFFSET: + } + + case DECL_OFFSET: { if (F.LocalNumDecls != 0) { Error("duplicate DECL_OFFSET record in AST file"); return Failure; } F.DeclOffsets = (const uint32_t *)BlobStart; F.LocalNumDecls = Record[0]; + unsigned LocalBaseDeclID = Record[1]; + F.BaseDeclID = getTotalNumDecls(); + + if (F.LocalNumDecls > 0) { + // Introduce the global -> local mapping for declarations within this + // module. + GlobalDeclMap.insert( + std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F)); + + // Introduce the local -> global mapping for declarations within this + // module. + F.DeclRemap.insert(std::make_pair(LocalBaseDeclID, + F.BaseDeclID - LocalBaseDeclID)); + + DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); + } break; - + } + case TU_UPDATE_LEXICAL: { - DeclContextInfo Info = { - /* No visible information */ 0, - reinterpret_cast<const KindDeclIDPair *>(BlobStart), - BlobLen / sizeof(KindDeclIDPair) - }; - DeclContextOffsets[Context ? Context->getTranslationUnitDecl() : 0] - .push_back(Info); + DeclContext *TU = Context.getTranslationUnitDecl(); + DeclContextInfo &Info = F.DeclContextInfos[TU]; + Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart); + Info.NumLexicalDecls + = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair)); + TU->setHasExternalLexicalStorage(true); break; } case UPDATE_VISIBLE: { - serialization::DeclID ID = Record[0]; + unsigned Idx = 0; + serialization::DeclID ID = ReadDeclID(F, Record, Idx); void *Table = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)BlobStart + Record[1], + (const unsigned char *)BlobStart + Record[Idx++], (const unsigned char *)BlobStart, - ASTDeclContextNameLookupTrait(*this)); - if (ID == 1 && Context) { // Is it the TU? - DeclContextInfo Info = { - Table, /* No lexical inforamtion */ 0, 0 - }; - DeclContextOffsets[Context->getTranslationUnitDecl()].push_back(Info); + ASTDeclContextNameLookupTrait(*this, F)); + if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? + DeclContext *TU = Context.getTranslationUnitDecl(); + F.DeclContextInfos[TU].NameLookupTableData = Table; + TU->setHasExternalVisibleStorage(true); } else - PendingVisibleUpdates[ID].push_back(Table); + PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); break; } case REDECLS_UPDATE_LATEST: { assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs"); - for (unsigned i = 0, e = Record.size(); i < e; i += 2) { - DeclID First = Record[i], Latest = Record[i+1]; - assert((FirstLatestDeclIDs.find(First) == FirstLatestDeclIDs.end() || - Latest > FirstLatestDeclIDs[First]) && - "The new latest is supposed to come after the previous latest"); + for (unsigned i = 0, e = Record.size(); i < e; /* in loop */) { + DeclID First = ReadDeclID(F, Record, i); + DeclID Latest = ReadDeclID(F, Record, i); FirstLatestDeclIDs[First] = Latest; } break; @@ -2096,35 +1780,47 @@ ASTReader::ReadASTBlock(PerFileData &F) { (const unsigned char *)F.IdentifierTableData + Record[0], (const unsigned char *)F.IdentifierTableData, ASTIdentifierLookupTrait(*this, F)); - if (PP) - PP->getIdentifierTable().setExternalIdentifierLookup(this); + + PP.getIdentifierTable().setExternalIdentifierLookup(this); } break; - case IDENTIFIER_OFFSET: + case IDENTIFIER_OFFSET: { if (F.LocalNumIdentifiers != 0) { Error("duplicate IDENTIFIER_OFFSET record in AST file"); return Failure; } F.IdentifierOffsets = (const uint32_t *)BlobStart; F.LocalNumIdentifiers = Record[0]; + unsigned LocalBaseIdentifierID = Record[1]; + F.BaseIdentifierID = getTotalNumIdentifiers(); + + if (F.LocalNumIdentifiers > 0) { + // Introduce the global -> local mapping for identifiers within this + // module. + GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1, + &F)); + + // Introduce the local -> global mapping for identifiers within this + // module. + F.IdentifierRemap.insert( + std::make_pair(LocalBaseIdentifierID, + F.BaseIdentifierID - LocalBaseIdentifierID)); + + IdentifiersLoaded.resize(IdentifiersLoaded.size() + + F.LocalNumIdentifiers); + } break; - + } + case EXTERNAL_DEFINITIONS: - // Optimization for the first block. - if (ExternalDefinitions.empty()) - ExternalDefinitions.swap(Record); - else - ExternalDefinitions.insert(ExternalDefinitions.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I])); break; case SPECIAL_TYPES: - // Optimization for the first block - if (SpecialTypes.empty()) - SpecialTypes.swap(Record); - else - SpecialTypes.insert(SpecialTypes.end(), Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); break; case STATISTICS: @@ -2135,42 +1831,63 @@ ASTReader::ReadASTBlock(PerFileData &F) { break; case UNUSED_FILESCOPED_DECLS: - // Optimization for the first block. - if (UnusedFileScopedDecls.empty()) - UnusedFileScopedDecls.swap(Record); - else - UnusedFileScopedDecls.insert(UnusedFileScopedDecls.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I])); break; case DELEGATING_CTORS: - // Optimization for the first block. - if (DelegatingCtorDecls.empty()) - DelegatingCtorDecls.swap(Record); - else - DelegatingCtorDecls.insert(DelegatingCtorDecls.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I])); break; case WEAK_UNDECLARED_IDENTIFIERS: - // Later blocks overwrite earlier ones. - WeakUndeclaredIdentifiers.swap(Record); + if (Record.size() % 4 != 0) { + Error("invalid weak identifiers record"); + return Failure; + } + + // FIXME: Ignore weak undeclared identifiers from non-original PCH + // files. This isn't the way to do it :) + WeakUndeclaredIdentifiers.clear(); + + // Translate the weak, undeclared identifiers into global IDs. + for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) { + WeakUndeclaredIdentifiers.push_back( + getGlobalIdentifierID(F, Record[I++])); + WeakUndeclaredIdentifiers.push_back( + getGlobalIdentifierID(F, Record[I++])); + WeakUndeclaredIdentifiers.push_back( + ReadSourceLocation(F, Record, I).getRawEncoding()); + WeakUndeclaredIdentifiers.push_back(Record[I++]); + } break; case LOCALLY_SCOPED_EXTERNAL_DECLS: - // Optimization for the first block. - if (LocallyScopedExternalDecls.empty()) - LocallyScopedExternalDecls.swap(Record); - else - LocallyScopedExternalDecls.insert(LocallyScopedExternalDecls.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I])); break; - case SELECTOR_OFFSETS: + case SELECTOR_OFFSETS: { F.SelectorOffsets = (const uint32_t *)BlobStart; F.LocalNumSelectors = Record[0]; - break; + unsigned LocalBaseSelectorID = Record[1]; + F.BaseSelectorID = getTotalNumSelectors(); + + if (F.LocalNumSelectors > 0) { + // Introduce the global -> local mapping for selectors within this + // module. + GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F)); + + // Introduce the local -> global mapping for selectors within this + // module. + F.SelectorRemap.insert(std::make_pair(LocalBaseSelectorID, + F.BaseSelectorID - LocalBaseSelectorID)); + SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors); + } + break; + } + case METHOD_POOL: F.SelectorLookupTableData = (const unsigned char *)BlobStart; if (Record[0]) @@ -2178,12 +1895,19 @@ ASTReader::ReadASTBlock(PerFileData &F) { = ASTSelectorLookupTable::Create( F.SelectorLookupTableData + Record[0], F.SelectorLookupTableData, - ASTSelectorLookupTrait(*this)); + ASTSelectorLookupTrait(*this, F)); TotalNumMethodPoolEntries += Record[1]; break; case REFERENCED_SELECTOR_POOL: - F.ReferencedSelectorsData.swap(Record); + if (!Record.empty()) { + for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { + ReferencedSelectorsData.push_back(getGlobalSelectorID(F, + Record[Idx++])); + ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx). + getRawEncoding()); + } + } break; case PP_COUNTER_VALUE: @@ -2191,10 +1915,94 @@ ASTReader::ReadASTBlock(PerFileData &F) { Listener->ReadCounter(Record[0]); break; - case SOURCE_LOCATION_OFFSETS: - F.SLocOffsets = (const uint32_t *)BlobStart; + case SOURCE_LOCATION_OFFSETS: { + F.SLocEntryOffsets = (const uint32_t *)BlobStart; F.LocalNumSLocEntries = Record[0]; - F.LocalSLocSize = Record[1]; + unsigned SLocSpaceSize = Record[1]; + llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = + SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, + SLocSpaceSize); + // Make our entry in the range map. BaseID is negative and growing, so + // we invert it. Because we invert it, though, we need the other end of + // the range. + unsigned RangeStart = + unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1; + GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); + F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); + + // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. + assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0); + GlobalSLocOffsetMap.insert( + std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset + - SLocSpaceSize,&F)); + + // Initialize the remapping table. + // Invalid stays invalid. + F.SLocRemap.insert(std::make_pair(0U, 0)); + // This module. Base was 2 when being compiled. + F.SLocRemap.insert(std::make_pair(2U, + static_cast<int>(F.SLocEntryBaseOffset - 2))); + + TotalNumSLocEntries += F.LocalNumSLocEntries; + break; + } + + case MODULE_OFFSET_MAP: { + // Additional remapping information. + const unsigned char *Data = (const unsigned char*)BlobStart; + const unsigned char *DataEnd = Data + BlobLen; + + // Continuous range maps we may be updating in our module. + ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + IdentifierRemap(F.IdentifierRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + PreprocessedEntityRemap(F.PreprocessedEntityRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder + SelectorRemap(F.SelectorRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap); + + while(Data < DataEnd) { + uint16_t Len = io::ReadUnalignedLE16(Data); + StringRef Name = StringRef((const char*)Data, Len); + Data += Len; + Module *OM = ModuleMgr.lookup(Name); + if (!OM) { + Error("SourceLocation remap refers to unknown module"); + return Failure; + } + + uint32_t SLocOffset = io::ReadUnalignedLE32(Data); + uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data); + uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data); + uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data); + uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data); + uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data); + + // Source location offset is mapped to OM->SLocEntryBaseOffset. + SLocRemap.insert(std::make_pair(SLocOffset, + static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset))); + IdentifierRemap.insert( + std::make_pair(IdentifierIDOffset, + OM->BaseIdentifierID - IdentifierIDOffset)); + PreprocessedEntityRemap.insert( + std::make_pair(PreprocessedEntityIDOffset, + OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset)); + SelectorRemap.insert(std::make_pair(SelectorIDOffset, + OM->BaseSelectorID - SelectorIDOffset)); + DeclRemap.insert(std::make_pair(DeclIDOffset, + OM->BaseDeclID - DeclIDOffset)); + + TypeRemap.insert(std::make_pair(TypeIndexOffset, + OM->BaseTypeIndex - TypeIndexOffset)); + } + break; + } + + case SOURCE_MANAGER_LINE_TABLE: + if (ParseLineTable(F, Record)) + return Failure; break; case FILE_SOURCE_LOCATION_OFFSETS: @@ -2202,13 +2010,17 @@ ASTReader::ReadASTBlock(PerFileData &F) { F.LocalNumSLocFileEntries = Record[0]; break; - case SOURCE_LOCATION_PRELOADS: - if (PreloadSLocEntries.empty()) - PreloadSLocEntries.swap(Record); - else - PreloadSLocEntries.insert(PreloadSLocEntries.end(), - Record.begin(), Record.end()); + case SOURCE_LOCATION_PRELOADS: { + // Need to transform from the local view (1-based IDs) to the global view, + // which is based off F.SLocEntryBaseID. + if (!F.PreloadSLocEntries.empty()) { + Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); + return Failure; + } + + F.PreloadSLocEntries.swap(Record); break; + } case STAT_CACHE: { if (!DisableStatCache) { @@ -2223,35 +2035,56 @@ ASTReader::ReadASTBlock(PerFileData &F) { } case EXT_VECTOR_DECLS: - // Optimization for the first block. - if (ExtVectorDecls.empty()) - ExtVectorDecls.swap(Record); - else - ExtVectorDecls.insert(ExtVectorDecls.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); break; case VTABLE_USES: + if (Record.size() % 3 != 0) { + Error("Invalid VTABLE_USES record"); + return Failure; + } + // Later tables overwrite earlier ones. - VTableUses.swap(Record); + // FIXME: Modules will have some trouble with this. This is clearly not + // the right way to do this. + VTableUses.clear(); + + for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { + VTableUses.push_back(getGlobalDeclID(F, Record[Idx++])); + VTableUses.push_back( + ReadSourceLocation(F, Record, Idx).getRawEncoding()); + VTableUses.push_back(Record[Idx++]); + } break; case DYNAMIC_CLASSES: - // Optimization for the first block. - if (DynamicClasses.empty()) - DynamicClasses.swap(Record); - else - DynamicClasses.insert(DynamicClasses.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + DynamicClasses.push_back(getGlobalDeclID(F, Record[I])); break; case PENDING_IMPLICIT_INSTANTIATIONS: - F.PendingInstantiations.swap(Record); + if (PendingInstantiations.size() % 2 != 0) { + Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); + return Failure; + } + + // Later lists of pending instantiations overwrite earlier ones. + // FIXME: This is most certainly wrong for modules. + PendingInstantiations.clear(); + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); + PendingInstantiations.push_back( + ReadSourceLocation(F, Record, I).getRawEncoding()); + } break; case SEMA_DECL_REFS: // Later tables overwrite earlier ones. - SemaDeclRefs.swap(Record); + // FIXME: Modules will have some trouble with this. + SemaDeclRefs.clear(); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; case ORIGINAL_FILE_NAME: @@ -2274,28 +2107,54 @@ ASTReader::ReadASTBlock(PerFileData &F) { case VERSION_CONTROL_BRANCH_REVISION: { const std::string &CurBranch = getClangFullRepositoryVersion(); - llvm::StringRef ASTBranch(BlobStart, BlobLen); - if (llvm::StringRef(CurBranch) != ASTBranch && !DisableValidation) { + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; return IgnorePCH; } break; } - case MACRO_DEFINITION_OFFSETS: - F.MacroDefinitionOffsets = (const uint32_t *)BlobStart; - F.NumPreallocatedPreprocessingEntities = Record[0]; - F.LocalNumMacroDefinitions = Record[1]; - break; + case PPD_ENTITIES_OFFSETS: { + F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; + assert(BlobLen % sizeof(PPEntityOffset) == 0); + F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); + + unsigned LocalBasePreprocessedEntityID = Record[0]; + + unsigned StartingID; + if (!PP.getPreprocessingRecord()) + PP.createPreprocessingRecord(true); + if (!PP.getPreprocessingRecord()->getExternalSource()) + PP.getPreprocessingRecord()->SetExternalSource(*this); + StartingID + = PP.getPreprocessingRecord() + ->allocateLoadedEntities(F.NumPreprocessedEntities); + F.BasePreprocessedEntityID = StartingID; + + if (F.NumPreprocessedEntities > 0) { + // Introduce the global -> local mapping for preprocessed entities in + // this module. + GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F)); + + // Introduce the local -> global mapping for preprocessed entities in + // this module. + F.PreprocessedEntityRemap.insert( + std::make_pair(LocalBasePreprocessedEntityID, + F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID)); + } + break; + } + case DECL_UPDATE_OFFSETS: { if (Record.size() % 2 != 0) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; I += 2) - DeclUpdateOffsets[static_cast<DeclID>(Record[I])] - .push_back(std::make_pair(&F, Record[I+1])); + DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] + .push_back(std::make_pair(&F, Record[I+1])); break; } @@ -2305,8 +2164,22 @@ ASTReader::ReadASTBlock(PerFileData &F) { return Failure; } for (unsigned I = 0, N = Record.size(); I != N; I += 2) - ReplacedDecls[static_cast<DeclID>(Record[I])] = - std::make_pair(&F, Record[I+1]); + ReplacedDecls[getGlobalDeclID(F, Record[I])] + = std::make_pair(&F, Record[I+1]); + break; + } + + case OBJC_CHAINED_CATEGORIES: { + if (Record.size() % 3 != 0) { + Error("invalid OBJC_CHAINED_CATEGORIES block in AST file"); + return Failure; + } + for (unsigned I = 0, N = Record.size(); I != N; I += 3) { + serialization::GlobalDeclID GlobID = getGlobalDeclID(F, Record[I]); + F.ChainedObjCCategories[GlobID] = std::make_pair(Record[I+1], + Record[I+2]); + ObjCChainedCategoriesInterfaces.insert(GlobID); + } break; } @@ -2318,6 +2191,7 @@ ASTReader::ReadASTBlock(PerFileData &F) { F.LocalNumCXXBaseSpecifiers = Record[0]; F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; + NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers; break; } @@ -2326,31 +2200,42 @@ ASTReader::ReadASTBlock(PerFileData &F) { Error("invalid DIAG_USER_MAPPINGS block in AST file"); return Failure; } - if (PragmaDiagMappings.empty()) - PragmaDiagMappings.swap(Record); + + if (F.PragmaDiagMappings.empty()) + F.PragmaDiagMappings.swap(Record); else - PragmaDiagMappings.insert(PragmaDiagMappings.end(), - Record.begin(), Record.end()); + F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(), + Record.begin(), Record.end()); break; case CUDA_SPECIAL_DECL_REFS: // Later tables overwrite earlier ones. - CUDASpecialDeclRefs.swap(Record); + // FIXME: Modules will have trouble with this. + CUDASpecialDeclRefs.clear(); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; - case HEADER_SEARCH_TABLE: + case HEADER_SEARCH_TABLE: { F.HeaderFileInfoTableData = BlobStart; F.LocalNumHeaderFileInfos = Record[1]; + F.HeaderFileFrameworkStrings = BlobStart + Record[2]; if (Record[0]) { F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create( (const unsigned char *)F.HeaderFileInfoTableData + Record[0], - (const unsigned char *)F.HeaderFileInfoTableData); - if (PP) - PP->getHeaderSearchInfo().SetExternalSource(this); + (const unsigned char *)F.HeaderFileInfoTableData, + HeaderFileInfoTrait(*this, F, + &PP.getHeaderSearchInfo(), + BlobStart + Record[2])); + + PP.getHeaderSearchInfo().SetExternalSource(this); + if (!PP.getHeaderSearchInfo().getExternalLookup()) + PP.getHeaderSearchInfo().SetExternalLookup(this); } break; - + } + case FP_PRAGMA_OPTIONS: // Later tables overwrite earlier ones. FPPragmaOptions.swap(Record); @@ -2362,272 +2247,222 @@ ASTReader::ReadASTBlock(PerFileData &F) { break; case TENTATIVE_DEFINITIONS: - // Optimization for the first block. - if (TentativeDefinitions.empty()) - TentativeDefinitions.swap(Record); - else - TentativeDefinitions.insert(TentativeDefinitions.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I])); break; case KNOWN_NAMESPACES: - // Optimization for the first block. - if (KnownNamespaces.empty()) - KnownNamespaces.swap(Record); - else - KnownNamespaces.insert(KnownNamespaces.end(), - Record.begin(), Record.end()); + for (unsigned I = 0, N = Record.size(); I != N; ++I) + KnownNamespaces.push_back(getGlobalDeclID(F, Record[I])); break; } - First = false; } Error("premature end of bitstream in AST file"); return Failure; } -ASTReader::ASTReadResult ASTReader::validateFileEntries() { - for (unsigned CI = 0, CN = Chain.size(); CI != CN; ++CI) { - PerFileData *F = Chain[CI]; - llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; +ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) { + llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor; - for (unsigned i = 0, e = F->LocalNumSLocFileEntries; i != e; ++i) { - SLocEntryCursor.JumpToBit(F->SLocFileOffsets[i]); - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK || - Code == llvm::bitc::ENTER_SUBBLOCK || - Code == llvm::bitc::DEFINE_ABBREV) { - Error("incorrectly-formatted source location entry in AST file"); - return Failure; + for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) { + SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]); + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK || + Code == llvm::bitc::ENTER_SUBBLOCK || + Code == llvm::bitc::DEFINE_ABBREV) { + Error("incorrectly-formatted source location entry in AST file"); + return Failure; + } + + RecordData Record; + const char *BlobStart; + unsigned BlobLen; + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: + Error("incorrectly-formatted source location entry in AST file"); + return Failure; + + case SM_SLOC_FILE_ENTRY: { + StringRef Filename(BlobStart, BlobLen); + const FileEntry *File = getFileEntry(Filename); + + if (File == 0) { + std::string ErrorStr = "could not find file '"; + ErrorStr += Filename; + ErrorStr += "' referenced by AST file"; + Error(ErrorStr.c_str()); + return IgnorePCH; } - - RecordData Record; - const char *BlobStart; - unsigned BlobLen; - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: - Error("incorrectly-formatted source location entry in AST file"); + + if (Record.size() < 6) { + Error("source location entry is incorrect"); return Failure; - - case SM_SLOC_FILE_ENTRY: { - llvm::StringRef Filename(BlobStart, BlobLen); - const FileEntry *File = getFileEntry(Filename); - - if (File == 0) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; - Error(ErrorStr.c_str()); - return IgnorePCH; - } - - if (Record.size() < 6) { - Error("source location entry is incorrect"); - return Failure; - } + } - // The stat info from the FileEntry came from the cached stat - // info of the PCH, so we cannot trust it. - struct stat StatBuf; - if (::stat(File->getName(), &StatBuf) != 0) { - StatBuf.st_size = File->getSize(); - StatBuf.st_mtime = File->getModificationTime(); - } + // The stat info from the FileEntry came from the cached stat + // info of the PCH, so we cannot trust it. + struct stat StatBuf; + if (::stat(File->getName(), &StatBuf) != 0) { + StatBuf.st_size = File->getSize(); + StatBuf.st_mtime = File->getModificationTime(); + } - if (((off_t)Record[4] != StatBuf.st_size + if (((off_t)Record[4] != StatBuf.st_size #if !defined(LLVM_ON_WIN32) - // In our regression testing, the Windows file system seems to - // have inconsistent modification times that sometimes - // erroneously trigger this error-handling path. - || (time_t)Record[5] != StatBuf.st_mtime + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || (time_t)Record[5] != StatBuf.st_mtime #endif - )) { - Error(diag::err_fe_pch_file_modified, Filename); - return IgnorePCH; - } - - break; - } + )) { + Error(diag::err_fe_pch_file_modified, Filename); + return IgnorePCH; } + + break; + } } } return Success; } +namespace { + /// \brief Visitor class used to look up identifirs in an AST file. + class IdentifierLookupVisitor { + StringRef Name; + IdentifierInfo *Found; + public: + explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { } + + static bool visit(Module &M, void *UserData) { + IdentifierLookupVisitor *This + = static_cast<IdentifierLookupVisitor *>(UserData); + + ASTIdentifierLookupTable *IdTable + = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; + if (!IdTable) + return false; + + std::pair<const char*, unsigned> Key(This->Name.begin(), + This->Name.size()); + ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key); + if (Pos == IdTable->end()) + return false; + + // Dereferencing the iterator has the effect of building the + // IdentifierInfo node and populating it with the various + // declarations it needs. + This->Found = *Pos; + return true; + } + + // \brief Retrieve the identifier info found within the module + // files. + IdentifierInfo *getIdentifierInfo() const { return Found; } + }; +} + + ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, - ASTFileType Type) { - switch(ReadASTCore(FileName, Type)) { + ModuleKind Type) { + switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { case Failure: return Failure; case IgnorePCH: return IgnorePCH; case Success: break; } // Here comes stuff that we only do once the entire chain is loaded. - - if (!DisableValidation) { - switch(validateFileEntries()) { - case Failure: return Failure; - case IgnorePCH: return IgnorePCH; - case Success: break; - } - } - - // Allocate space for loaded slocentries, identifiers, decls and types. - unsigned TotalNumIdentifiers = 0, TotalNumTypes = 0, TotalNumDecls = 0, - TotalNumPreallocatedPreprocessingEntities = 0, TotalNumMacroDefs = 0, - TotalNumSelectors = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - TotalNumSLocEntries += Chain[I]->LocalNumSLocEntries; - NextSLocOffset += Chain[I]->LocalSLocSize; - TotalNumIdentifiers += Chain[I]->LocalNumIdentifiers; - TotalNumTypes += Chain[I]->LocalNumTypes; - TotalNumDecls += Chain[I]->LocalNumDecls; - TotalNumPreallocatedPreprocessingEntities += - Chain[I]->NumPreallocatedPreprocessingEntities; - TotalNumMacroDefs += Chain[I]->LocalNumMacroDefinitions; - TotalNumSelectors += Chain[I]->LocalNumSelectors; - } - SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, NextSLocOffset); - IdentifiersLoaded.resize(TotalNumIdentifiers); - TypesLoaded.resize(TotalNumTypes); - DeclsLoaded.resize(TotalNumDecls); - MacroDefinitionsLoaded.resize(TotalNumMacroDefs); - if (PP) { - if (TotalNumIdentifiers > 0) - PP->getHeaderSearchInfo().SetExternalLookup(this); - if (TotalNumPreallocatedPreprocessingEntities > 0) { - if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(true); - PP->getPreprocessingRecord()->SetExternalSource(*this, - TotalNumPreallocatedPreprocessingEntities); - } - } - SelectorsLoaded.resize(TotalNumSelectors); - // Preload SLocEntries. - for (unsigned I = 0, N = PreloadSLocEntries.size(); I != N; ++I) { - ASTReadResult Result = ReadSLocEntryRecord(PreloadSLocEntries[I]); - if (Result != Success) - return Result; - } - + // Check the predefines buffers. - if (!DisableValidation && CheckPredefinesBuffers()) + if (!DisableValidation && Type != MK_Module && Type != MK_Preamble && + // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines; + // if DisableValidation is true, defines that were set on command-line + // but not in the PCH file will not be added to SuggestedPredefines. + CheckPredefinesBuffers()) return IgnorePCH; - if (PP) { - // Initialization of keywords and pragmas occurs before the - // AST file is read, so there may be some identifiers that were - // loaded into the IdentifierTable before we intercepted the - // creation of identifiers. Iterate through the list of known - // identifiers and determine whether we have to establish - // preprocessor definitions or top-level identifier declaration - // chains for those identifiers. - // - // We copy the IdentifierInfo pointers to a small vector first, - // since de-serializing declarations or macro definitions can add - // new entries into the identifier table, invalidating the - // iterators. - llvm::SmallVector<IdentifierInfo *, 128> Identifiers; - for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(), - IdEnd = PP->getIdentifierTable().end(); - Id != IdEnd; ++Id) - Identifiers.push_back(Id->second); - // We need to search the tables in all files. - for (unsigned J = 0, M = Chain.size(); J != M; ++J) { - ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Chain[J]->IdentifierLookupTable; - // Not all AST files necessarily have identifier tables, only the useful - // ones. - if (!IdTable) - continue; - for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { - IdentifierInfo *II = Identifiers[I]; - // Look in the on-disk hash tables for an entry for this identifier - ASTIdentifierLookupTrait Info(*this, *Chain[J], II); - std::pair<const char*,unsigned> Key(II->getNameStart(),II->getLength()); - ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); - if (Pos == IdTable->end()) - continue; - - // Dereferencing the iterator has the effect of populating the - // IdentifierInfo node with the various declarations it needs. - (void)*Pos; - } - } + // Initialization of keywords and pragmas occurs before the + // AST file is read, so there may be some identifiers that were + // loaded into the IdentifierTable before we intercepted the + // creation of identifiers. Iterate through the list of known + // identifiers and determine whether we have to establish + // preprocessor definitions or top-level identifier declaration + // chains for those identifiers. + // + // We copy the IdentifierInfo pointers to a small vector first, + // since de-serializing declarations or macro definitions can add + // new entries into the identifier table, invalidating the + // iterators. + // + // FIXME: We need a lazier way to load this information, e.g., by marking + // the identifier data as 'dirty', so that it will be looked up in the + // AST file(s) if it is uttered in the source. This could save us some + // module load time. + SmallVector<IdentifierInfo *, 128> Identifiers; + for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), + IdEnd = PP.getIdentifierTable().end(); + Id != IdEnd; ++Id) + Identifiers.push_back(Id->second); + + for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { + IdentifierLookupVisitor Visitor(Identifiers[I]->getName()); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); } - if (Context) - InitializeContext(*Context); + InitializeContext(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); - // If this AST file is a precompiled preamble, then set the main file ID of - // the source manager to the file source file from which the preamble was - // built. This is the only valid way to use a precompiled preamble. - if (Type == Preamble) { - if (OriginalFileID.isInvalid()) { - SourceLocation Loc - = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1); - if (Loc.isValid()) - OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first; + // If this AST file is a precompiled preamble, then set the preamble file ID + // of the source manager to the file source file from which the preamble was + // built. + if (Type == MK_Preamble) { + if (!OriginalFileID.isInvalid()) { + OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID + + OriginalFileID.getOpaqueValue() - 1); + SourceMgr.setPreambleFileID(OriginalFileID); } - - if (!OriginalFileID.isInvalid()) - SourceMgr.SetPreambleFileID(OriginalFileID); } return Success; } -ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName, - ASTFileType Type) { - PerFileData *Prev = Chain.empty() ? 0 : Chain.back(); - Chain.push_back(new PerFileData(Type)); - PerFileData &F = *Chain.back(); - if (Prev) - Prev->NextInSource = &F; - else - FirstInSource = &F; - F.Loaders.push_back(Prev); +ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, + ModuleKind Type, + Module *ImportedBy) { + Module *M; + bool NewModule; + std::string ErrorStr; + llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy, + ErrorStr); + + if (!M) { + // We couldn't load the module. + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + return Failure; + } - // Set the AST file name. - F.FileName = FileName; + if (!NewModule) { + // We've already loaded this module. + return Success; + } + // FIXME: This seems rather a hack. Should CurrentDir be part of the + // module? if (FileName != "-") { CurrentDir = llvm::sys::path::parent_path(FileName); if (CurrentDir.empty()) CurrentDir = "."; } - if (!ASTBuffers.empty()) { - F.Buffer.reset(ASTBuffers.back()); - ASTBuffers.pop_back(); - assert(F.Buffer && "Passed null buffer"); - } else { - // Open the AST file. - // - // FIXME: This shouldn't be here, we should just take a raw_ostream. - std::string ErrStr; - llvm::error_code ec; - if (FileName == "-") { - ec = llvm::MemoryBuffer::getSTDIN(F.Buffer); - if (ec) - ErrStr = ec.message(); - } else - F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr)); - if (!F.Buffer) { - Error(ErrStr.c_str()); - return IgnorePCH; - } - } - - // Initialize the stream - F.StreamFile.init((const unsigned char *)F.Buffer->getBufferStart(), - (const unsigned char *)F.Buffer->getBufferEnd()); + Module &F = *M; llvm::BitstreamCursor &Stream = F.Stream; Stream.init(F.StreamFile); F.SizeInBits = F.Buffer->getBufferSize() * 8; - + // Sniff for the signature. if (Stream.Read(8) != 'C' || Stream.Read(8) != 'P' || @@ -2668,9 +2503,8 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName, // AST block, skipping subblocks, to see if there are other // AST blocks elsewhere. - // Clear out any preallocated source location entries, so that - // the source manager does not try to resolve them later. - SourceMgr.ClearPreallocatedSLocEntries(); + // FIXME: We can't clear loaded slocentries anymore. + //SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. if (F.StatCache) @@ -2687,143 +2521,152 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName, break; } } + + // Once read, set the Module bit base offset and update the size in + // bits of all files we've seen. + F.GlobalBitOffset = TotalModulesSizeInBits; + TotalModulesSizeInBits += F.SizeInBits; + GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); - return Success; -} + // Make sure that the files this module was built against are still available. + if (!DisableValidation) { + switch(validateFileEntries(*M)) { + case Failure: return Failure; + case IgnorePCH: return IgnorePCH; + case Success: break; + } + } + + // Preload SLocEntries. + for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) { + int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; + // Load it through the SourceManager and don't call ReadSLocEntryRecord() + // directly because the entry may have already been loaded in which case + // calling ReadSLocEntryRecord() directly would trigger an assertion in + // SourceManager. + SourceMgr.getLoadedSLocEntryByID(Index); + } -void ASTReader::setPreprocessor(Preprocessor &pp) { - PP = &pp; - unsigned TotalNum = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) - TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities; - if (TotalNum) { - if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(true); - PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum); - } + return Success; } -void ASTReader::InitializeContext(ASTContext &Ctx) { - Context = &Ctx; - assert(Context && "Passed null context!"); +void ASTReader::InitializeContext() { + // If there's a listener, notify them that we "read" the translation unit. + if (DeserializationListener) + DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, + Context.getTranslationUnitDecl()); - assert(PP && "Forgot to set Preprocessor ?"); - PP->getIdentifierTable().setExternalIdentifierLookup(this); - PP->getHeaderSearchInfo().SetExternalLookup(this); - PP->setExternalSource(this); - PP->getHeaderSearchInfo().SetExternalSource(this); + // Make sure we load the declaration update records for the translation unit, + // if there are any. + loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, + Context.getTranslationUnitDecl()); + + // FIXME: Find a better way to deal with collisions between these + // built-in types. Right now, we just ignore the problem. - // If we have an update block for the TU waiting, we have to add it before - // deserializing the decl. - DeclContextOffsetsMap::iterator DCU = DeclContextOffsets.find(0); - if (DCU != DeclContextOffsets.end()) { - // Insertion could invalidate map, so grab vector. - DeclContextInfos T; - T.swap(DCU->second); - DeclContextOffsets.erase(DCU); - DeclContextOffsets[Ctx.getTranslationUnitDecl()].swap(T); - } - - // Load the translation unit declaration - GetTranslationUnitDecl(); - // Load the special types. - Context->setBuiltinVaListType( - GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST])); - if (unsigned Id = SpecialTypes[SPECIAL_TYPE_OBJC_ID]) - Context->setObjCIdType(GetType(Id)); - if (unsigned Sel = SpecialTypes[SPECIAL_TYPE_OBJC_SELECTOR]) - Context->setObjCSelType(GetType(Sel)); - if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL]) - Context->setObjCProtoType(GetType(Proto)); - if (unsigned Class = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS]) - Context->setObjCClassType(GetType(Class)); - - if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) - Context->setCFConstantStringType(GetType(String)); - if (unsigned FastEnum - = SpecialTypes[SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) - Context->setObjCFastEnumerationStateType(GetType(FastEnum)); - if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { - QualType FileType = GetType(File); - if (FileType.isNull()) { - Error("FILE type is NULL"); - return; + if (SpecialTypes.size() > NumSpecialTypeIDs) { + if (Context.getBuiltinVaListType().isNull()) { + Context.setBuiltinVaListType( + GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST])); } - if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) - Context->setFILEDecl(Typedef->getDecl()); - else { - const TagType *Tag = FileType->getAs<TagType>(); - if (!Tag) { - Error("Invalid FILE type in AST file"); + + if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL]) { + if (Context.ObjCProtoType.isNull()) + Context.ObjCProtoType = GetType(Proto); + } + + if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { + if (!Context.CFConstantStringTypeDecl) + Context.setCFConstantStringType(GetType(String)); + } + + if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { + QualType FileType = GetType(File); + if (FileType.isNull()) { + Error("FILE type is NULL"); return; } - Context->setFILEDecl(Tag->getDecl()); + + if (!Context.FILEDecl) { + if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) + Context.setFILEDecl(Typedef->getDecl()); + else { + const TagType *Tag = FileType->getAs<TagType>(); + if (!Tag) { + Error("Invalid FILE type in AST file"); + return; + } + Context.setFILEDecl(Tag->getDecl()); + } + } } - } - if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_jmp_buf]) { - QualType Jmp_bufType = GetType(Jmp_buf); - if (Jmp_bufType.isNull()) { - Error("jmp_bug type is NULL"); - return; + + if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_jmp_buf]) { + QualType Jmp_bufType = GetType(Jmp_buf); + if (Jmp_bufType.isNull()) { + Error("jmp_buf type is NULL"); + return; + } + + if (!Context.jmp_bufDecl) { + if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) + Context.setjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Jmp_bufType->getAs<TagType>(); + if (!Tag) { + Error("Invalid jmp_buf type in AST file"); + return; + } + Context.setjmp_bufDecl(Tag->getDecl()); + } + } } - if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) - Context->setjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Jmp_bufType->getAs<TagType>(); - if (!Tag) { - Error("Invalid jmp_buf type in AST file"); + + if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_sigjmp_buf]) { + QualType Sigjmp_bufType = GetType(Sigjmp_buf); + if (Sigjmp_bufType.isNull()) { + Error("sigjmp_buf type is NULL"); return; } - Context->setjmp_bufDecl(Tag->getDecl()); + + if (!Context.sigjmp_bufDecl) { + if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) + Context.setsigjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Sigjmp_bufType->getAs<TagType>(); + assert(Tag && "Invalid sigjmp_buf type in AST file"); + Context.setsigjmp_bufDecl(Tag->getDecl()); + } + } } - } - if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_sigjmp_buf]) { - QualType Sigjmp_bufType = GetType(Sigjmp_buf); - if (Sigjmp_bufType.isNull()) { - Error("sigjmp_buf type is NULL"); - return; + + if (unsigned ObjCIdRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { + if (Context.ObjCIdRedefinitionType.isNull()) + Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); } - if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) - Context->setsigjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Sigjmp_bufType->getAs<TagType>(); - assert(Tag && "Invalid sigjmp_buf type in AST file"); - Context->setsigjmp_bufDecl(Tag->getDecl()); + + if (unsigned ObjCClassRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { + if (Context.ObjCClassRedefinitionType.isNull()) + Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); + } + + if (unsigned ObjCSelRedef + = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { + if (Context.ObjCSelRedefinitionType.isNull()) + Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); } } - if (unsigned ObjCIdRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) - Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef); - if (unsigned ObjCClassRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) - Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); - if (unsigned String = SpecialTypes[SPECIAL_TYPE_BLOCK_DESCRIPTOR]) - Context->setBlockDescriptorType(GetType(String)); - if (unsigned String - = SpecialTypes[SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) - Context->setBlockDescriptorExtendedType(GetType(String)); - if (unsigned ObjCSelRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) - Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); - if (unsigned String = SpecialTypes[SPECIAL_TYPE_NS_CONSTANT_STRING]) - Context->setNSConstantStringType(GetType(String)); - - if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED]) - Context->setInt128Installed(); - - if (unsigned AutoDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_DEDUCT]) - Context->AutoDeductTy = GetType(AutoDeduct); - if (unsigned AutoRRefDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_RREF_DEDUCT]) - Context->AutoRRefDeductTy = GetType(AutoRRefDeduct); - - ReadPragmaDiagnosticMappings(Context->getDiagnostics()); + + ReadPragmaDiagnosticMappings(Context.getDiagnostics()); // If there were any CUDA special declarations, deserialize them. if (!CUDASpecialDeclRefs.empty()) { assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!"); - Context->setcudaConfigureCallDecl( + Context.setcudaConfigureCallDecl( cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0]))); } } @@ -2833,7 +2676,7 @@ void ASTReader::InitializeContext(ASTContext &Ctx) { /// file. std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, FileManager &FileMgr, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { // Open the AST file. std::string ErrStr; llvm::OwningPtr<llvm::MemoryBuffer> Buffer; @@ -2917,181 +2760,349 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, /// /// \returns true if the listener deems the file unacceptable, false otherwise. bool ASTReader::ParseLanguageOptions( - const llvm::SmallVectorImpl<uint64_t> &Record) { + const SmallVectorImpl<uint64_t> &Record) { if (Listener) { LangOptions LangOpts; - - #define PARSE_LANGOPT(Option) \ - LangOpts.Option = Record[Idx]; \ - ++Idx - unsigned Idx = 0; - PARSE_LANGOPT(Trigraphs); - PARSE_LANGOPT(BCPLComment); - PARSE_LANGOPT(DollarIdents); - PARSE_LANGOPT(AsmPreprocessor); - PARSE_LANGOPT(GNUMode); - PARSE_LANGOPT(GNUKeywords); - PARSE_LANGOPT(ImplicitInt); - PARSE_LANGOPT(Digraphs); - PARSE_LANGOPT(HexFloats); - PARSE_LANGOPT(C99); - PARSE_LANGOPT(C1X); - PARSE_LANGOPT(Microsoft); - PARSE_LANGOPT(CPlusPlus); - PARSE_LANGOPT(CPlusPlus0x); - PARSE_LANGOPT(CXXOperatorNames); - PARSE_LANGOPT(ObjC1); - PARSE_LANGOPT(ObjC2); - PARSE_LANGOPT(ObjCNonFragileABI); - PARSE_LANGOPT(ObjCNonFragileABI2); - PARSE_LANGOPT(AppleKext); - PARSE_LANGOPT(ObjCDefaultSynthProperties); - PARSE_LANGOPT(ObjCInferRelatedResultType); - PARSE_LANGOPT(NoConstantCFStrings); - PARSE_LANGOPT(PascalStrings); - PARSE_LANGOPT(WritableStrings); - PARSE_LANGOPT(LaxVectorConversions); - PARSE_LANGOPT(AltiVec); - PARSE_LANGOPT(Exceptions); - PARSE_LANGOPT(ObjCExceptions); - PARSE_LANGOPT(CXXExceptions); - PARSE_LANGOPT(SjLjExceptions); - PARSE_LANGOPT(MSBitfields); - PARSE_LANGOPT(NeXTRuntime); - PARSE_LANGOPT(Freestanding); - PARSE_LANGOPT(NoBuiltin); - PARSE_LANGOPT(ThreadsafeStatics); - PARSE_LANGOPT(POSIXThreads); - PARSE_LANGOPT(Blocks); - PARSE_LANGOPT(EmitAllDecls); - PARSE_LANGOPT(MathErrno); - LangOpts.setSignedOverflowBehavior((LangOptions::SignedOverflowBehaviorTy) - Record[Idx++]); - PARSE_LANGOPT(HeinousExtensions); - PARSE_LANGOPT(Optimize); - PARSE_LANGOPT(OptimizeSize); - PARSE_LANGOPT(Static); - PARSE_LANGOPT(PICLevel); - PARSE_LANGOPT(GNUInline); - PARSE_LANGOPT(NoInline); - PARSE_LANGOPT(Deprecated); - PARSE_LANGOPT(AccessControl); - PARSE_LANGOPT(CharIsSigned); - PARSE_LANGOPT(ShortWChar); - PARSE_LANGOPT(ShortEnums); - LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]); - LangOpts.setVisibilityMode((Visibility)Record[Idx++]); - LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode) - Record[Idx++]); - PARSE_LANGOPT(InstantiationDepth); - PARSE_LANGOPT(OpenCL); - PARSE_LANGOPT(CUDA); - PARSE_LANGOPT(CatchUndefined); - PARSE_LANGOPT(DefaultFPContract); - PARSE_LANGOPT(ElideConstructors); - PARSE_LANGOPT(SpellChecking); - PARSE_LANGOPT(MRTD); - PARSE_LANGOPT(ObjCAutoRefCount); - #undef PARSE_LANGOPT - +#define LANGOPT(Name, Bits, Default, Description) \ + LangOpts.Name = Record[Idx++]; +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++])); +#include "clang/Basic/LangOptions.def" + return Listener->ReadLanguageOptions(LangOpts); } return false; } -void ASTReader::ReadPreprocessedEntities() { - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[I]; - if (!F.PreprocessorDetailCursor.getBitStreamReader()) - continue; +PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { + PreprocessedEntityID PPID = Index+1; + GlobalPreprocessedEntityMapType::iterator + I = GlobalPreprocessedEntityMap.find(Index); + assert(I != GlobalPreprocessedEntityMap.end() && + "Corrupted global preprocessed entity map"); + Module &M = *I->second; + unsigned LocalIndex = Index - M.BasePreprocessedEntityID; + const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; - SavedStreamPosition SavedPosition(F.PreprocessorDetailCursor); - F.PreprocessorDetailCursor.JumpToBit(F.PreprocessorDetailStartOffset); - while (LoadPreprocessedEntity(F)) { } + SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); + M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); + + unsigned Code = M.PreprocessorDetailCursor.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + return 0; + + case llvm::bitc::ENTER_SUBBLOCK: + Error("unexpected subblock record in preprocessor detail block"); + return 0; + + case llvm::bitc::DEFINE_ABBREV: + Error("unexpected abbrevation record in preprocessor detail block"); + return 0; + + default: + break; } -} -PreprocessedEntity *ASTReader::ReadPreprocessedEntityAtOffset(uint64_t Offset) { - PerFileData *F = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Offset < Chain[I]->SizeInBits) { - F = Chain[I]; - break; + if (!PP.getPreprocessingRecord()) { + Error("no preprocessing record"); + return 0; + } + + // Read the record. + SourceRange Range(ReadSourceLocation(M, PPOffs.Begin), + ReadSourceLocation(M, PPOffs.End)); + PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + RecordData Record; + PreprocessorDetailRecordTypes RecType = + (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord( + Code, Record, BlobStart, BlobLen); + switch (RecType) { + case PPD_MACRO_EXPANSION: { + bool isBuiltin = Record[0]; + IdentifierInfo *Name = 0; + MacroDefinition *Def = 0; + if (isBuiltin) + Name = getLocalIdentifier(M, Record[1]); + else { + PreprocessedEntityID + GlobalID = getGlobalPreprocessedEntityID(M, Record[1]); + Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1)); } + + MacroExpansion *ME; + if (isBuiltin) + ME = new (PPRec) MacroExpansion(Name, Range); + else + ME = new (PPRec) MacroExpansion(Def, Range); + + return ME; + } + + case PPD_MACRO_DEFINITION: { + // Decode the identifier info and then check again; if the macro is + // still defined and associated with the identifier, + IdentifierInfo *II = getLocalIdentifier(M, Record[0]); + MacroDefinition *MD + = new (PPRec) MacroDefinition(II, Range); + + if (DeserializationListener) + DeserializationListener->MacroDefinitionRead(PPID, MD); + + return MD; + } + + case PPD_INCLUSION_DIRECTIVE: { + const char *FullFileNameStart = BlobStart + Record[0]; + const FileEntry *File + = PP.getFileManager().getFile(StringRef(FullFileNameStart, + BlobLen - Record[0])); - Offset -= Chain[I]->SizeInBits; + // FIXME: Stable encoding + InclusionDirective::InclusionKind Kind + = static_cast<InclusionDirective::InclusionKind>(Record[2]); + InclusionDirective *ID + = new (PPRec) InclusionDirective(PPRec, Kind, + StringRef(BlobStart, Record[0]), + Record[1], + File, + Range); + return ID; + } } - if (!F) { - Error("Malformed preprocessed entity offset"); - return 0; + Error("invalid offset in preprocessor detail block"); + return 0; +} + +/// \brief \arg SLocMapI points at a chunk of a module that contains no +/// preprocessed entities or the entities it contains are not the ones we are +/// looking for. Find the next module that contains entities and return the ID +/// of the first entry. +PreprocessedEntityID ASTReader::findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const { + ++SLocMapI; + for (GlobalSLocOffsetMapType::const_iterator + EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { + Module &M = *SLocMapI->second; + if (M.NumPreprocessedEntities) + return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID); } - // Keep track of where we are in the stream, then jump back there - // after reading this entity. - SavedStreamPosition SavedPosition(F->PreprocessorDetailCursor); - F->PreprocessorDetailCursor.JumpToBit(Offset); - return LoadPreprocessedEntity(*F); + return getTotalNumPreprocessedEntities(); } -HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { - HeaderFileInfoTrait Trait(FE->getName()); - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[I]; - HeaderFileInfoLookupTable *Table - = static_cast<HeaderFileInfoLookupTable *>(F.HeaderFileInfoTable); - if (!Table) - continue; +namespace { + +template <unsigned PPEntityOffset::*PPLoc> +struct PPEntityComp { + const ASTReader &Reader; + Module &M; + + PPEntityComp(const ASTReader &Reader, Module &M) : Reader(Reader), M(M) { } + + bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { + SourceLocation LHS = getLoc(L); + SourceLocation RHS = getLoc(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(const PPEntityOffset &L, SourceLocation RHS) const { + SourceLocation LHS = getLoc(L); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, const PPEntityOffset &R) const { + SourceLocation RHS = getLoc(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLoc(const PPEntityOffset &PPE) const { + return Reader.ReadSourceLocation(M, PPE.*PPLoc); + } +}; + +} + +/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. +PreprocessedEntityID +ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { + if (SourceMgr.isLocalSourceLocation(BLoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + BLoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + Module &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + + size_t Count = M.NumPreprocessedEntities; + size_t Half; + pp_iterator First = pp_begin; + pp_iterator PPI; + + // Do a binary search manually instead of using std::lower_bound because + // The end locations of entities may be unordered (when a macro expansion + // is inside another macro argument), but for this case it is not important + // whether we get the first macro expansion or its containing macro. + while (Count > 0) { + Half = Count/2; + PPI = First; + std::advance(PPI, Half); + if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End), + BLoc)){ + First = PPI; + ++First; + Count = Count - Half - 1; + } else + Count = Half; + } + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return getGlobalPreprocessedEntityID(M, + M.BasePreprocessedEntityID + (PPI - pp_begin)); +} + +/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. +PreprocessedEntityID +ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { + if (SourceMgr.isLocalSourceLocation(ELoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + ELoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + Module &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + pp_iterator PPI = + std::upper_bound(pp_begin, pp_end, ELoc, + PPEntityComp<&PPEntityOffset::Begin>(*this, M)); + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return getGlobalPreprocessedEntityID(M, + M.BasePreprocessedEntityID + (PPI - pp_begin)); +} + +/// \brief Returns a pair of [Begin, End) indices of preallocated +/// preprocessed entities that \arg Range encompasses. +std::pair<unsigned, unsigned> + ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { + if (Range.isInvalid()) + return std::make_pair(0,0); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin()); + PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd()); + return std::make_pair(BeginID, EndID); +} + +namespace { + /// \brief Visitor used to search for information about a header file. + class HeaderFileInfoVisitor { + ASTReader &Reader; + const FileEntry *FE; - // Look in the on-disk hash table for an entry for this file name. - HeaderFileInfoLookupTable::iterator Pos = Table->find(FE->getName(), - &Trait); - if (Pos == Table->end()) - continue; + llvm::Optional<HeaderFileInfo> HFI; + + public: + HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE) + : Reader(Reader), FE(FE) { } + + static bool visit(Module &M, void *UserData) { + HeaderFileInfoVisitor *This + = static_cast<HeaderFileInfoVisitor *>(UserData); + + HeaderFileInfoTrait Trait(This->Reader, M, + &This->Reader.getPreprocessor().getHeaderSearchInfo(), + M.HeaderFileFrameworkStrings, + This->FE->getName()); + + HeaderFileInfoLookupTable *Table + = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable); + if (!Table) + return false; - HeaderFileInfo HFI = *Pos; - if (Listener) - Listener->ReadHeaderFileInfo(HFI, FE->getUID()); + // Look in the on-disk hash table for an entry for this file name. + HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(), + &Trait); + if (Pos == Table->end()) + return false; + + This->HFI = *Pos; + return true; + } + + llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } + }; +} - return HFI; +HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { + HeaderFileInfoVisitor Visitor(*this, FE); + ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); + if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) { + if (Listener) + Listener->ReadHeaderFileInfo(*HFI, FE->getUID()); + return *HFI; } return HeaderFileInfo(); } -void ASTReader::ReadPragmaDiagnosticMappings(Diagnostic &Diag) { - unsigned Idx = 0; - while (Idx < PragmaDiagMappings.size()) { - SourceLocation - Loc = SourceLocation::getFromRawEncoding(PragmaDiagMappings[Idx++]); - while (1) { - assert(Idx < PragmaDiagMappings.size() && - "Invalid data, didn't find '-1' marking end of diag/map pairs"); - if (Idx >= PragmaDiagMappings.size()) - break; // Something is messed up but at least avoid infinite loop in - // release build. - unsigned DiagID = PragmaDiagMappings[Idx++]; - if (DiagID == (unsigned)-1) - break; // no more diag/map pairs for this location. - diag::Mapping Map = (diag::Mapping)PragmaDiagMappings[Idx++]; - Diag.setDiagnosticMapping(DiagID, Map, Loc); +void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { + for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { + Module &F = *(*I); + unsigned Idx = 0; + while (Idx < F.PragmaDiagMappings.size()) { + SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); + while (1) { + assert(Idx < F.PragmaDiagMappings.size() && + "Invalid data, didn't find '-1' marking end of diag/map pairs"); + if (Idx >= F.PragmaDiagMappings.size()) { + break; // Something is messed up but at least avoid infinite loop in + // release build. + } + unsigned DiagID = F.PragmaDiagMappings[Idx++]; + if (DiagID == (unsigned)-1) { + break; // no more diag/map pairs for this location. + } + diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++]; + // The user bit gets set by WritePragmaDiagnosticMappings. + Diag.setDiagnosticMapping(DiagID, Map, Loc); + } } } } /// \brief Get the correct cursor and offset for loading a type. ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { - PerFileData *F = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - F = Chain[N - I - 1]; - if (Index < F->LocalNumTypes) - break; - Index -= F->LocalNumTypes; - } - assert(F && F->LocalNumTypes > Index && "Broken chain"); - return RecordLocation(F, F->TypeOffsets[Index]); + GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index); + assert(I != GlobalTypeMap.end() && "Corrupted global type map"); + Module *M = I->second; + return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]); } /// \brief Read and return the type with the given index.. @@ -3100,7 +3111,7 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { /// routine actually reads the record corresponding to the type at the given /// location. It is a helper routine for GetType, which deals with reading type /// IDs. -QualType ASTReader::ReadTypeRecord(unsigned Index) { +QualType ASTReader::readTypeRecord(unsigned Index) { RecordLocation Loc = TypeCursorForIndex(Index); llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; @@ -3113,6 +3124,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { // Note that we are loading a type record. Deserializing AType(this); + unsigned Idx = 0; DeclsCursor.JumpToBit(Loc.Offset); RecordData Record; unsigned Code = DeclsCursor.ReadCode(); @@ -3122,9 +3134,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of extended qualifier type"); return QualType(); } - QualType Base = GetType(Record[0]); - Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); - return Context->getQualifiedType(Base, Quals); + QualType Base = readType(*Loc.F, Record, Idx); + Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]); + return Context.getQualifiedType(Base, Quals); } case TYPE_COMPLEX: { @@ -3132,8 +3144,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of complex type"); return QualType(); } - QualType ElemType = GetType(Record[0]); - return Context->getComplexType(ElemType); + QualType ElemType = readType(*Loc.F, Record, Idx); + return Context.getComplexType(ElemType); } case TYPE_POINTER: { @@ -3141,8 +3153,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of pointer type"); return QualType(); } - QualType PointeeType = GetType(Record[0]); - return Context->getPointerType(PointeeType); + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getPointerType(PointeeType); } case TYPE_BLOCK_POINTER: { @@ -3150,8 +3162,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of block pointer type"); return QualType(); } - QualType PointeeType = GetType(Record[0]); - return Context->getBlockPointerType(PointeeType); + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getBlockPointerType(PointeeType); } case TYPE_LVALUE_REFERENCE: { @@ -3159,8 +3171,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of lvalue reference type"); return QualType(); } - QualType PointeeType = GetType(Record[0]); - return Context->getLValueReferenceType(PointeeType, Record[1]); + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getLValueReferenceType(PointeeType, Record[1]); } case TYPE_RVALUE_REFERENCE: { @@ -3168,8 +3180,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of rvalue reference type"); return QualType(); } - QualType PointeeType = GetType(Record[0]); - return Context->getRValueReferenceType(PointeeType); + QualType PointeeType = readType(*Loc.F, Record, Idx); + return Context.getRValueReferenceType(PointeeType); } case TYPE_MEMBER_POINTER: { @@ -3177,38 +3189,38 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("Incorrect encoding of member pointer type"); return QualType(); } - QualType PointeeType = GetType(Record[0]); - QualType ClassType = GetType(Record[1]); + QualType PointeeType = readType(*Loc.F, Record, Idx); + QualType ClassType = readType(*Loc.F, Record, Idx); if (PointeeType.isNull() || ClassType.isNull()) return QualType(); - return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr()); + return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); } case TYPE_CONSTANT_ARRAY: { - QualType ElementType = GetType(Record[0]); + QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; unsigned Idx = 3; llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayType(ElementType, Size, + return Context.getConstantArrayType(ElementType, Size, ASM, IndexTypeQuals); } case TYPE_INCOMPLETE_ARRAY: { - QualType ElementType = GetType(Record[0]); + QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; - return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); + return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); } case TYPE_VARIABLE_ARRAY: { - QualType ElementType = GetType(Record[0]); + QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; unsigned IndexTypeQuals = Record[2]; SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]); SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]); - return Context->getVariableArrayType(ElementType, ReadExpr(*Loc.F), + return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F), ASM, IndexTypeQuals, SourceRange(LBLoc, RBLoc)); } @@ -3219,10 +3231,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { return QualType(); } - QualType ElementType = GetType(Record[0]); + QualType ElementType = readType(*Loc.F, Record, Idx); unsigned NumElements = Record[1]; unsigned VecKind = Record[2]; - return Context->getVectorType(ElementType, NumElements, + return Context.getVectorType(ElementType, NumElements, (VectorType::VectorKind)VecKind); } @@ -3232,9 +3244,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { return QualType(); } - QualType ElementType = GetType(Record[0]); + QualType ElementType = readType(*Loc.F, Record, Idx); unsigned NumElements = Record[1]; - return Context->getExtVectorType(ElementType, NumElements); + return Context.getExtVectorType(ElementType, NumElements); } case TYPE_FUNCTION_NO_PROTO: { @@ -3242,14 +3254,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of no-proto function type"); return QualType(); } - QualType ResultType = GetType(Record[0]); + QualType ResultType = readType(*Loc.F, Record, Idx); FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4], Record[5]); - return Context->getFunctionNoProtoType(ResultType, Info); + return Context.getFunctionNoProtoType(ResultType, Info); } case TYPE_FUNCTION_PROTO: { - QualType ResultType = GetType(Record[0]); + QualType ResultType = readType(*Loc.F, Record, Idx); FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], @@ -3260,9 +3272,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { unsigned Idx = 6; unsigned NumParams = Record[Idx++]; - llvm::SmallVector<QualType, 16> ParamTypes; + SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) - ParamTypes.push_back(GetType(Record[Idx++])); + ParamTypes.push_back(readType(*Loc.F, Record, Idx)); EPI.Variadic = Record[Idx++]; EPI.TypeQuals = Record[Idx++]; @@ -3272,65 +3284,70 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { EPI.ExceptionSpecType = EST; if (EST == EST_Dynamic) { EPI.NumExceptions = Record[Idx++]; - llvm::SmallVector<QualType, 2> Exceptions; + SmallVector<QualType, 2> Exceptions; for (unsigned I = 0; I != EPI.NumExceptions; ++I) - Exceptions.push_back(GetType(Record[Idx++])); + Exceptions.push_back(readType(*Loc.F, Record, Idx)); EPI.Exceptions = Exceptions.data(); } else if (EST == EST_ComputedNoexcept) { EPI.NoexceptExpr = ReadExpr(*Loc.F); } - return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, + return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, EPI); } - case TYPE_UNRESOLVED_USING: - return Context->getTypeDeclType( - cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0]))); - + case TYPE_UNRESOLVED_USING: { + unsigned Idx = 0; + return Context.getTypeDeclType( + ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx)); + } + case TYPE_TYPEDEF: { if (Record.size() != 2) { Error("incorrect encoding of typedef type"); return QualType(); } - TypedefNameDecl *Decl = cast<TypedefNameDecl>(GetDecl(Record[0])); - QualType Canonical = GetType(Record[1]); + unsigned Idx = 0; + TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx); + QualType Canonical = readType(*Loc.F, Record, Idx); if (!Canonical.isNull()) - Canonical = Context->getCanonicalType(Canonical); - return Context->getTypedefType(Decl, Canonical); + Canonical = Context.getCanonicalType(Canonical); + return Context.getTypedefType(Decl, Canonical); } case TYPE_TYPEOF_EXPR: - return Context->getTypeOfExprType(ReadExpr(*Loc.F)); + return Context.getTypeOfExprType(ReadExpr(*Loc.F)); case TYPE_TYPEOF: { if (Record.size() != 1) { Error("incorrect encoding of typeof(type) in AST file"); return QualType(); } - QualType UnderlyingType = GetType(Record[0]); - return Context->getTypeOfType(UnderlyingType); + QualType UnderlyingType = readType(*Loc.F, Record, Idx); + return Context.getTypeOfType(UnderlyingType); } case TYPE_DECLTYPE: - return Context->getDecltypeType(ReadExpr(*Loc.F)); + return Context.getDecltypeType(ReadExpr(*Loc.F)); case TYPE_UNARY_TRANSFORM: { - QualType BaseType = GetType(Record[0]); - QualType UnderlyingType = GetType(Record[1]); + QualType BaseType = readType(*Loc.F, Record, Idx); + QualType UnderlyingType = readType(*Loc.F, Record, Idx); UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; - return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind); + return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); } case TYPE_AUTO: - return Context->getAutoType(GetType(Record[0])); + return Context.getAutoType(readType(*Loc.F, Record, Idx)); case TYPE_RECORD: { if (Record.size() != 2) { Error("incorrect encoding of record type"); return QualType(); } - bool IsDependent = Record[0]; - QualType T = Context->getRecordType(cast<RecordDecl>(GetDecl(Record[1]))); + unsigned Idx = 0; + bool IsDependent = Record[Idx++]; + QualType T + = Context.getRecordType(ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx)); const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); return T; } @@ -3340,8 +3357,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of enum type"); return QualType(); } - bool IsDependent = Record[0]; - QualType T = Context->getEnumType(cast<EnumDecl>(GetDecl(Record[1]))); + unsigned Idx = 0; + bool IsDependent = Record[Idx++]; + QualType T + = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx)); const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); return T; } @@ -3351,10 +3370,10 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of attributed type"); return QualType(); } - QualType modifiedType = GetType(Record[0]); - QualType equivalentType = GetType(Record[1]); + QualType modifiedType = readType(*Loc.F, Record, Idx); + QualType equivalentType = readType(*Loc.F, Record, Idx); AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]); - return Context->getAttributedType(kind, modifiedType, equivalentType); + return Context.getAttributedType(kind, modifiedType, equivalentType); } case TYPE_PAREN: { @@ -3362,8 +3381,8 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of paren type"); return QualType(); } - QualType InnerType = GetType(Record[0]); - return Context->getParenType(InnerType); + QualType InnerType = readType(*Loc.F, Record, Idx); + return Context.getParenType(InnerType); } case TYPE_PACK_EXPANSION: { @@ -3371,70 +3390,71 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of pack expansion type"); return QualType(); } - QualType Pattern = GetType(Record[0]); + QualType Pattern = readType(*Loc.F, Record, Idx); if (Pattern.isNull()) return QualType(); llvm::Optional<unsigned> NumExpansions; if (Record[1]) NumExpansions = Record[1] - 1; - return Context->getPackExpansionType(Pattern, NumExpansions); + return Context.getPackExpansionType(Pattern, NumExpansions); } case TYPE_ELABORATED: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - QualType NamedType = GetType(Record[Idx++]); - return Context->getElaboratedType(Keyword, NNS, NamedType); + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + QualType NamedType = readType(*Loc.F, Record, Idx); + return Context.getElaboratedType(Keyword, NNS, NamedType); } case TYPE_OBJC_INTERFACE: { unsigned Idx = 0; - ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); - return Context->getObjCInterfaceType(ItfD); + ObjCInterfaceDecl *ItfD + = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx); + return Context.getObjCInterfaceType(ItfD); } case TYPE_OBJC_OBJECT: { unsigned Idx = 0; - QualType Base = GetType(Record[Idx++]); + QualType Base = readType(*Loc.F, Record, Idx); unsigned NumProtos = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; + SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCObjectType(Base, Protos.data(), NumProtos); + Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); + return Context.getObjCObjectType(Base, Protos.data(), NumProtos); } case TYPE_OBJC_OBJECT_POINTER: { unsigned Idx = 0; - QualType Pointee = GetType(Record[Idx++]); - return Context->getObjCObjectPointerType(Pointee); + QualType Pointee = readType(*Loc.F, Record, Idx); + return Context.getObjCObjectPointerType(Pointee); } case TYPE_SUBST_TEMPLATE_TYPE_PARM: { unsigned Idx = 0; - QualType Parm = GetType(Record[Idx++]); - QualType Replacement = GetType(Record[Idx++]); + QualType Parm = readType(*Loc.F, Record, Idx); + QualType Replacement = readType(*Loc.F, Record, Idx); return - Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), Replacement); } case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: { unsigned Idx = 0; - QualType Parm = GetType(Record[Idx++]); + QualType Parm = readType(*Loc.F, Record, Idx); TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx); - return Context->getSubstTemplateTypeParmPackType( + return Context.getSubstTemplateTypeParmPackType( cast<TemplateTypeParmType>(Parm), ArgPack); } case TYPE_INJECTED_CLASS_NAME: { - CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0])); - QualType TST = GetType(Record[1]); // probably derivable + CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx); + QualType TST = readType(*Loc.F, Record, Idx); // probably derivable // FIXME: ASTContext::getInjectedClassNameType is not currently suitable // for AST reading, too much interdependencies. return - QualType(new (*Context, TypeAlignment) InjectedClassNameType(D, TST), 0); + QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0); } case TYPE_TEMPLATE_TYPE_PARM: { @@ -3442,33 +3462,33 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { unsigned Depth = Record[Idx++]; unsigned Index = Record[Idx++]; bool Pack = Record[Idx++]; - TemplateTypeParmDecl *D = - cast_or_null<TemplateTypeParmDecl>(GetDecl(Record[Idx++])); - return Context->getTemplateTypeParmType(Depth, Index, Pack, D); + TemplateTypeParmDecl *D + = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx); + return Context.getTemplateTypeParmType(Depth, Index, Pack, D); } case TYPE_DEPENDENT_NAME: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx); - QualType Canon = GetType(Record[Idx++]); + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); + QualType Canon = readType(*Loc.F, Record, Idx); if (!Canon.isNull()) - Canon = Context->getCanonicalType(Canon); - return Context->getDependentNameType(Keyword, NNS, Name, Canon); + Canon = Context.getCanonicalType(Canon); + return Context.getDependentNameType(Keyword, NNS, Name, Canon); } case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx); + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); + const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); unsigned NumArgs = Record[Idx++]; - llvm::SmallVector<TemplateArgument, 8> Args; + SmallVector<TemplateArgument, 8> Args; Args.reserve(NumArgs); while (NumArgs--) Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx)); - return Context->getDependentTemplateSpecializationType(Keyword, NNS, Name, + return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, Args.size(), Args.data()); } @@ -3476,7 +3496,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { unsigned Idx = 0; // ArrayType - QualType ElementType = GetType(Record[Idx++]); + QualType ElementType = readType(*Loc.F, Record, Idx); ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[Idx++]; unsigned IndexTypeQuals = Record[Idx++]; @@ -3485,7 +3505,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Expr *NumElts = ReadExpr(*Loc.F); SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx); - return Context->getDependentSizedArrayType(ElementType, NumElts, ASM, + return Context.getDependentSizedArrayType(ElementType, NumElts, ASM, IndexTypeQuals, Brackets); } @@ -3493,19 +3513,28 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { unsigned Idx = 0; bool IsDependent = Record[Idx++]; TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); - llvm::SmallVector<TemplateArgument, 8> Args; + SmallVector<TemplateArgument, 8> Args; ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); - QualType Underlying = GetType(Record[Idx++]); + QualType Underlying = readType(*Loc.F, Record, Idx); QualType T; if (Underlying.isNull()) - T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(), + T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(), Args.size()); else - T = Context->getTemplateSpecializationType(Name, Args.data(), + T = Context.getTemplateSpecializationType(Name, Args.data(), Args.size(), Underlying); const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); return T; } + + case TYPE_ATOMIC: { + if (Record.size() != 1) { + Error("Incorrect encoding of atomic type"); + return QualType(); + } + QualType ValueType = readType(*Loc.F, Record, Idx); + return Context.getAtomicType(ValueType); + } } // Suppress a GCC warning return QualType(); @@ -3513,7 +3542,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> { ASTReader &Reader; - ASTReader::PerFileData &F; + Module &F; llvm::BitstreamCursor &DeclsCursor; const ASTReader::RecordData &Record; unsigned &Idx; @@ -3523,8 +3552,13 @@ class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> { return Reader.ReadSourceLocation(F, R, I); } + template<typename T> + T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) { + return Reader.ReadDeclAs<T>(F, Record, Idx); + } + public: - TypeLocReader(ASTReader &Reader, ASTReader::PerFileData &F, + TypeLocReader(ASTReader &Reader, Module &F, const ASTReader::RecordData &Record, unsigned &Idx) : Reader(Reader), F(F), DeclsCursor(F.DeclsCursor), Record(Record), Idx(Idx) { } @@ -3608,7 +3642,7 @@ void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); TL.setTrailingReturn(Record[Idx++]); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx)); } } void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { @@ -3735,15 +3769,20 @@ void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); +} -TypeSourceInfo *ASTReader::GetTypeSourceInfo(PerFileData &F, +TypeSourceInfo *ASTReader::GetTypeSourceInfo(Module &F, const RecordData &Record, unsigned &Idx) { - QualType InfoTy = GetType(Record[Idx++]); + QualType InfoTy = readType(F, Record, Idx); if (InfoTy.isNull()) return 0; - TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); + TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(*this, F, Record, Idx); for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); @@ -3758,41 +3797,47 @@ QualType ASTReader::GetType(TypeID ID) { QualType T; switch ((PredefinedTypeIDs)Index) { case PREDEF_TYPE_NULL_ID: return QualType(); - case PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break; - case PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break; + case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; + case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; case PREDEF_TYPE_CHAR_U_ID: case PREDEF_TYPE_CHAR_S_ID: // FIXME: Check that the signedness of CharTy is correct! - T = Context->CharTy; + T = Context.CharTy; break; - case PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break; - case PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break; - case PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break; - case PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break; - case PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break; - case PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break; - case PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break; - case PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break; - case PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break; - case PREDEF_TYPE_INT_ID: T = Context->IntTy; break; - case PREDEF_TYPE_LONG_ID: T = Context->LongTy; break; - case PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break; - case PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break; - case PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break; - case PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break; - case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break; - case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break; - case PREDEF_TYPE_BOUND_MEMBER: T = Context->BoundMemberTy; break; - case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break; - case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break; - case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break; - case PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break; - case PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break; - case PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break; - case PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break; - case PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break; + case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; + case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; + case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; + case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; + case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; + case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; + case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; + case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; + case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; + case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; + case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; + case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; + case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; + case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; + case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; + case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; + case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; + case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; + case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; + case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; + case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; + case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; + case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; + case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; + case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; + case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; + case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; + case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; + + case PREDEF_TYPE_AUTO_RREF_DEDUCT: + T = Context.getAutoRRefDeductType(); + break; } assert(!T.isNull() && "Unknown predefined type"); @@ -3802,12 +3847,11 @@ QualType ASTReader::GetType(TypeID ID) { Index -= NUM_PREDEF_TYPE_IDS; assert(Index < TypesLoaded.size() && "Type index out-of-range"); if (TypesLoaded[Index].isNull()) { - TypesLoaded[Index] = ReadTypeRecord(Index); + TypesLoaded[Index] = readTypeRecord(Index); if (TypesLoaded[Index].isNull()) return QualType(); TypesLoaded[Index]->setFromAST(); - TypeIdxs[TypesLoaded[Index]] = TypeIdx::fromTypeID(ID); if (DeserializationListener) DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID), TypesLoaded[Index]); @@ -3816,37 +3860,28 @@ QualType ASTReader::GetType(TypeID ID) { return TypesLoaded[Index].withFastQualifiers(FastQuals); } -TypeID ASTReader::GetTypeID(QualType T) const { - return MakeTypeID(T, - std::bind1st(std::mem_fun(&ASTReader::GetTypeIdx), this)); +QualType ASTReader::getLocalType(Module &F, unsigned LocalID) { + return GetType(getGlobalTypeID(F, LocalID)); } -TypeIdx ASTReader::GetTypeIdx(QualType T) const { - if (T.isNull()) - return TypeIdx(); - assert(!T.getLocalFastQualifiers()); - - TypeIdxMap::const_iterator I = TypeIdxs.find(T); - // GetTypeIdx is mostly used for computing the hash of DeclarationNames and - // comparing keys of ASTDeclContextNameLookupTable. - // If the type didn't come from the AST file use a specially marked index - // so that any hash/key comparison fail since no such index is stored - // in a AST file. - if (I == TypeIdxs.end()) - return TypeIdx(-1); - return I->second; -} +serialization::TypeID +ASTReader::getGlobalTypeID(Module &F, unsigned LocalID) const { + unsigned FastQuals = LocalID & Qualifiers::FastMask; + unsigned LocalIndex = LocalID >> Qualifiers::FastWidth; + + if (LocalIndex < NUM_PREDEF_TYPE_IDS) + return LocalID; -unsigned ASTReader::getTotalNumCXXBaseSpecifiers() const { - unsigned Result = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) - Result += Chain[I]->LocalNumCXXBaseSpecifiers; + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); + assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); - return Result; + unsigned GlobalIndex = LocalIndex + I->second; + return (GlobalIndex << Qualifiers::FastWidth) | FastQuals; } TemplateArgumentLocInfo -ASTReader::GetTemplateArgumentLocInfo(PerFileData &F, +ASTReader::GetTemplateArgumentLocInfo(Module &F, TemplateArgument::ArgKind Kind, const RecordData &Record, unsigned &Index) { @@ -3881,7 +3916,7 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F, } TemplateArgumentLoc -ASTReader::ReadTemplateArgumentLoc(PerFileData &F, +ASTReader::ReadTemplateArgumentLoc(Module &F, const RecordData &Record, unsigned &Index) { TemplateArgument Arg = ReadTemplateArgument(F, Record, Index); @@ -3897,47 +3932,20 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } -uint64_t -ASTReader::GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID) { - if (ID == 0) +uint64_t ASTReader::readCXXBaseSpecifiers(Module &M, const RecordData &Record, + unsigned &Idx){ + if (Idx >= Record.size()) return 0; - --ID; - uint64_t Offset = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[N - I - 1]; - - if (ID < F.LocalNumCXXBaseSpecifiers) - return Offset + F.CXXBaseSpecifiersOffsets[ID]; - - ID -= F.LocalNumCXXBaseSpecifiers; - Offset += F.SizeInBits; - } - - assert(false && "CXXBaseSpecifiers not found"); - return 0; + unsigned LocalID = Record[Idx++]; + return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]); } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { - // Figure out which AST file contains this offset. - PerFileData *F = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Offset < Chain[N - I - 1]->SizeInBits) { - F = Chain[N - I - 1]; - break; - } - - Offset -= Chain[N - I - 1]->SizeInBits; - } - - if (!F) { - Error("Malformed AST file: C++ base specifiers at impossible offset"); - return 0; - } - - llvm::BitstreamCursor &Cursor = F->DeclsCursor; + RecordLocation Loc = getLocalBitOffset(Offset); + llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); - Cursor.JumpToBit(Offset); + Cursor.JumpToBit(Loc.Offset); ReadingKindTracker ReadingKind(Read_Decl, *this); RecordData Record; unsigned Code = Cursor.ReadCode(); @@ -3949,35 +3957,72 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { unsigned Idx = 0; unsigned NumBases = Record[Idx++]; - void *Mem = Context->Allocate(sizeof(CXXBaseSpecifier) * NumBases); + void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; for (unsigned I = 0; I != NumBases; ++I) - Bases[I] = ReadCXXBaseSpecifier(*F, Record, Idx); + Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx); return Bases; } -TranslationUnitDecl *ASTReader::GetTranslationUnitDecl() { - if (!DeclsLoaded[0]) { - ReadDeclRecord(0, 1); - if (DeserializationListener) - DeserializationListener->DeclRead(1, DeclsLoaded[0]); - } +serialization::DeclID +ASTReader::getGlobalDeclID(Module &F, unsigned LocalID) const { + if (LocalID < NUM_PREDEF_DECL_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS); + assert(I != F.DeclRemap.end() && "Invalid index into decl index remap"); + + return LocalID + I->second; +} - return cast<TranslationUnitDecl>(DeclsLoaded[0]); +bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, + Module &M) const { + GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + return &M == I->second; } Decl *ASTReader::GetDecl(DeclID ID) { - if (ID == 0) + if (ID < NUM_PREDEF_DECL_IDS) { + switch ((PredefinedDeclIDs)ID) { + case PREDEF_DECL_NULL_ID: + return 0; + + case PREDEF_DECL_TRANSLATION_UNIT_ID: + return Context.getTranslationUnitDecl(); + + case PREDEF_DECL_OBJC_ID_ID: + return Context.getObjCIdDecl(); + + case PREDEF_DECL_OBJC_SEL_ID: + return Context.getObjCSelDecl(); + + case PREDEF_DECL_OBJC_CLASS_ID: + return Context.getObjCClassDecl(); + + case PREDEF_DECL_INT_128_ID: + return Context.getInt128Decl(); + + case PREDEF_DECL_UNSIGNED_INT_128_ID: + return Context.getUInt128Decl(); + + case PREDEF_DECL_OBJC_INSTANCETYPE_ID: + return Context.getObjCInstanceTypeDecl(); + } + return 0; + } + + unsigned Index = ID - NUM_PREDEF_DECL_IDS; - if (ID > DeclsLoaded.size()) { + if (Index > DeclsLoaded.size()) { Error("declaration ID out-of-range for AST file"); return 0; } - - unsigned Index = ID - 1; - if (!DeclsLoaded[Index]) { - ReadDeclRecord(Index, ID); + +if (!DeclsLoaded[Index]) { + ReadDeclRecord(ID); if (DeserializationListener) DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); } @@ -3985,6 +4030,17 @@ Decl *ASTReader::GetDecl(DeclID ID) { return DeclsLoaded[Index]; } +serialization::DeclID ASTReader::ReadDeclID(Module &F, + const RecordData &Record, + unsigned &Idx) { + if (Idx >= Record.size()) { + Error("Corrupted AST file"); + return 0; + } + + return getGlobalDeclID(F, Record[Idx++]); +} + /// \brief Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external @@ -3995,49 +4051,137 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { ClearSwitchCaseIDs(); // Offset here is a global offset across the entire chain. - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[N - I - 1]; - if (Offset < F.SizeInBits) { - // Since we know that this statement is part of a decl, make sure to use - // the decl cursor to read it. - F.DeclsCursor.JumpToBit(Offset); - return ReadStmtFromStream(F); - } - Offset -= F.SizeInBits; - } - llvm_unreachable("Broken chain"); + RecordLocation Loc = getLocalBitOffset(Offset); + Loc.F->DeclsCursor.JumpToBit(Loc.Offset); + return ReadStmtFromStream(*Loc.F); } -ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - llvm::SmallVectorImpl<Decl*> &Decls) { - // There might be lexical decls in multiple parts of the chain, for the TU - // at least. - // DeclContextOffsets might reallocate as we load additional decls below, - // so make a copy of the vector. - DeclContextInfos Infos = DeclContextOffsets[DC]; - for (DeclContextInfos::iterator I = Infos.begin(), E = Infos.end(); - I != E; ++I) { - // IDs can be 0 if this context doesn't contain declarations. - if (!I->LexicalDecls) - continue; +namespace { + class FindExternalLexicalDeclsVisitor { + ASTReader &Reader; + const DeclContext *DC; + bool (*isKindWeWant)(Decl::Kind); + + SmallVectorImpl<Decl*> &Decls; + bool PredefsVisited[NUM_PREDEF_DECL_IDS]; - // Load all of the declaration IDs - for (const KindDeclIDPair *ID = I->LexicalDecls, - *IDE = ID + I->NumLexicalDecls; ID != IDE; ++ID) { - if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first)) - continue; + public: + FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls) + : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) + { + for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) + PredefsVisited[I] = false; + } - Decl *D = GetDecl(ID->second); - assert(D && "Null decl in lexical decls"); - Decls.push_back(D); + static bool visit(Module &M, bool Preorder, void *UserData) { + if (Preorder) + return false; + + FindExternalLexicalDeclsVisitor *This + = static_cast<FindExternalLexicalDeclsVisitor *>(UserData); + + Module::DeclContextInfosMap::iterator Info + = M.DeclContextInfos.find(This->DC); + if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) + return false; + + // Load all of the declaration IDs + for (const KindDeclIDPair *ID = Info->second.LexicalDecls, + *IDE = ID + Info->second.NumLexicalDecls; + ID != IDE; ++ID) { + if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) + continue; + + // Don't add predefined declarations to the lexical context more + // than once. + if (ID->second < NUM_PREDEF_DECL_IDS) { + if (This->PredefsVisited[ID->second]) + continue; + + This->PredefsVisited[ID->second] = true; + } + + if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) { + if (!This->DC->isDeclInLexicalTraversal(D)) + This->Decls.push_back(D); + } + } + + return false; } - } + }; +} +ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls) { + // There might be lexical decls in multiple modules, for the TU at + // least. Walk all of the modules in the order they were loaded. + FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); + ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor); ++NumLexicalDeclContextsRead; return ELR_Success; } +namespace { + /// \brief Module visitor used to perform name lookup into a + /// declaration context. + class DeclContextNameLookupVisitor { + ASTReader &Reader; + const DeclContext *DC; + DeclarationName Name; + SmallVectorImpl<NamedDecl *> &Decls; + + public: + DeclContextNameLookupVisitor(ASTReader &Reader, + const DeclContext *DC, DeclarationName Name, + SmallVectorImpl<NamedDecl *> &Decls) + : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { } + + static bool visit(Module &M, void *UserData) { + DeclContextNameLookupVisitor *This + = static_cast<DeclContextNameLookupVisitor *>(UserData); + + // Check whether we have any visible declaration information for + // this context in this module. + Module::DeclContextInfosMap::iterator Info + = M.DeclContextInfos.find(This->DC); + if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData) + return false; + + // Look for this name within this module. + ASTDeclContextNameLookupTable *LookupTable = + (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData; + ASTDeclContextNameLookupTable::iterator Pos + = LookupTable->find(This->Name); + if (Pos == LookupTable->end()) + return false; + + bool FoundAnything = false; + ASTDeclContextNameLookupTrait::data_type Data = *Pos; + for (; Data.first != Data.second; ++Data.first) { + NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first); + if (!ND) + continue; + + if (ND->getDeclName() != This->Name) { + assert(!This->Name.getCXXNameType().isNull() && + "Name mismatch without a type"); + continue; + } + + // Record this declaration. + FoundAnything = true; + This->Decls.push_back(ND); + } + + return FoundAnything; + } + }; +} + DeclContext::lookup_result ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { @@ -4047,69 +4191,39 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, return DeclContext::lookup_result(DeclContext::lookup_iterator(0), DeclContext::lookup_iterator(0)); - llvm::SmallVector<NamedDecl *, 64> Decls; - // There might be visible decls in multiple parts of the chain, for the TU - // and namespaces. For any given name, the last available results replace - // all earlier ones. For this reason, we walk in reverse. - DeclContextInfos &Infos = DeclContextOffsets[DC]; - for (DeclContextInfos::reverse_iterator I = Infos.rbegin(), E = Infos.rend(); - I != E; ++I) { - if (!I->NameLookupTableData) - continue; - - ASTDeclContextNameLookupTable *LookupTable = - (ASTDeclContextNameLookupTable*)I->NameLookupTableData; - ASTDeclContextNameLookupTable::iterator Pos = LookupTable->find(Name); - if (Pos == LookupTable->end()) - continue; - - ASTDeclContextNameLookupTrait::data_type Data = *Pos; - for (; Data.first != Data.second; ++Data.first) - Decls.push_back(cast<NamedDecl>(GetDecl(*Data.first))); - break; - } - + SmallVector<NamedDecl *, 64> Decls; + DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls); + ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); ++NumVisibleDeclContextsRead; - SetExternalVisibleDeclsForName(DC, Name, Decls); return const_cast<DeclContext*>(DC)->lookup(Name); } -void ASTReader::MaterializeVisibleDecls(const DeclContext *DC) { - assert(DC->hasExternalVisibleStorage() && - "DeclContext has no visible decls in storage"); +/// \brief Under non-PCH compilation the consumer receives the objc methods +/// before receiving the implementation, and codegen depends on this. +/// We simulate this by deserializing and passing to consumer the methods of the +/// implementation before passing the deserialized implementation decl. +static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, + ASTConsumer *Consumer) { + assert(ImplD && Consumer); - llvm::SmallVector<NamedDecl *, 64> Decls; - // There might be visible decls in multiple parts of the chain, for the TU - // and namespaces. - DeclContextInfos &Infos = DeclContextOffsets[DC]; - for (DeclContextInfos::iterator I = Infos.begin(), E = Infos.end(); - I != E; ++I) { - if (!I->NameLookupTableData) - continue; + for (ObjCImplDecl::method_iterator + I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I) + Consumer->HandleInterestingDecl(DeclGroupRef(*I)); - ASTDeclContextNameLookupTable *LookupTable = - (ASTDeclContextNameLookupTable*)I->NameLookupTableData; - for (ASTDeclContextNameLookupTable::item_iterator - ItemI = LookupTable->item_begin(), - ItemEnd = LookupTable->item_end() ; ItemI != ItemEnd; ++ItemI) { - ASTDeclContextNameLookupTable::item_iterator::value_type Val - = *ItemI; - ASTDeclContextNameLookupTrait::data_type Data = Val.second; - Decls.clear(); - for (; Data.first != Data.second; ++Data.first) - Decls.push_back(cast<NamedDecl>(GetDecl(*Data.first))); - MaterializeVisibleDeclsForName(DC, Val.first, Decls); - } - } + Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } void ASTReader::PassInterestingDeclsToConsumer() { assert(Consumer); while (!InterestingDecls.empty()) { - DeclGroupRef DG(InterestingDecls.front()); + Decl *D = InterestingDecls.front(); InterestingDecls.pop_front(); - Consumer->HandleInterestingDecl(DG); + + if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) + PassObjCImplDeclToConsumer(ImplD, Consumer); + else + Consumer->HandleInterestingDecl(DeclGroupRef(D)); } } @@ -4124,6 +4238,7 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { // passing to the consumer. GetDecl(ExternalDefinitions[I]); } + ExternalDefinitions.clear(); PassInterestingDeclsToConsumer(); } @@ -4148,7 +4263,7 @@ void ASTReader::PrintStats() { std::fprintf(stderr, " %u stat cache hits\n", NumStatHits); std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses); - if (TotalNumSLocEntries) + if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", NumSLocEntriesRead, TotalNumSLocEntries, ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); @@ -4194,13 +4309,51 @@ void ASTReader::PrintStats() { std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); } std::fprintf(stderr, "\n"); + dump(); + std::fprintf(stderr, "\n"); +} + +template<typename Key, typename Module, unsigned InitialCapacity> +static void +dumpModuleIDMap(StringRef Name, + const ContinuousRangeMap<Key, Module *, + InitialCapacity> &Map) { + if (Map.begin() == Map.end()) + return; + + typedef ContinuousRangeMap<Key, Module *, InitialCapacity> MapType; + llvm::errs() << Name << ":\n"; + for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); + I != IEnd; ++I) { + llvm::errs() << " " << I->first << " -> " << I->second->FileName + << "\n"; + } +} + +void ASTReader::dump() { + llvm::errs() << "*** PCH/Module Remappings:\n"; + dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap); + dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap); + dumpModuleIDMap("Global type map", GlobalTypeMap); + dumpModuleIDMap("Global declaration map", GlobalDeclMap); + dumpModuleIDMap("Global identifier map", GlobalIdentifierMap); + dumpModuleIDMap("Global selector map", GlobalSelectorMap); + dumpModuleIDMap("Global preprocessed entity map", + GlobalPreprocessedEntityMap); + + llvm::errs() << "\n*** PCH/Modules Loaded:"; + for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(), + MEnd = ModuleMgr.end(); + M != MEnd; ++M) + (*M)->dump(); } /// Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { - for (unsigned i = 0, e = Chain.size(); i != e; ++i) - if (llvm::MemoryBuffer *buf = Chain[i]->Buffer.get()) { + for (ModuleConstIterator I = ModuleMgr.begin(), + E = ModuleMgr.end(); I != E; ++I) { + if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) { size_t bytes = buf->getBufferSize(); switch (buf->getBufferKind()) { case llvm::MemoryBuffer::MemoryBuffer_Malloc: @@ -4211,6 +4364,7 @@ void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { break; } } + } } void ASTReader::InitializeSema(Sema &S) { @@ -4227,114 +4381,14 @@ void ASTReader::InitializeSema(Sema &S) { } PreloadedDecls.clear(); - // If there were any tentative definitions, deserialize them and add - // them to Sema's list of tentative definitions. - for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { - VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I])); - SemaObj->TentativeDefinitions.push_back(Var); - } - - // If there were any unused file scoped decls, deserialize them and add to - // Sema's list of unused file scoped decls. - for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { - DeclaratorDecl *D = cast<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I])); - SemaObj->UnusedFileScopedDecls.push_back(D); - } - - // If there were any delegating constructors, add them to Sema's list - for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { - CXXConstructorDecl *D - = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); - SemaObj->DelegatingCtorDecls.push_back(D); - } - - // If there were any locally-scoped external declarations, - // deserialize them and add them to Sema's table of locally-scoped - // external declarations. - for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { - NamedDecl *D = cast<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); - SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D; - } - - // If there were any ext_vector type declarations, deserialize them - // and add them to Sema's vector of such declarations. - for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) - SemaObj->ExtVectorDecls.push_back( - cast<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]))); - - // FIXME: Do VTable uses and dynamic classes deserialize too much ? - // Can we cut them down before writing them ? - - // If there were any dynamic classes declarations, deserialize them - // and add them to Sema's vector of such declarations. - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) - SemaObj->DynamicClasses.push_back( - cast<CXXRecordDecl>(GetDecl(DynamicClasses[I]))); - // Load the offsets of the declarations that Sema references. // They will be lazily deserialized when needed. if (!SemaDeclRefs.empty()) { assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!"); - SemaObj->StdNamespace = SemaDeclRefs[0]; - SemaObj->StdBadAlloc = SemaDeclRefs[1]; - } - - for (PerFileData *F = FirstInSource; F; F = F->NextInSource) { - - // If there are @selector references added them to its pool. This is for - // implementation of -Wselector. - if (!F->ReferencedSelectorsData.empty()) { - unsigned int DataSize = F->ReferencedSelectorsData.size()-1; - unsigned I = 0; - while (I < DataSize) { - Selector Sel = DecodeSelector(F->ReferencedSelectorsData[I++]); - SourceLocation SelLoc = ReadSourceLocation( - *F, F->ReferencedSelectorsData, I); - SemaObj->ReferencedSelectors.insert(std::make_pair(Sel, SelLoc)); - } - } - } - - // The special data sets below always come from the most recent PCH, - // which is at the front of the chain. - PerFileData &F = *Chain.front(); - - // If there were any pending implicit instantiations, deserialize them - // and add them to Sema's queue of such instantiations. - assert(F.PendingInstantiations.size() % 2 == 0 && - "Expected pairs of entries"); - for (unsigned Idx = 0, N = F.PendingInstantiations.size(); Idx < N;) { - ValueDecl *D=cast<ValueDecl>(GetDecl(F.PendingInstantiations[Idx++])); - SourceLocation Loc = ReadSourceLocation(F, F.PendingInstantiations,Idx); - SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc)); - } - - // If there were any weak undeclared identifiers, deserialize them and add to - // Sema's list of weak undeclared identifiers. - if (!WeakUndeclaredIdentifiers.empty()) { - unsigned Idx = 0; - for (unsigned I = 0, N = WeakUndeclaredIdentifiers[Idx++]; I != N; ++I) { - IdentifierInfo *WeakId = GetIdentifierInfo(WeakUndeclaredIdentifiers,Idx); - IdentifierInfo *AliasId= GetIdentifierInfo(WeakUndeclaredIdentifiers,Idx); - SourceLocation Loc = ReadSourceLocation(F, WeakUndeclaredIdentifiers,Idx); - bool Used = WeakUndeclaredIdentifiers[Idx++]; - Sema::WeakInfo WI(AliasId, Loc); - WI.setUsed(Used); - SemaObj->WeakUndeclaredIdentifiers.insert(std::make_pair(WeakId, WI)); - } - } - - // If there were any VTable uses, deserialize the information and add it - // to Sema's vector and map of VTable uses. - if (!VTableUses.empty()) { - unsigned Idx = 0; - for (unsigned I = 0, N = VTableUses[Idx++]; I != N; ++I) { - CXXRecordDecl *Class = cast<CXXRecordDecl>(GetDecl(VTableUses[Idx++])); - SourceLocation Loc = ReadSourceLocation(F, VTableUses, Idx); - bool DefinitionRequired = VTableUses[Idx++]; - SemaObj->VTableUses.push_back(std::make_pair(Class, Loc)); - SemaObj->VTablesUsed[Class] = DefinitionRequired; - } + if (!SemaObj->StdNamespace) + SemaObj->StdNamespace = SemaDeclRefs[0]; + if (!SemaObj->StdBadAlloc) + SemaObj->StdBadAlloc = SemaDeclRefs[1]; } if (!FPPragmaOptions.empty()) { @@ -4352,24 +4406,9 @@ void ASTReader::InitializeSema(Sema &S) { } IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { - // Try to find this name within our on-disk hash tables. We start with the - // most recent one, since that one contains the most up-to-date info. - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Chain[I]->IdentifierLookupTable; - if (!IdTable) - continue; - std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart); - ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key); - if (Pos == IdTable->end()) - continue; - - // Dereferencing the iterator has the effect of building the - // IdentifierInfo node and populating it with the various - // declarations it needs. - return *Pos; - } - return 0; + IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart)); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + return Visitor.getIdentifierInfo(); } namespace clang { @@ -4394,27 +4433,28 @@ namespace clang { public: explicit ASTIdentifierIterator(const ASTReader &Reader); - virtual llvm::StringRef Next(); + virtual StringRef Next(); }; } ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader) - : Reader(Reader), Index(Reader.Chain.size() - 1) { + : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) { ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Reader.Chain[Index]->IdentifierLookupTable; + = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } -llvm::StringRef ASTIdentifierIterator::Next() { +StringRef ASTIdentifierIterator::Next() { while (Current == End) { // If we have exhausted all of our AST files, we're done. if (Index == 0) - return llvm::StringRef(); + return StringRef(); --Index; ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Reader.Chain[Index]->IdentifierLookupTable; + = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index]. + IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } @@ -4423,43 +4463,103 @@ llvm::StringRef ASTIdentifierIterator::Next() { // the next one. std::pair<const char*, unsigned> Key = *Current; ++Current; - return llvm::StringRef(Key.first, Key.second); + return StringRef(Key.first, Key.second); } IdentifierIterator *ASTReader::getIdentifiers() const { return new ASTIdentifierIterator(*this); } -std::pair<ObjCMethodList, ObjCMethodList> -ASTReader::ReadMethodPool(Selector Sel) { - // Find this selector in a hash table. We want to find the most recent entry. - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[I]; - if (!F.SelectorLookupTable) - continue; - - ASTSelectorLookupTable *PoolTable - = (ASTSelectorLookupTable*)F.SelectorLookupTable; - ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); - if (Pos != PoolTable->end()) { - ++NumSelectorsRead; +namespace clang { namespace serialization { + class ReadMethodPoolVisitor { + ASTReader &Reader; + Selector Sel; + llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods; + llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods; + + /// \brief Build an ObjCMethodList from a vector of Objective-C method + /// declarations. + ObjCMethodList + buildObjCMethodList(const SmallVectorImpl<ObjCMethodDecl *> &Vec) const + { + ObjCMethodList List; + ObjCMethodList *Prev = 0; + for (unsigned I = 0, N = Vec.size(); I != N; ++I) { + if (!List.Method) { + // This is the first method, which is the easy case. + List.Method = Vec[I]; + Prev = &List; + continue; + } + + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); + Prev->Next = new (Mem) ObjCMethodList(Vec[I], 0); + Prev = Prev->Next; + } + + return List; + } + + public: + ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel) + : Reader(Reader), Sel(Sel) { } + + static bool visit(Module &M, void *UserData) { + ReadMethodPoolVisitor *This + = static_cast<ReadMethodPoolVisitor *>(UserData); + + if (!M.SelectorLookupTable) + return false; + + ASTSelectorLookupTable *PoolTable + = (ASTSelectorLookupTable*)M.SelectorLookupTable; + ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); + if (Pos == PoolTable->end()) + return false; + + ++This->Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. // Also, should entries without methods count as misses? - ++NumMethodPoolEntriesRead; + ++This->Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; - if (DeserializationListener) - DeserializationListener->SelectorRead(Data.ID, Sel); - return std::make_pair(Data.Instance, Data.Factory); + if (This->Reader.DeserializationListener) + This->Reader.DeserializationListener->SelectorRead(Data.ID, + This->Sel); + + This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); + This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + return true; + } + + /// \brief Retrieve the instance methods found by this visitor. + ObjCMethodList getInstanceMethods() const { + return buildObjCMethodList(InstanceMethods); } - } - ++NumMethodPoolMisses; - return std::pair<ObjCMethodList, ObjCMethodList>(); + /// \brief Retrieve the instance methods found by this visitor. + ObjCMethodList getFactoryMethods() const { + return buildObjCMethodList(FactoryMethods); + } + }; +} } // end namespace clang::serialization + +std::pair<ObjCMethodList, ObjCMethodList> +ASTReader::ReadMethodPool(Selector Sel) { + ReadMethodPoolVisitor Visitor(*this, Sel); + ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); + std::pair<ObjCMethodList, ObjCMethodList> Result; + Result.first = Visitor.getInstanceMethods(); + Result.second = Visitor.getFactoryMethods(); + + if (!Result.first.Method && !Result.second.Method) + ++NumMethodPoolMisses; + return Result; } void ASTReader::ReadKnownNamespaces( - llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) { + SmallVectorImpl<NamespaceDecl *> &Namespaces) { Namespaces.clear(); for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) { @@ -4469,12 +4569,136 @@ void ASTReader::ReadKnownNamespaces( } } +void ASTReader::ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) { + for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { + VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I])); + if (Var) + TentativeDefs.push_back(Var); + } + TentativeDefinitions.clear(); +} + +void ASTReader::ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) { + for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { + DeclaratorDecl *D + = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I])); + if (D) + Decls.push_back(D); + } + UnusedFileScopedDecls.clear(); +} + +void ASTReader::ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) { + for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { + CXXConstructorDecl *D + = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); + if (D) + Decls.push_back(D); + } + DelegatingCtorDecls.clear(); +} + +void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) { + for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) { + TypedefNameDecl *D + = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I])); + if (D) + Decls.push_back(D); + } + ExtVectorDecls.clear(); +} + +void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) { + for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { + CXXRecordDecl *D + = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I])); + if (D) + Decls.push_back(D); + } + DynamicClasses.clear(); +} + +void +ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) { + for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { + NamedDecl *D + = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); + if (D) + Decls.push_back(D); + } + LocallyScopedExternalDecls.clear(); +} + +void ASTReader::ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) { + if (ReferencedSelectorsData.empty()) + return; + + // If there are @selector references added them to its pool. This is for + // implementation of -Wselector. + unsigned int DataSize = ReferencedSelectorsData.size()-1; + unsigned I = 0; + while (I < DataSize) { + Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]); + SourceLocation SelLoc + = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]); + Sels.push_back(std::make_pair(Sel, SelLoc)); + } + ReferencedSelectorsData.clear(); +} + +void ASTReader::ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) { + if (WeakUndeclaredIdentifiers.empty()) + return; + + for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) { + IdentifierInfo *WeakId + = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); + IdentifierInfo *AliasId + = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); + SourceLocation Loc + = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]); + bool Used = WeakUndeclaredIdentifiers[I++]; + WeakInfo WI(AliasId, Loc); + WI.setUsed(Used); + WeakIDs.push_back(std::make_pair(WeakId, WI)); + } + WeakUndeclaredIdentifiers.clear(); +} + +void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) { + for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) { + ExternalVTableUse VT; + VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++])); + VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]); + VT.DefinitionRequired = VTableUses[Idx++]; + VTables.push_back(VT); + } + + VTableUses.clear(); +} + +void ASTReader::ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) { + for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { + ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++])); + SourceLocation Loc + = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]); + Pending.push_back(std::make_pair(D, Loc)); + } + PendingInstantiations.clear(); +} + void ASTReader::LoadSelector(Selector Sel) { // It would be complicated to avoid reading the methods anyway. So don't. ReadMethodPool(Sel); } -void ASTReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) { +void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { assert(ID && "Non-zero identifier ID required"); assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); IdentifiersLoaded[ID - 1] = II; @@ -4500,7 +4724,7 @@ void ASTReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) { /// will not be placed onto the pending queue. void ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, - const llvm::SmallVectorImpl<uint32_t> &DeclIDs, + const SmallVectorImpl<uint32_t> &DeclIDs, bool Nonrecursive) { if (NumCurrentElementsDeserializing && !Nonrecursive) { PendingIdentifierInfos.push_back(PendingIdentifierInfo()); @@ -4529,7 +4753,7 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, } } -IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) { +IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { if (ID == 0) return 0; @@ -4538,21 +4762,13 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) { return 0; } - assert(PP && "Forgot to set Preprocessor ?"); ID -= 1; if (!IdentifiersLoaded[ID]) { - unsigned Index = ID; - const char *Str = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData *F = Chain[N - I - 1]; - if (Index < F->LocalNumIdentifiers) { - uint32_t Offset = F->IdentifierOffsets[Index]; - Str = F->IdentifierTableData + Offset; - break; - } - Index -= F->LocalNumIdentifiers; - } - assert(Str && "Broken Chain"); + GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1); + assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map"); + Module *M = I->second; + unsigned Index = ID - M->BaseIdentifierID; + const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index]; // All of the strings in the AST file are preceded by a 16-bit length. // Extract that 16-bit length to avoid having to execute strlen(). @@ -4563,7 +4779,7 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) { unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; IdentifiersLoaded[ID] - = &PP->getIdentifierTable().get(llvm::StringRef(Str, StrLen)); + = &PP.getIdentifierTable().get(StringRef(Str, StrLen)); if (DeserializationListener) DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]); } @@ -4571,11 +4787,31 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) { return IdentifiersLoaded[ID]; } -bool ASTReader::ReadSLocEntry(unsigned ID) { +IdentifierInfo *ASTReader::getLocalIdentifier(Module &M, unsigned LocalID) { + return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID)); +} + +IdentifierID ASTReader::getGlobalIdentifierID(Module &M, unsigned LocalID) { + if (LocalID < NUM_PREDEF_IDENT_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS); + assert(I != M.IdentifierRemap.end() + && "Invalid index into identifier index remap"); + + return LocalID + I->second; +} + +bool ASTReader::ReadSLocEntry(int ID) { return ReadSLocEntryRecord(ID) != Success; } -Selector ASTReader::DecodeSelector(unsigned ID) { +Selector ASTReader::getLocalSelector(Module &M, unsigned LocalID) { + return DecodeSelector(getGlobalSelectorID(M, LocalID)); +} + +Selector ASTReader::DecodeSelector(serialization::SelectorID ID) { if (ID == 0) return Selector(); @@ -4586,25 +4822,21 @@ Selector ASTReader::DecodeSelector(unsigned ID) { if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) { // Load this selector from the selector table. - unsigned Idx = ID - 1; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - PerFileData &F = *Chain[N - I - 1]; - if (Idx < F.LocalNumSelectors) { - ASTSelectorLookupTrait Trait(*this); - SelectorsLoaded[ID - 1] = - Trait.ReadKey(F.SelectorLookupTableData + F.SelectorOffsets[Idx], 0); - if (DeserializationListener) - DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); - break; - } - Idx -= F.LocalNumSelectors; - } + GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID); + assert(I != GlobalSelectorMap.end() && "Corrupted global selector map"); + Module &M = *I->second; + ASTSelectorLookupTrait Trait(*this, M); + unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS; + SelectorsLoaded[ID - 1] = + Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0); + if (DeserializationListener) + DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); } return SelectorsLoaded[ID - 1]; } -Selector ASTReader::GetExternalSelector(uint32_t ID) { +Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) { return DecodeSelector(ID); } @@ -4613,37 +4845,51 @@ uint32_t ASTReader::GetNumExternalSelectors() { return getTotalNumSelectors() + 1; } +serialization::SelectorID +ASTReader::getGlobalSelectorID(Module &M, unsigned LocalID) const { + if (LocalID < NUM_PREDEF_SELECTOR_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); + assert(I != M.SelectorRemap.end() + && "Invalid index into identifier index remap"); + + return LocalID + I->second; +} + DeclarationName -ASTReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { +ASTReader::ReadDeclarationName(Module &F, + const RecordData &Record, unsigned &Idx) { DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; switch (Kind) { case DeclarationName::Identifier: - return DeclarationName(GetIdentifierInfo(Record, Idx)); + return DeclarationName(GetIdentifierInfo(F, Record, Idx)); case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(GetSelector(Record, Idx)); + return DeclarationName(ReadSelector(F, Record, Idx)); case DeclarationName::CXXConstructorName: - return Context->DeclarationNames.getCXXConstructorName( - Context->getCanonicalType(GetType(Record[Idx++]))); + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXDestructorName: - return Context->DeclarationNames.getCXXDestructorName( - Context->getCanonicalType(GetType(Record[Idx++]))); + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXConversionFunctionName: - return Context->DeclarationNames.getCXXConversionFunctionName( - Context->getCanonicalType(GetType(Record[Idx++]))); + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(readType(F, Record, Idx))); case DeclarationName::CXXOperatorName: - return Context->DeclarationNames.getCXXOperatorName( + return Context.DeclarationNames.getCXXOperatorName( (OverloadedOperatorKind)Record[Idx++]); case DeclarationName::CXXLiteralOperatorName: - return Context->DeclarationNames.getCXXLiteralOperatorName( - GetIdentifierInfo(Record, Idx)); + return Context.DeclarationNames.getCXXLiteralOperatorName( + GetIdentifierInfo(F, Record, Idx)); case DeclarationName::CXXUsingDirective: return DeclarationName::getUsingDirectiveName(); @@ -4653,7 +4899,7 @@ ASTReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { return DeclarationName(); } -void ASTReader::ReadDeclarationNameLoc(PerFileData &F, +void ASTReader::ReadDeclarationNameLoc(Module &F, DeclarationNameLoc &DNLoc, DeclarationName Name, const RecordData &Record, unsigned &Idx) { @@ -4685,72 +4931,73 @@ void ASTReader::ReadDeclarationNameLoc(PerFileData &F, } } -void ASTReader::ReadDeclarationNameInfo(PerFileData &F, +void ASTReader::ReadDeclarationNameInfo(Module &F, DeclarationNameInfo &NameInfo, const RecordData &Record, unsigned &Idx) { - NameInfo.setName(ReadDeclarationName(Record, Idx)); + NameInfo.setName(ReadDeclarationName(F, Record, Idx)); NameInfo.setLoc(ReadSourceLocation(F, Record, Idx)); DeclarationNameLoc DNLoc; ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx); NameInfo.setInfo(DNLoc); } -void ASTReader::ReadQualifierInfo(PerFileData &F, QualifierInfo &Info, +void ASTReader::ReadQualifierInfo(Module &F, QualifierInfo &Info, const RecordData &Record, unsigned &Idx) { Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); unsigned NumTPLists = Record[Idx++]; Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { - Info.TemplParamLists = new (*Context) TemplateParameterList*[NumTPLists]; + Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; for (unsigned i=0; i != NumTPLists; ++i) Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); } } TemplateName -ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record, +ASTReader::ReadTemplateName(Module &F, const RecordData &Record, unsigned &Idx) { TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; switch (Kind) { case TemplateName::Template: - return TemplateName(cast_or_null<TemplateDecl>(GetDecl(Record[Idx++]))); + return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx)); case TemplateName::OverloadedTemplate: { unsigned size = Record[Idx++]; UnresolvedSet<8> Decls; while (size--) - Decls.addDecl(cast<NamedDecl>(GetDecl(Record[Idx++]))); + Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx)); - return Context->getOverloadedTemplateName(Decls.begin(), Decls.end()); + return Context.getOverloadedTemplateName(Decls.begin(), Decls.end()); } case TemplateName::QualifiedTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); bool hasTemplKeyword = Record[Idx++]; - TemplateDecl *Template = cast<TemplateDecl>(GetDecl(Record[Idx++])); - return Context->getQualifiedTemplateName(NNS, hasTemplKeyword, Template); + TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx); + return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template); } case TemplateName::DependentTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); + NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); if (Record[Idx++]) // isIdentifier - return Context->getDependentTemplateName(NNS, - GetIdentifierInfo(Record, Idx)); - return Context->getDependentTemplateName(NNS, + return Context.getDependentTemplateName(NNS, + GetIdentifierInfo(F, Record, + Idx)); + return Context.getDependentTemplateName(NNS, (OverloadedOperatorKind)Record[Idx++]); } case TemplateName::SubstTemplateTemplateParm: { TemplateTemplateParmDecl *param - = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++])); + = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); if (!param) return TemplateName(); TemplateName replacement = ReadTemplateName(F, Record, Idx); - return Context->getSubstTemplateTemplateParm(param, replacement); + return Context.getSubstTemplateTemplateParm(param, replacement); } case TemplateName::SubstTemplateTemplateParmPack: { TemplateTemplateParmDecl *Param - = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++])); + = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); if (!Param) return TemplateName(); @@ -4758,28 +5005,27 @@ ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record, if (ArgPack.getKind() != TemplateArgument::Pack) return TemplateName(); - return Context->getSubstTemplateTemplateParmPack(Param, ArgPack); + return Context.getSubstTemplateTemplateParmPack(Param, ArgPack); } } - assert(0 && "Unhandled template name kind!"); - return TemplateName(); + llvm_unreachable("Unhandled template name kind!"); } TemplateArgument -ASTReader::ReadTemplateArgument(PerFileData &F, +ASTReader::ReadTemplateArgument(Module &F, const RecordData &Record, unsigned &Idx) { TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; switch (Kind) { case TemplateArgument::Null: return TemplateArgument(); case TemplateArgument::Type: - return TemplateArgument(GetType(Record[Idx++])); + return TemplateArgument(readType(F, Record, Idx)); case TemplateArgument::Declaration: - return TemplateArgument(GetDecl(Record[Idx++])); + return TemplateArgument(ReadDecl(F, Record, Idx)); case TemplateArgument::Integral: { llvm::APSInt Value = ReadAPSInt(Record, Idx); - QualType T = GetType(Record[Idx++]); + QualType T = readType(F, Record, Idx); return TemplateArgument(Value, T); } case TemplateArgument::Template: @@ -4795,40 +5041,39 @@ ASTReader::ReadTemplateArgument(PerFileData &F, return TemplateArgument(ReadExpr(F)); case TemplateArgument::Pack: { unsigned NumArgs = Record[Idx++]; - TemplateArgument *Args = new (*Context) TemplateArgument[NumArgs]; + TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; for (unsigned I = 0; I != NumArgs; ++I) Args[I] = ReadTemplateArgument(F, Record, Idx); return TemplateArgument(Args, NumArgs); } } - assert(0 && "Unhandled template argument kind!"); - return TemplateArgument(); + llvm_unreachable("Unhandled template argument kind!"); } TemplateParameterList * -ASTReader::ReadTemplateParameterList(PerFileData &F, +ASTReader::ReadTemplateParameterList(Module &F, const RecordData &Record, unsigned &Idx) { SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx); SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx); SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx); unsigned NumParams = Record[Idx++]; - llvm::SmallVector<NamedDecl *, 16> Params; + SmallVector<NamedDecl *, 16> Params; Params.reserve(NumParams); while (NumParams--) - Params.push_back(cast<NamedDecl>(GetDecl(Record[Idx++]))); + Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); TemplateParameterList* TemplateParams = - TemplateParameterList::Create(*Context, TemplateLoc, LAngleLoc, + TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, Params.data(), Params.size(), RAngleLoc); return TemplateParams; } void ASTReader:: -ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs, - PerFileData &F, const RecordData &Record, +ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs, + Module &F, const RecordData &Record, unsigned &Idx) { unsigned NumTemplateArgs = Record[Idx++]; TemplArgs.reserve(NumTemplateArgs); @@ -4837,18 +5082,18 @@ ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs, } /// \brief Read a UnresolvedSet structure. -void ASTReader::ReadUnresolvedSet(UnresolvedSetImpl &Set, +void ASTReader::ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; while (NumDecls--) { - NamedDecl *D = cast<NamedDecl>(GetDecl(Record[Idx++])); + NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; Set.addDecl(D, AS); } } CXXBaseSpecifier -ASTReader::ReadCXXBaseSpecifier(PerFileData &F, +ASTReader::ReadCXXBaseSpecifier(Module &F, const RecordData &Record, unsigned &Idx) { bool isVirtual = static_cast<bool>(Record[Idx++]); bool isBaseOfClass = static_cast<bool>(Record[Idx++]); @@ -4864,15 +5109,13 @@ ASTReader::ReadCXXBaseSpecifier(PerFileData &F, } std::pair<CXXCtorInitializer **, unsigned> -ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, +ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record, unsigned &Idx) { CXXCtorInitializer **CtorInitializers = 0; unsigned NumInitializers = Record[Idx++]; if (NumInitializers) { - ASTContext &C = *getContext(); - CtorInitializers - = new (C) CXXCtorInitializer*[NumInitializers]; + = new (Context) CXXCtorInitializer*[NumInitializers]; for (unsigned i=0; i != NumInitializers; ++i) { TypeSourceInfo *BaseClassInfo = 0; bool IsBaseVirtual = false; @@ -4888,15 +5131,15 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, break; case CTOR_INITIALIZER_DELEGATING: - Target = cast<CXXConstructorDecl>(GetDecl(Record[Idx++])); + Target = ReadDeclAs<CXXConstructorDecl>(F, Record, Idx); break; case CTOR_INITIALIZER_MEMBER: - Member = cast<FieldDecl>(GetDecl(Record[Idx++])); + Member = ReadDeclAs<FieldDecl>(F, Record, Idx); break; case CTOR_INITIALIZER_INDIRECT_MEMBER: - IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++])); + IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx); break; } @@ -4906,34 +5149,34 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx); bool IsWritten = Record[Idx++]; unsigned SourceOrderOrNumArrayIndices; - llvm::SmallVector<VarDecl *, 8> Indices; + SmallVector<VarDecl *, 8> Indices; if (IsWritten) { SourceOrderOrNumArrayIndices = Record[Idx++]; } else { SourceOrderOrNumArrayIndices = Record[Idx++]; Indices.reserve(SourceOrderOrNumArrayIndices); for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i) - Indices.push_back(cast<VarDecl>(GetDecl(Record[Idx++]))); + Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx)); } CXXCtorInitializer *BOMInit; if (Type == CTOR_INITIALIZER_BASE) { - BOMInit = new (C) CXXCtorInitializer(C, BaseClassInfo, IsBaseVirtual, + BOMInit = new (Context) CXXCtorInitializer(Context, BaseClassInfo, IsBaseVirtual, LParenLoc, Init, RParenLoc, MemberOrEllipsisLoc); } else if (Type == CTOR_INITIALIZER_DELEGATING) { - BOMInit = new (C) CXXCtorInitializer(C, MemberOrEllipsisLoc, LParenLoc, + BOMInit = new (Context) CXXCtorInitializer(Context, MemberOrEllipsisLoc, LParenLoc, Target, Init, RParenLoc); } else if (IsWritten) { if (Member) - BOMInit = new (C) CXXCtorInitializer(C, Member, MemberOrEllipsisLoc, + BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); else - BOMInit = new (C) CXXCtorInitializer(C, IndirectMember, + BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); } else { - BOMInit = CXXCtorInitializer::Create(C, Member, MemberOrEllipsisLoc, + BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc, Indices.data(), Indices.size()); } @@ -4948,7 +5191,8 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record, } NestedNameSpecifier * -ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { +ASTReader::ReadNestedNameSpecifier(Module &F, + const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; NestedNameSpecifier *NNS = 0, *Prev = 0; for (unsigned I = 0; I != N; ++I) { @@ -4956,37 +5200,36 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; switch (Kind) { case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(Record, Idx); - NNS = NestedNameSpecifier::Create(*Context, Prev, II); + IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, II); break; } case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++])); - NNS = NestedNameSpecifier::Create(*Context, Prev, NS); + NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, NS); break; } case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias - = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++])); - NNS = NestedNameSpecifier::Create(*Context, Prev, Alias); + NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); + NNS = NestedNameSpecifier::Create(Context, Prev, Alias); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - const Type *T = GetType(Record[Idx++]).getTypePtrOrNull(); + const Type *T = readType(F, Record, Idx).getTypePtrOrNull(); if (!T) return 0; bool Template = Record[Idx++]; - NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T); + NNS = NestedNameSpecifier::Create(Context, Prev, Template, T); break; } case NestedNameSpecifier::Global: { - NNS = NestedNameSpecifier::GlobalSpecifier(*Context); + NNS = NestedNameSpecifier::GlobalSpecifier(Context); // No associated value, and there can't be a prefix. break; } @@ -4997,7 +5240,7 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { } NestedNameSpecifierLoc -ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record, +ASTReader::ReadNestedNameSpecifierLoc(Module &F, const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; NestedNameSpecifierLocBuilder Builder; @@ -5006,24 +5249,23 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record, = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; switch (Kind) { case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(Record, Idx); + IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(*Context, II, Range.getBegin(), Range.getEnd()); + Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++])); + NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(*Context, NS, Range.getBegin(), Range.getEnd()); + Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias - = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++])); + NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(*Context, Alias, Range.getBegin(), Range.getEnd()); + Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); break; } @@ -5036,7 +5278,7 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record, SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); // FIXME: 'template' keyword location not saved anywhere, so we fake it. - Builder.Extend(*Context, + Builder.Extend(Context, Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), T->getTypeLoc(), ColonColonLoc); break; @@ -5044,17 +5286,17 @@ ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record, case NestedNameSpecifier::Global: { SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); - Builder.MakeGlobal(*Context, ColonColonLoc); + Builder.MakeGlobal(Context, ColonColonLoc); break; } } } - return Builder.getWithLocInContext(*Context); + return Builder.getWithLocInContext(Context); } SourceRange -ASTReader::ReadSourceRange(PerFileData &F, const RecordData &Record, +ASTReader::ReadSourceRange(Module &F, const RecordData &Record, unsigned &Idx) { SourceLocation beg = ReadSourceLocation(F, Record, Idx); SourceLocation end = ReadSourceLocation(F, Record, Idx); @@ -5101,10 +5343,11 @@ VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, return VersionTuple(Major, Minor - 1, Subminor - 1); } -CXXTemporary *ASTReader::ReadCXXTemporary(const RecordData &Record, +CXXTemporary *ASTReader::ReadCXXTemporary(Module &F, + const RecordData &Record, unsigned &Idx) { - CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++])); - return CXXTemporary::Create(*Context, Decl); + CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx); + return CXXTemporary::Create(Context, Decl); } DiagnosticBuilder ASTReader::Diag(unsigned DiagID) { @@ -5118,8 +5361,7 @@ DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) { /// \brief Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &ASTReader::getIdentifierTable() { - assert(PP && "Forgot to set Preprocessor ?"); - return PP->getIdentifierTable(); + return PP.getIdentifierTable(); } /// \brief Record that the given ID maps to the given switch-case @@ -5169,56 +5411,29 @@ void ASTReader::FinishedDeserializing() { --NumCurrentElementsDeserializing; } -ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context, - const char *isysroot, bool DisableValidation, +ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, + StringRef isysroot, bool DisableValidation, bool DisableStatCache) : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), - Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context), - Consumer(0), isysroot(isysroot), DisableValidation(DisableValidation), + Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), + Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()), + RelocatablePCH(false), isysroot(isysroot), + DisableValidation(DisableValidation), DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0), - NumSLocEntriesRead(0), TotalNumSLocEntries(0), NextSLocOffset(0), + NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), - NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), - NumCurrentElementsDeserializing(0) + NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), + TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), + NumCXXBaseSpecifiersLoaded(0) { - RelocatablePCH = false; -} - -ASTReader::ASTReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot, - bool DisableValidation, bool DisableStatCache) - : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr), - Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0), - isysroot(isysroot), DisableValidation(DisableValidation), - DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0), - NumSLocEntriesRead(0), TotalNumSLocEntries(0), - NextSLocOffset(0), NumStatementsRead(0), TotalNumStatements(0), - NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0), - NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0), - TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0), - TotalLexicalDeclContexts(0), NumVisibleDeclContextsRead(0), - TotalVisibleDeclContexts(0), NumCurrentElementsDeserializing(0) { - RelocatablePCH = false; + SourceMgr.setExternalSLocEntrySource(this); } ASTReader::~ASTReader() { - for (unsigned i = 0, e = Chain.size(); i != e; ++i) - delete Chain[e - i - 1]; - // Delete all visible decl lookup tables - for (DeclContextOffsetsMap::iterator I = DeclContextOffsets.begin(), - E = DeclContextOffsets.end(); - I != E; ++I) { - for (DeclContextInfos::iterator J = I->second.begin(), F = I->second.end(); - J != F; ++J) { - if (J->NameLookupTableData) - delete static_cast<ASTDeclContextNameLookupTable*>( - J->NameLookupTableData); - } - } for (DeclContextVisibleUpdatesPending::iterator I = PendingVisibleUpdates.begin(), E = PendingVisibleUpdates.end(); @@ -5226,27 +5441,6 @@ ASTReader::~ASTReader() { for (DeclContextVisibleUpdates::iterator J = I->second.begin(), F = I->second.end(); J != F; ++J) - delete static_cast<ASTDeclContextNameLookupTable*>(*J); - } -} - -ASTReader::PerFileData::PerFileData(ASTFileType Ty) - : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0), - SLocFileOffsets(0), LocalSLocSize(0), - LocalNumIdentifiers(0), IdentifierOffsets(0), IdentifierTableData(0), - IdentifierLookupTable(0), LocalNumMacroDefinitions(0), - MacroDefinitionOffsets(0), - LocalNumHeaderFileInfos(0), HeaderFileInfoTableData(0), - HeaderFileInfoTable(0), - LocalNumSelectors(0), SelectorOffsets(0), - SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), - DeclOffsets(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), - LocalNumTypes(0), TypeOffsets(0), StatCache(0), - NumPreallocatedPreprocessingEntities(0), NextInSource(0) -{} - -ASTReader::PerFileData::~PerFileData() { - delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable); - delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable); - delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable); + delete static_cast<ASTDeclContextNameLookupTable*>(J->first); + } } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index 24ab544..6cc3f0a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -14,6 +14,7 @@ #include "ASTCommon.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Sema/SemaDiagnostic.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclVisitor.h" @@ -31,7 +32,7 @@ using namespace clang::serialization; namespace clang { class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { ASTReader &Reader; - ASTReader::PerFileData &F; + Module &F; llvm::BitstreamCursor &Cursor; const DeclID ThisDeclID; typedef ASTReader::RecordData RecordData; @@ -43,23 +44,42 @@ namespace clang { DeclID LexicalDeclContextIDForTemplateParmDecl; uint64_t GetCurrentCursorOffset(); + SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { return Reader.ReadSourceLocation(F, R, I); } + SourceRange ReadSourceRange(const RecordData &R, unsigned &I) { return Reader.ReadSourceRange(F, R, I); } + TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) { return Reader.GetTypeSourceInfo(F, R, I); } + + serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) { + return Reader.ReadDeclID(F, R, I); + } + + Decl *ReadDecl(const RecordData &R, unsigned &I) { + return Reader.ReadDecl(F, R, I); + } + + template<typename T> + T *ReadDeclAs(const RecordData &R, unsigned &I) { + return Reader.ReadDeclAs<T>(F, R, I); + } + void ReadQualifierInfo(QualifierInfo &Info, const RecordData &R, unsigned &I) { Reader.ReadQualifierInfo(F, Info, R, I); } + void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name, const RecordData &R, unsigned &I) { Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I); } + void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo, const RecordData &R, unsigned &I) { Reader.ReadDeclarationNameInfo(F, NameInfo, R, I); @@ -72,7 +92,7 @@ namespace clang { CXXRecordDecl *DefinitionDecl, const RecordData &Record, unsigned &Idx); public: - ASTDeclReader(ASTReader &Reader, ASTReader::PerFileData &F, + ASTDeclReader(ASTReader &Reader, Module &F, llvm::BitstreamCursor &Cursor, DeclID thisDeclID, const RecordData &Record, unsigned &Idx) : Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID), @@ -82,9 +102,14 @@ namespace clang { void Visit(Decl *D); - void UpdateDecl(Decl *D, ASTReader::PerFileData &Module, + void UpdateDecl(Decl *D, Module &Module, const RecordData &Record); + static void setNextObjCCategory(ObjCCategoryDecl *Cat, + ObjCCategoryDecl *Next) { + Cat->NextClassCategory = Next; + } + void VisitDecl(Decl *D); void VisitTranslationUnitDecl(TranslationUnitDecl *TU); void VisitNamedDecl(NamedDecl *ND); @@ -104,6 +129,8 @@ namespace clang { ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); + void VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); @@ -159,16 +186,7 @@ namespace clang { } uint64_t ASTDeclReader::GetCurrentCursorOffset() { - uint64_t Off = 0; - for (unsigned I = 0, N = Reader.Chain.size(); I != N; ++I) { - ASTReader::PerFileData &F = *Reader.Chain[N - I - 1]; - if (&Cursor == &F.DeclsCursor) { - Off += F.DeclsCursor.GetCurrentBitNo(); - break; - } - Off += F.SizeInBits; - } - return Off; + return F.DeclsCursor.GetCurrentBitNo() + F.GlobalBitOffset; } void ASTDeclReader::Visit(Decl *D) { @@ -211,13 +229,12 @@ void ASTDeclReader::VisitDecl(Decl *D) { // parameter immediately, because the template parameter might be // used in the formulation of its DeclContext. Use the translation // unit DeclContext as a placeholder. - DeclContextIDForTemplateParmDecl = Record[Idx++]; - LexicalDeclContextIDForTemplateParmDecl = Record[Idx++]; - D->setDeclContext(Reader.getContext()->getTranslationUnitDecl()); + DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx); + LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx); + D->setDeclContext(Reader.getContext().getTranslationUnitDecl()); } else { - D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); - D->setLexicalDeclContext( - cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setDeclContext(ReadDeclAs<DeclContext>(Record, Idx)); + D->setLexicalDeclContext(ReadDeclAs<DeclContext>(Record, Idx)); } D->setLocation(ReadSourceLocation(Record, Idx)); D->setInvalidDecl(Record[Idx++]); @@ -230,25 +247,24 @@ void ASTDeclReader::VisitDecl(Decl *D) { D->setUsed(Record[Idx++]); D->setReferenced(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); - D->setPCHLevel(Record[Idx++] + (F.Type <= ASTReader::PCH)); + D->FromASTFile = true; + D->ModulePrivate = Record[Idx++]; } void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { - VisitDecl(TU); - TU->setAnonymousNamespace( - cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + llvm_unreachable("Translation units are not serialized"); } void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) { VisitDecl(ND); - ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); + ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx)); } void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { VisitNamedDecl(TD); TD->setLocStart(ReadSourceLocation(Record, Idx)); // Delay type reading until after we have fully initialized the decl. - TypeIDForTypeDecl = Record[Idx++]; + TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]); } void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) { @@ -266,16 +282,16 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) { VisitRedeclarable(TD); TD->IdentifierNamespace = Record[Idx++]; TD->setTagKind((TagDecl::TagKind)Record[Idx++]); - TD->setDefinition(Record[Idx++]); + TD->setCompleteDefinition(Record[Idx++]); TD->setEmbeddedInDeclarator(Record[Idx++]); + TD->setFreeStanding(Record[Idx++]); TD->setRBraceLoc(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) { // hasExtInfo - TagDecl::ExtInfo *Info = new (*Reader.getContext()) TagDecl::ExtInfo(); + TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); TD->TypedefNameDeclOrQualifier = Info; } else - TD->setTypedefNameForAnonDecl( - cast_or_null<TypedefNameDecl>(Reader.GetDecl(Record[Idx++]))); + TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx)); } void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { @@ -283,15 +299,14 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { if (TypeSourceInfo *TI = Reader.GetTypeSourceInfo(F, Record, Idx)) ED->setIntegerTypeSourceInfo(TI); else - ED->setIntegerType(Reader.GetType(Record[Idx++])); - ED->setPromotionType(Reader.GetType(Record[Idx++])); + ED->setIntegerType(Reader.readType(F, Record, Idx)); + ED->setPromotionType(Reader.readType(F, Record, Idx)); ED->setNumPositiveBits(Record[Idx++]); ED->setNumNegativeBits(Record[Idx++]); ED->IsScoped = Record[Idx++]; ED->IsScopedUsingClassTag = Record[Idx++]; ED->IsFixed = Record[Idx++]; - ED->setInstantiationOfMemberEnum( - cast_or_null<EnumDecl>(Reader.GetDecl(Record[Idx++]))); + ED->setInstantiationOfMemberEnum(ReadDeclAs<EnumDecl>(Record, Idx)); } void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { @@ -303,7 +318,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { VisitNamedDecl(VD); - VD->setType(Reader.GetType(Record[Idx++])); + VD->setType(Reader.readType(F, Record, Idx)); } void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { @@ -318,7 +333,7 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { DD->setInnerLocStart(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) { // hasExtInfo DeclaratorDecl::ExtInfo *Info - = new (*Reader.getContext()) DeclaratorDecl::ExtInfo(); + = new (Reader.getContext()) DeclaratorDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); DD->DeclInfo = Info; } @@ -331,35 +346,35 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx); FD->IdentifierNamespace = Record[Idx++]; switch ((FunctionDecl::TemplatedKind)Record[Idx++]) { - default: assert(false && "Unhandled TemplatedKind!"); - break; + default: llvm_unreachable("Unhandled TemplatedKind!"); case FunctionDecl::TK_NonTemplate: break; case FunctionDecl::TK_FunctionTemplate: - FD->setDescribedFunctionTemplate( - cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]))); + FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record, + Idx)); break; case FunctionDecl::TK_MemberSpecialization: { - FunctionDecl *InstFD = cast<FunctionDecl>(Reader.GetDecl(Record[Idx++])); + FunctionDecl *InstFD = ReadDeclAs<FunctionDecl>(Record, Idx); TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; SourceLocation POI = ReadSourceLocation(Record, Idx); - FD->setInstantiationOfMemberFunction(*Reader.getContext(), InstFD, TSK); + FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK); FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); break; } case FunctionDecl::TK_FunctionTemplateSpecialization: { - FunctionTemplateDecl *Template - = cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++])); + FunctionTemplateDecl *Template = ReadDeclAs<FunctionTemplateDecl>(Record, + Idx); TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; // Template arguments. - llvm::SmallVector<TemplateArgument, 8> TemplArgs; + SmallVector<TemplateArgument, 8> TemplArgs; Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); // Template args as written. - llvm::SmallVector<TemplateArgumentLoc, 8> TemplArgLocs; + SmallVector<TemplateArgumentLoc, 8> TemplArgLocs; SourceLocation LAngleLoc, RAngleLoc; - if (Record[Idx++]) { // TemplateArgumentsAsWritten != 0 + bool HasTemplateArgumentsAsWritten = Record[Idx++]; + if (HasTemplateArgumentsAsWritten) { unsigned NumTemplateArgLocs = Record[Idx++]; TemplArgLocs.reserve(NumTemplateArgLocs); for (unsigned i=0; i != NumTemplateArgLocs; ++i) @@ -372,24 +387,24 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { SourceLocation POI = ReadSourceLocation(Record, Idx); - ASTContext &C = *Reader.getContext(); + ASTContext &C = Reader.getContext(); TemplateArgumentList *TemplArgList = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); - TemplateArgumentListInfo *TemplArgsInfo - = new (C) TemplateArgumentListInfo(LAngleLoc, RAngleLoc); + TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i=0, e = TemplArgLocs.size(); i != e; ++i) - TemplArgsInfo->addArgument(TemplArgLocs[i]); + TemplArgsInfo.addArgument(TemplArgLocs[i]); FunctionTemplateSpecializationInfo *FTInfo = FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK, TemplArgList, - TemplArgsInfo, POI); + HasTemplateArgumentsAsWritten ? &TemplArgsInfo : 0, + POI); FD->TemplateOrSpecialization = FTInfo; if (FD->isCanonicalDecl()) { // if canonical add to template's set. // The template that contains the specializations set. It's not safe to // use getCanonicalDecl on Template since it may still be initializing. FunctionTemplateDecl *CanonTemplate - = cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++])); + = ReadDeclAs<FunctionTemplateDecl>(Record, Idx); // Get the InsertPos by FindNodeOrInsertPos() instead of calling // InsertNode(FTInfo) directly to avoid the getASTContext() call in // FunctionTemplateSpecializationInfo's Profile(). @@ -410,7 +425,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { UnresolvedSet<8> TemplDecls; unsigned NumTemplates = Record[Idx++]; while (NumTemplates--) - TemplDecls.addDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + TemplDecls.addDecl(ReadDeclAs<NamedDecl>(Record, Idx)); // Templates args. TemplateArgumentListInfo TemplArgs; @@ -420,7 +435,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { TemplArgs.setLAngleLoc(ReadSourceLocation(Record, Idx)); TemplArgs.setRAngleLoc(ReadSourceLocation(Record, Idx)); - FD->setDependentTemplateSpecialization(*Reader.getContext(), + FD->setDependentTemplateSpecialization(Reader.getContext(), TemplDecls, TemplArgs); break; } @@ -442,15 +457,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->IsDefaulted = Record[Idx++]; FD->IsExplicitlyDefaulted = Record[Idx++]; FD->HasImplicitReturnZero = Record[Idx++]; + FD->IsConstexpr = Record[Idx++]; FD->EndRangeLoc = ReadSourceLocation(Record, Idx); // Read in the parameters. unsigned NumParams = Record[Idx++]; - llvm::SmallVector<ParmVarDecl *, 16> Params; + SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - FD->setParams(*Reader.getContext(), Params.data(), NumParams); + Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx)); + FD->setParams(Reader.getContext(), Params); } void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { @@ -459,77 +475,87 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { // In practice, this won't be executed (since method definitions // don't occur in header files). MD->setBody(Reader.ReadStmt(F)); - MD->setSelfDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++]))); - MD->setCmdDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++]))); + MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); + MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); } MD->setInstanceMethod(Record[Idx++]); MD->setVariadic(Record[Idx++]); MD->setSynthesized(Record[Idx++]); MD->setDefined(Record[Idx++]); + + MD->IsRedeclaration = Record[Idx++]; + MD->HasRedeclaration = Record[Idx++]; + if (MD->HasRedeclaration) + Reader.getContext().setObjCMethodRedeclaration(MD, + ReadDeclAs<ObjCMethodDecl>(Record, Idx)); + MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); MD->SetRelatedResultType(Record[Idx++]); - MD->setNumSelectorArgs(unsigned(Record[Idx++])); - MD->setResultType(Reader.GetType(Record[Idx++])); + MD->setResultType(Reader.readType(F, Record, Idx)); MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); MD->setEndLoc(ReadSourceLocation(Record, Idx)); unsigned NumParams = Record[Idx++]; - llvm::SmallVector<ParmVarDecl *, 16> Params; + SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams, - NumParams); + Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx)); + + MD->SelLocsKind = Record[Idx++]; + unsigned NumStoredSelLocs = Record[Idx++]; + SmallVector<SourceLocation, 16> SelLocs; + SelLocs.reserve(NumStoredSelLocs); + for (unsigned i = 0; i != NumStoredSelLocs; ++i) + SelLocs.push_back(ReadSourceLocation(Record, Idx)); + + MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs); } void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); - SourceLocation A = ReadSourceLocation(Record, Idx); - SourceLocation B = ReadSourceLocation(Record, Idx); - CD->setAtEndRange(SourceRange(A, B)); + CD->setAtStartLoc(ReadSourceLocation(Record, Idx)); + CD->setAtEndRange(ReadSourceRange(Record, Idx)); } void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { VisitObjCContainerDecl(ID); - ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtrOrNull()); - ID->setSuperClass(cast_or_null<ObjCInterfaceDecl> - (Reader.GetDecl(Record[Idx++]))); + ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull()); + ID->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); // Read the directly referenced protocols and their SourceLocations. unsigned NumProtocols = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols; + SmallVector<ObjCProtocolDecl *, 16> Protocols; Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) - Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector<SourceLocation, 16> ProtoLocs; + Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); + SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) ProtoLocs.push_back(ReadSourceLocation(Record, Idx)); ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(), - *Reader.getContext()); + Reader.getContext()); // Read the transitive closure of protocols referenced by this class. NumProtocols = Record[Idx++]; Protocols.clear(); Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) - Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols, - *Reader.getContext()); + Reader.getContext()); // Read the ivars. unsigned NumIvars = Record[Idx++]; - llvm::SmallVector<ObjCIvarDecl *, 16> IVars; + SmallVector<ObjCIvarDecl *, 16> IVars; IVars.reserve(NumIvars); for (unsigned I = 0; I != NumIvars; ++I) - IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); - ID->setCategoryList( - cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); + IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx)); + ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx)); + // We will rebuild this list lazily. ID->setIvarList(0); ID->setForwardDecl(Record[Idx++]); ID->setImplicitInterfaceDecl(Record[Idx++]); - ID->setClassLoc(ReadSourceLocation(Record, Idx)); ID->setSuperClassLoc(ReadSourceLocation(Record, Idx)); ID->setLocEnd(ReadSourceLocation(Record, Idx)); } @@ -548,16 +574,16 @@ void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { PD->setForwardDecl(Record[Idx++]); PD->setLocEnd(ReadSourceLocation(Record, Idx)); unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); + SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoLocs.push_back(ReadSourceLocation(Record, Idx)); PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); + Reader.getContext()); } void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { @@ -566,57 +592,48 @@ void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { void ASTDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { VisitDecl(CD); - unsigned NumClassRefs = Record[Idx++]; - llvm::SmallVector<ObjCInterfaceDecl *, 16> ClassRefs; - ClassRefs.reserve(NumClassRefs); - for (unsigned I = 0; I != NumClassRefs; ++I) - ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector<SourceLocation, 16> SLocs; - SLocs.reserve(NumClassRefs); - for (unsigned I = 0; I != NumClassRefs; ++I) - SLocs.push_back(ReadSourceLocation(Record, Idx)); - CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(), - NumClassRefs); + ObjCInterfaceDecl *ClassRef = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); + SourceLocation SLoc = ReadSourceLocation(Record, Idx); + CD->setClass(Reader.getContext(), ClassRef, SLoc); } void ASTDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { VisitDecl(FPD); unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); + SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoLocs.push_back(ReadSourceLocation(Record, Idx)); FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); + Reader.getContext()); } void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { VisitObjCContainerDecl(CD); - CD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); + SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoLocs.push_back(ReadSourceLocation(Record, Idx)); CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); - CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); + Reader.getContext()); + CD->NextClassCategory = ReadDeclAs<ObjCCategoryDecl>(Record, Idx); CD->setHasSynthBitfield(Record[Idx++]); - CD->setAtLoc(ReadSourceLocation(Record, Idx)); CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx)); } void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { VisitNamedDecl(CAD); - CAD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); } void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { @@ -631,31 +648,26 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // FIXME: stable encoding D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record[Idx++]); - D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); - D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); - D->setGetterMethodDecl( - cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); - D->setSetterMethodDecl( - cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); - D->setPropertyIvarDecl( - cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + D->setGetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector()); + D->setSetterName(Reader.ReadDeclarationName(F,Record, Idx).getObjCSelector()); + D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx)); + D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx)); + D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx)); } void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { VisitObjCContainerDecl(D); - D->setClassInterface( - cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); } void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); - D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx)); + D->setIdentifier(Reader.GetIdentifierInfo(F, Record, Idx)); } void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); - D->setSuperClass( - cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); llvm::tie(D->IvarInitializers, D->NumIvarInitializers) = Reader.ReadCXXCtorInitializers(F, Record, Idx); D->setHasSynthBitfield(Record[Idx++]); @@ -665,10 +677,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); D->setAtLoc(ReadSourceLocation(Record, Idx)); - D->setPropertyDecl( - cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++]))); - D->PropertyIvarDecl = - cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])); + D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>(Record, Idx)); + D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(Record, Idx); D->IvarLoc = ReadSourceLocation(Record, Idx); D->setGetterCXXConstructor(Reader.ReadExpr(F)); D->setSetterCXXAssignment(Reader.ReadExpr(F)); @@ -683,9 +693,8 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { else if (BitWidthOrInitializer == 2) FD->setInClassInitializer(Reader.ReadExpr(F)); if (!FD->getDeclName()) { - FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); - if (Tmpl) - Reader.getContext()->setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); + if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>(Record, Idx)) + Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); } } @@ -694,10 +703,10 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { FD->ChainingSize = Record[Idx++]; assert(FD->ChainingSize >= 2 && "Anonymous chaining must be >= 2"); - FD->Chaining = new (*Reader.getContext())NamedDecl*[FD->ChainingSize]; + FD->Chaining = new (Reader.getContext())NamedDecl*[FD->ChainingSize]; for (unsigned I = 0; I != FD->ChainingSize; ++I) - FD->Chaining[I] = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx); } void ASTDeclReader::VisitVarDecl(VarDecl *VD) { @@ -715,10 +724,10 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VD->setInit(Reader.ReadExpr(F)); if (Record[Idx++]) { // HasMemberSpecializationInfo. - VarDecl *Tmpl = cast<VarDecl>(Reader.GetDecl(Record[Idx++])); + VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx); TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; SourceLocation POI = ReadSourceLocation(Record, Idx); - Reader.getContext()->setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); + Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); } } @@ -756,18 +765,18 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadStmt(F))); BD->setSignatureAsWritten(GetTypeSourceInfo(Record, Idx)); unsigned NumParams = Record[Idx++]; - llvm::SmallVector<ParmVarDecl *, 16> Params; + SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - BD->setParams(Params.data(), NumParams); + Params.push_back(ReadDeclAs<ParmVarDecl>(Record, Idx)); + BD->setParams(Params); bool capturesCXXThis = Record[Idx++]; unsigned numCaptures = Record[Idx++]; - llvm::SmallVector<BlockDecl::Capture, 16> captures; + SmallVector<BlockDecl::Capture, 16> captures; captures.reserve(numCaptures); for (unsigned i = 0; i != numCaptures; ++i) { - VarDecl *decl = cast<VarDecl>(Reader.GetDecl(Record[Idx++])); + VarDecl *decl = ReadDeclAs<VarDecl>(Record, Idx); unsigned flags = Record[Idx++]; bool byRef = (flags & 1); bool nested = (flags & 2); @@ -775,7 +784,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr)); } - BD->setCaptures(*Reader.getContext(), captures.begin(), + BD->setCaptures(Reader.getContext(), captures.begin(), captures.end(), capturesCXXThis); } @@ -800,9 +809,10 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { D->NextNamespace = Record[Idx++]; bool IsOriginal = Record[Idx++]; + // FIXME: Modules will likely have trouble with pointing directly at + // the original namespace. D->OrigOrAnonNamespace.setInt(IsOriginal); - D->OrigOrAnonNamespace.setPointer( - cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + D->OrigOrAnonNamespace.setPointer(ReadDeclAs<NamespaceDecl>(Record, Idx)); } void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { @@ -810,7 +820,7 @@ void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { D->NamespaceLoc = ReadSourceLocation(Record, Idx); D->IdentLoc = ReadSourceLocation(Record, Idx); D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); - D->Namespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + D->Namespace = ReadDeclAs<NamedDecl>(Record, Idx); } void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { @@ -818,21 +828,19 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { D->setUsingLocation(ReadSourceLocation(Record, Idx)); D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx); - D->FirstUsingShadow = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++])); + D->FirstUsingShadow = ReadDeclAs<UsingShadowDecl>(Record, Idx); D->setTypeName(Record[Idx++]); - NamedDecl *Pattern = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); - if (Pattern) - Reader.getContext()->setInstantiatedFromUsingDecl(D, Pattern); + if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx)) + Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern); } void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitNamedDecl(D); - D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); - D->UsingOrNextShadow = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); - UsingShadowDecl *Pattern - = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++])); + D->setTargetDecl(ReadDeclAs<NamedDecl>(Record, Idx)); + D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(Record, Idx); + UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>(Record, Idx); if (Pattern) - Reader.getContext()->setInstantiatedFromUsingShadowDecl(D, Pattern); + Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern); } void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { @@ -840,8 +848,8 @@ void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { D->UsingLoc = ReadSourceLocation(Record, Idx); D->NamespaceLoc = ReadSourceLocation(Record, Idx); D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); - D->NominatedNamespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); - D->CommonAncestor = cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])); + D->NominatedNamespace = ReadDeclAs<NamedDecl>(Record, Idx); + D->CommonAncestor = ReadDeclAs<DeclContext>(Record, Idx); } void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { @@ -863,7 +871,9 @@ void ASTDeclReader::ReadCXXDefinitionData( const RecordData &Record, unsigned &Idx) { Data.UserDeclaredConstructor = Record[Idx++]; Data.UserDeclaredCopyConstructor = Record[Idx++]; + Data.UserDeclaredMoveConstructor = Record[Idx++]; Data.UserDeclaredCopyAssignment = Record[Idx++]; + Data.UserDeclaredMoveAssignment = Record[Idx++]; Data.UserDeclaredDestructor = Record[Idx++]; Data.Aggregate = Record[Idx++]; Data.PlainOldData = Record[Idx++]; @@ -877,7 +887,7 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasPublicFields = Record[Idx++]; Data.HasMutableFields = Record[Idx++]; Data.HasTrivialDefaultConstructor = Record[Idx++]; - Data.HasConstExprNonCopyMoveConstructor = Record[Idx++]; + Data.HasConstexprNonCopyMoveConstructor = Record[Idx++]; Data.HasTrivialCopyConstructor = Record[Idx++]; Data.HasTrivialMoveConstructor = Record[Idx++]; Data.HasTrivialCopyAssignment = Record[Idx++]; @@ -888,28 +898,31 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.UserProvidedDefaultConstructor = Record[Idx++]; Data.DeclaredDefaultConstructor = Record[Idx++]; Data.DeclaredCopyConstructor = Record[Idx++]; + Data.DeclaredMoveConstructor = Record[Idx++]; Data.DeclaredCopyAssignment = Record[Idx++]; + Data.DeclaredMoveAssignment = Record[Idx++]; Data.DeclaredDestructor = Record[Idx++]; + Data.FailedImplicitMoveConstructor = Record[Idx++]; + Data.FailedImplicitMoveAssignment = Record[Idx++]; Data.NumBases = Record[Idx++]; if (Data.NumBases) - Data.Bases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]); + Data.Bases = Reader.readCXXBaseSpecifiers(F, Record, Idx); Data.NumVBases = Record[Idx++]; if (Data.NumVBases) - Data.VBases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]); + Data.VBases = Reader.readCXXBaseSpecifiers(F, Record, Idx); - Reader.ReadUnresolvedSet(Data.Conversions, Record, Idx); - Reader.ReadUnresolvedSet(Data.VisibleConversions, Record, Idx); + Reader.ReadUnresolvedSet(F, Data.Conversions, Record, Idx); + Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx); assert(Data.Definition && "Data.Definition should be already set!"); - Data.FirstFriend - = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++])); + Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx); } void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D, CXXRecordDecl *DefinitionDecl, const RecordData &Record, unsigned &Idx) { - ASTContext &C = *Reader.getContext(); + ASTContext &C = Reader.getContext(); if (D == DefinitionDecl) { D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D); @@ -942,26 +955,24 @@ void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D, void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { VisitRecordDecl(D); - CXXRecordDecl *DefinitionDecl - = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); + CXXRecordDecl *DefinitionDecl = ReadDeclAs<CXXRecordDecl>(Record, Idx); InitializeCXXDefinitionData(D, DefinitionDecl, Record, Idx); - ASTContext &C = *Reader.getContext(); + ASTContext &C = Reader.getContext(); enum CXXRecKind { CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization }; switch ((CXXRecKind)Record[Idx++]) { default: - assert(false && "Out of sync with ASTDeclWriter::VisitCXXRecordDecl?"); + llvm_unreachable("Out of sync with ASTDeclWriter::VisitCXXRecordDecl?"); case CXXRecNotTemplate: break; case CXXRecTemplate: - D->TemplateOrInstantiation - = cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++])); + D->TemplateOrInstantiation = ReadDeclAs<ClassTemplateDecl>(Record, Idx); break; case CXXRecMemberSpecialization: { - CXXRecordDecl *RD = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); + CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx); TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; SourceLocation POI = ReadSourceLocation(Record, Idx); MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK); @@ -973,10 +984,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { // Load the key function to avoid deserializing every method so we can // compute it. - if (D->IsDefinition) { - CXXMethodDecl *Key - = cast_or_null<CXXMethodDecl>(Reader.GetDecl(Record[Idx++])); - if (Key) + if (D->IsCompleteDefinition) { + if (CXXMethodDecl *Key = ReadDeclAs<CXXMethodDecl>(Record, Idx)) C.KeyFunctions[D] = Key; } } @@ -985,10 +994,10 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); unsigned NumOverridenMethods = Record[Idx++]; while (NumOverridenMethods--) { - CXXMethodDecl *MD = cast<CXXMethodDecl>(Reader.GetDecl(Record[Idx++])); // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod, // MD may be initializing. - Reader.getContext()->addOverriddenMethod(D, MD); + if (CXXMethodDecl *MD = ReadDeclAs<CXXMethodDecl>(Record, Idx)) + Reader.getContext().addOverriddenMethod(D, MD); } } @@ -1005,7 +1014,7 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); D->ImplicitlyDefined = Record[Idx++]; - D->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])); + D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx); } void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { @@ -1023,7 +1032,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { if (Record[Idx++]) D->Friend = GetTypeSourceInfo(Record, Idx); else - D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + D->Friend = ReadDeclAs<NamedDecl>(Record, Idx); D->NextFriend = Record[Idx++]; D->UnsupportedFriend = (Record[Idx++] != 0); D->FriendLoc = ReadSourceLocation(Record, Idx); @@ -1037,7 +1046,7 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { for (unsigned i = 0; i != NumParams; ++i) D->Params[i] = Reader.ReadTemplateParameterList(F, Record, Idx); if (Record[Idx++]) // HasFriendDecl - D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + D->Friend = ReadDeclAs<NamedDecl>(Record, Idx); else D->Friend = GetTypeSourceInfo(Record, Idx); D->FriendLoc = ReadSourceLocation(Record, Idx); @@ -1046,8 +1055,7 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { VisitNamedDecl(D); - NamedDecl *TemplatedDecl - = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); + NamedDecl *TemplatedDecl = ReadDeclAs<NamedDecl>(Record, Idx); TemplateParameterList* TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); D->init(TemplatedDecl, TemplateParams); @@ -1058,8 +1066,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // can be used while this is still initializing. assert(D->CommonOrPrev.isNull() && "getCommonPtr was called earlier on this"); - DeclID PreviousDeclID = Record[Idx++]; - DeclID FirstDeclID = PreviousDeclID ? Record[Idx++] : 0; + DeclID PreviousDeclID = ReadDeclID(Record, Idx); + DeclID FirstDeclID = PreviousDeclID ? ReadDeclID(Record, Idx) : 0; // We delay loading of the redeclaration chain to avoid deeply nested calls. // We temporarily set the first (canonical) declaration as the previous one // which is the one that matters and mark the real previous DeclID to be @@ -1074,9 +1082,9 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { if (PreviousDeclID != FirstDeclID) Reader.PendingPreviousDecls.push_back(std::make_pair(D, PreviousDeclID)); } else { - D->CommonOrPrev = D->newCommon(*Reader.getContext()); + D->CommonOrPrev = D->newCommon(Reader.getContext()); if (RedeclarableTemplateDecl *RTD - = cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]))) { + = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx)) { assert(RTD->getKind() == D->getKind() && "InstantiatedFromMemberTemplate kind mismatch"); D->setInstantiatedFromMemberTemplateImpl(RTD); @@ -1084,8 +1092,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { D->setMemberSpecialization(); } - RedeclarableTemplateDecl *LatestDecl = - cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++])); + RedeclarableTemplateDecl *LatestDecl + = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx); // This decl is a first one and the latest declaration that it points to is // in the same AST file. However, if this actually needs to point to a @@ -1095,14 +1103,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { ASTReader::FirstLatestDeclIDMap::iterator I = Reader.FirstLatestDeclIDs.find(ThisDeclID); if (I != Reader.FirstLatestDeclIDs.end()) { - Decl *NewLatest = Reader.GetDecl(I->second); - assert((LatestDecl->getLocation().isInvalid() || - NewLatest->getLocation().isInvalid() || - !Reader.SourceMgr.isBeforeInTranslationUnit( - NewLatest->getLocation(), - LatestDecl->getLocation())) && - "The new latest is supposed to come after the previous latest"); - LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest); + if (Decl *NewLatest = Reader.GetDecl(I->second)) + LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest); } assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch"); @@ -1119,27 +1121,27 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (D->getPreviousDeclaration() == 0) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - llvm::SmallVector<serialization::DeclID, 2> SpecIDs; + SmallVector<serialization::DeclID, 2> SpecIDs; SpecIDs.push_back(0); // Specializations. unsigned Size = Record[Idx++]; SpecIDs[0] += Size; - SpecIDs.append(Record.begin() + Idx, Record.begin() + Idx + Size); - Idx += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); // Partial specializations. Size = Record[Idx++]; SpecIDs[0] += Size; - SpecIDs.append(Record.begin() + Idx, Record.begin() + Idx + Size); - Idx += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); if (SpecIDs[0]) { typedef serialization::DeclID DeclID; ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr(); CommonPtr->LazySpecializations - = new (*Reader.getContext()) DeclID [SpecIDs.size()]; + = new (Reader.getContext()) DeclID [SpecIDs.size()]; memcpy(CommonPtr->LazySpecializations, SpecIDs.data(), SpecIDs.size() * sizeof(DeclID)); } @@ -1152,12 +1154,12 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { VisitCXXRecordDecl(D); - ASTContext &C = *Reader.getContext(); - if (Decl *InstD = Reader.GetDecl(Record[Idx++])) { + ASTContext &C = Reader.getContext(); + if (Decl *InstD = ReadDecl(Record, Idx)) { if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(InstD)) { D->SpecializedTemplate = CTD; } else { - llvm::SmallVector<TemplateArgument, 8> TemplArgs; + SmallVector<TemplateArgument, 8> TemplArgs; Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), @@ -1182,7 +1184,7 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl( D->ExplicitInfo = ExplicitInfo; } - llvm::SmallVector<TemplateArgument, 8> TemplArgs; + SmallVector<TemplateArgument, 8> TemplArgs; Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); @@ -1190,8 +1192,7 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl( D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++]; if (D->isCanonicalDecl()) { // It's kept in the folding set. - ClassTemplateDecl *CanonPattern - = cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++])); + ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx); if (ClassTemplatePartialSpecializationDecl *Partial = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { CanonPattern->getCommonPtr()->PartialSpecializations.InsertNode(Partial); @@ -1205,7 +1206,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { VisitClassTemplateSpecializationDecl(D); - ASTContext &C = *Reader.getContext(); + ASTContext &C = Reader.getContext(); D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); unsigned NumArgs = Record[Idx++]; @@ -1221,12 +1222,17 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( // These are read/set from/to the first declaration. if (D->getPreviousDeclaration() == 0) { D->InstantiatedFromMember.setPointer( - cast_or_null<ClassTemplatePartialSpecializationDecl>( - Reader.GetDecl(Record[Idx++]))); + ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx)); D->InstantiatedFromMember.setInt(Record[Idx++]); } } +void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D) { + VisitDecl(D); + D->Specialization = ReadDeclAs<CXXMethodDecl>(Record, Idx); +} + void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); @@ -1238,7 +1244,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // when reading the specialized FunctionDecl. unsigned NumSpecs = Record[Idx++]; while (NumSpecs--) - Reader.GetDecl(Record[Idx++]); + (void)ReadDecl(Record, Idx); } } @@ -1260,7 +1266,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { if (D->isExpandedParameterPack()) { void **Data = reinterpret_cast<void **>(D + 1); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { - Data[2*I] = Reader.GetType(Record[Idx++]).getAsOpaquePtr(); + Data[2*I] = Reader.readType(F, Record, Idx).getAsOpaquePtr(); Data[2*I + 1] = GetTypeSourceInfo(Record, Idx); } } else { @@ -1310,13 +1316,13 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { RedeclKind Kind = (RedeclKind)Record[Idx++]; switch (Kind) { default: - assert(0 && "Out of sync with ASTDeclWriter::VisitRedeclarable or messed up" - " reading"); + llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or" + " messed up reading"); case NoRedeclaration: break; case PointsToPrevious: { - DeclID PreviousDeclID = Record[Idx++]; - DeclID FirstDeclID = Record[Idx++]; + DeclID PreviousDeclID = ReadDeclID(Record, Idx); + DeclID FirstDeclID = ReadDeclID(Record, Idx); // We delay loading of the redeclaration chain to avoid deeply nested calls. // We temporarily set the first (canonical) declaration as the previous one // which is the one that matters and mark the real previous DeclID to be @@ -1330,7 +1336,7 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { } case PointsToLatest: D->RedeclLink = typename Redeclarable<T>::LatestDeclLink( - cast_or_null<T>(Reader.GetDecl(Record[Idx++]))); + ReadDeclAs<T>(Record, Idx)); break; } @@ -1361,12 +1367,12 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { //===----------------------------------------------------------------------===// /// \brief Reads attributes from the current stream position. -void ASTReader::ReadAttributes(PerFileData &F, AttrVec &Attrs, +void ASTReader::ReadAttributes(Module &F, AttrVec &Attrs, const RecordData &Record, unsigned &Idx) { for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) { Attr *New = 0; attr::Kind Kind = (attr::Kind)Record[Idx++]; - SourceLocation Loc = ReadSourceLocation(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); #include "clang/Serialization/AttrPCHRead.inc" @@ -1398,33 +1404,47 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) { /// code generation, e.g., inline function definitions, Objective-C /// declarations with metadata, etc. static bool isConsumerInterestedIn(Decl *D) { - if (isa<FileScopeAsmDecl>(D)) + // An ObjCMethodDecl is never considered as "interesting" because its + // implementation container always is. + + if (isa<FileScopeAsmDecl>(D) || + isa<ObjCProtocolDecl>(D) || + isa<ObjCImplDecl>(D)) return true; if (VarDecl *Var = dyn_cast<VarDecl>(D)) return Var->isFileVarDecl() && Var->isThisDeclarationADefinition() == VarDecl::Definition; if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) return Func->doesThisDeclarationHaveABody(); - return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D); + + return false; } -/// \brief Get the correct cursor and offset for loading a type. +/// \brief Get the correct cursor and offset for loading a declaration. ASTReader::RecordLocation -ASTReader::DeclCursorForIndex(unsigned Index, DeclID ID) { +ASTReader::DeclCursorForID(DeclID ID) { // See if there's an override. DeclReplacementMap::iterator It = ReplacedDecls.find(ID); if (It != ReplacedDecls.end()) return RecordLocation(It->second.first, It->second.second); - PerFileData *F = 0; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - F = Chain[N - I - 1]; - if (Index < F->LocalNumDecls) - break; - Index -= F->LocalNumDecls; - } - assert(F && F->LocalNumDecls > Index && "Broken chain"); - return RecordLocation(F, F->DeclOffsets[Index]); + GlobalDeclMapType::iterator I = GlobalDeclMap.find(ID); + assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); + Module *M = I->second; + return RecordLocation(M, + M->DeclOffsets[ID - M->BaseDeclID - NUM_PREDEF_DECL_IDS]); +} + +ASTReader::RecordLocation ASTReader::getLocalBitOffset(uint64_t GlobalOffset) { + ContinuousRangeMap<uint64_t, Module*, 4>::iterator I + = GlobalBitOffsetsMap.find(GlobalOffset); + + assert(I != GlobalBitOffsetsMap.end() && "Corrupted global bit offsets map"); + return RecordLocation(I->second, GlobalOffset - I->second->GlobalBitOffset); +} + +uint64_t ASTReader::getGlobalBitOffset(Module &M, uint32_t LocalOffset) { + return LocalOffset + M.GlobalBitOffset; } void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { @@ -1447,8 +1467,9 @@ void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) { } /// \brief Read the declaration at the given offset from the AST file. -Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { - RecordLocation Loc = DeclCursorForIndex(Index, ID); +Decl *ASTReader::ReadDeclRecord(DeclID ID) { + unsigned Index = ID - NUM_PREDEF_DECL_IDS; + RecordLocation Loc = DeclCursorForID(ID); llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; // Keep track of where we are in the stream, then jump back there // after reading this declaration. @@ -1469,215 +1490,216 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: - assert(false && "Record cannot be de-serialized with ReadDeclRecord"); - break; - case DECL_TRANSLATION_UNIT: - assert(Index == 0 && "Translation unit must be at index 0"); - D = Context->getTranslationUnitDecl(); - break; + llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord"); case DECL_TYPEDEF: - D = TypedefDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + D = TypedefDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, 0); break; case DECL_TYPEALIAS: - D = TypeAliasDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + D = TypeAliasDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, 0); break; case DECL_ENUM: - D = EnumDecl::Create(*Context, Decl::EmptyShell()); + D = EnumDecl::Create(Context, Decl::EmptyShell()); break; case DECL_RECORD: - D = RecordDecl::Create(*Context, Decl::EmptyShell()); + D = RecordDecl::Create(Context, Decl::EmptyShell()); break; case DECL_ENUM_CONSTANT: - D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), + D = EnumConstantDecl::Create(Context, 0, SourceLocation(), 0, QualType(), 0, llvm::APSInt()); break; case DECL_FUNCTION: - D = FunctionDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + D = FunctionDecl::Create(Context, 0, SourceLocation(), SourceLocation(), DeclarationName(), QualType(), 0); break; case DECL_LINKAGE_SPEC: - D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + D = LinkageSpecDecl::Create(Context, 0, SourceLocation(), SourceLocation(), (LinkageSpecDecl::LanguageIDs)0, SourceLocation()); break; case DECL_LABEL: - D = LabelDecl::Create(*Context, 0, SourceLocation(), 0); + D = LabelDecl::Create(Context, 0, SourceLocation(), 0); break; case DECL_NAMESPACE: - D = NamespaceDecl::Create(*Context, 0, SourceLocation(), + D = NamespaceDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0); break; case DECL_NAMESPACE_ALIAS: - D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(), + D = NamespaceAliasDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, NestedNameSpecifierLoc(), SourceLocation(), 0); break; case DECL_USING: - D = UsingDecl::Create(*Context, 0, SourceLocation(), + D = UsingDecl::Create(Context, 0, SourceLocation(), NestedNameSpecifierLoc(), DeclarationNameInfo(), false); break; case DECL_USING_SHADOW: - D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = UsingShadowDecl::Create(Context, 0, SourceLocation(), 0, 0); break; case DECL_USING_DIRECTIVE: - D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(), + D = UsingDirectiveDecl::Create(Context, 0, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), 0, 0); break; case DECL_UNRESOLVED_USING_VALUE: - D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(), + D = UnresolvedUsingValueDecl::Create(Context, 0, SourceLocation(), NestedNameSpecifierLoc(), DeclarationNameInfo()); break; case DECL_UNRESOLVED_USING_TYPENAME: - D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(), + D = UnresolvedUsingTypenameDecl::Create(Context, 0, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), DeclarationName()); break; case DECL_CXX_RECORD: - D = CXXRecordDecl::Create(*Context, Decl::EmptyShell()); + D = CXXRecordDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CXX_METHOD: - D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), + D = CXXMethodDecl::Create(Context, 0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, - false, SC_None, false, SourceLocation()); + false, SC_None, false, false, SourceLocation()); break; case DECL_CXX_CONSTRUCTOR: - D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); + D = CXXConstructorDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CXX_DESTRUCTOR: - D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell()); + D = CXXDestructorDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CXX_CONVERSION: - D = CXXConversionDecl::Create(*Context, Decl::EmptyShell()); + D = CXXConversionDecl::Create(Context, Decl::EmptyShell()); break; case DECL_ACCESS_SPEC: - D = AccessSpecDecl::Create(*Context, Decl::EmptyShell()); + D = AccessSpecDecl::Create(Context, Decl::EmptyShell()); break; case DECL_FRIEND: - D = FriendDecl::Create(*Context, Decl::EmptyShell()); + D = FriendDecl::Create(Context, Decl::EmptyShell()); break; case DECL_FRIEND_TEMPLATE: - D = FriendTemplateDecl::Create(*Context, Decl::EmptyShell()); + D = FriendTemplateDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE: - D = ClassTemplateDecl::Create(*Context, Decl::EmptyShell()); + D = ClassTemplateDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_SPECIALIZATION: - D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell()); + D = ClassTemplateSpecializationDecl::Create(Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: - D = ClassTemplatePartialSpecializationDecl::Create(*Context, + D = ClassTemplatePartialSpecializationDecl::Create(Context, Decl::EmptyShell()); break; + case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION: + D = ClassScopeFunctionSpecializationDecl::Create(Context, + Decl::EmptyShell()); + break; case DECL_FUNCTION_TEMPLATE: - D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell()); + D = FunctionTemplateDecl::Create(Context, Decl::EmptyShell()); break; case DECL_TEMPLATE_TYPE_PARM: - D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell()); + D = TemplateTypeParmDecl::Create(Context, Decl::EmptyShell()); break; case DECL_NON_TYPE_TEMPLATE_PARM: - D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), + D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, 0, 0, QualType(), false, 0); break; case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: - D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), + D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, 0, 0, QualType(), 0, 0, Record[Idx++], 0); break; case DECL_TEMPLATE_TEMPLATE_PARM: - D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, + D = TemplateTemplateParmDecl::Create(Context, 0, SourceLocation(), 0, 0, false, 0, 0); break; case DECL_TYPE_ALIAS_TEMPLATE: - D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell()); + D = TypeAliasTemplateDecl::Create(Context, Decl::EmptyShell()); break; case DECL_STATIC_ASSERT: - D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0, + D = StaticAssertDecl::Create(Context, 0, SourceLocation(), 0, 0, SourceLocation()); break; case DECL_OBJC_METHOD: - D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(), + D = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(), Selector(), QualType(), 0, 0); break; case DECL_OBJC_INTERFACE: - D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0); + D = ObjCInterfaceDecl::Create(Context, 0, SourceLocation(), 0); break; case DECL_OBJC_IVAR: - D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, ObjCIvarDecl::None); break; case DECL_OBJC_PROTOCOL: - D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0); + D = ObjCProtocolDecl::Create(Context, 0, 0, SourceLocation(), + SourceLocation()); break; case DECL_OBJC_AT_DEFS_FIELD: - D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), + D = ObjCAtDefsFieldDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0); break; case DECL_OBJC_CLASS: - D = ObjCClassDecl::Create(*Context, 0, SourceLocation()); + D = ObjCClassDecl::Create(Context, 0, SourceLocation()); break; case DECL_OBJC_FORWARD_PROTOCOL: - D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation()); + D = ObjCForwardProtocolDecl::Create(Context, 0, SourceLocation()); break; case DECL_OBJC_CATEGORY: - D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), SourceLocation(), 0); + D = ObjCCategoryDecl::Create(Context, Decl::EmptyShell()); break; case DECL_OBJC_CATEGORY_IMPL: - D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = ObjCCategoryImplDecl::Create(Context, 0, 0, 0, SourceLocation(), + SourceLocation()); break; case DECL_OBJC_IMPLEMENTATION: - D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = ObjCImplementationDecl::Create(Context, 0, 0, 0, SourceLocation(), + SourceLocation()); break; case DECL_OBJC_COMPATIBLE_ALIAS: - D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = ObjCCompatibleAliasDecl::Create(Context, 0, SourceLocation(), 0, 0); break; case DECL_OBJC_PROPERTY: - D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), + D = ObjCPropertyDecl::Create(Context, 0, SourceLocation(), 0, SourceLocation(), 0); break; case DECL_OBJC_PROPERTY_IMPL: - D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(), + D = ObjCPropertyImplDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, ObjCPropertyImplDecl::Dynamic, 0, SourceLocation()); break; case DECL_FIELD: - D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + D = FieldDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, 0, false, false); break; case DECL_INDIRECTFIELD: - D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), + D = IndirectFieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(), 0, 0); break; case DECL_VAR: - D = VarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + D = VarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, SC_None, SC_None); break; case DECL_IMPLICIT_PARAM: - D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + D = ImplicitParamDecl::Create(Context, 0, SourceLocation(), 0, QualType()); break; case DECL_PARM_VAR: - D = ParmVarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + D = ParmVarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, SC_None, SC_None, 0); break; case DECL_FILE_SCOPE_ASM: - D = FileScopeAsmDecl::Create(*Context, 0, 0, SourceLocation(), + D = FileScopeAsmDecl::Create(Context, 0, 0, SourceLocation(), SourceLocation()); break; case DECL_BLOCK: - D = BlockDecl::Create(*Context, 0, SourceLocation()); + D = BlockDecl::Create(Context, 0, SourceLocation()); break; case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); @@ -1693,16 +1715,13 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { if (DeclContext *DC = dyn_cast<DeclContext>(D)) { std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); if (Offsets.first || Offsets.second) { - DC->setHasExternalLexicalStorage(Offsets.first != 0); - DC->setHasExternalVisibleStorage(Offsets.second != 0); - DeclContextInfo Info; - if (ReadDeclContextStorage(DeclsCursor, Offsets, Info)) + if (Offsets.first != 0) + DC->setHasExternalLexicalStorage(true); + if (Offsets.second != 0) + DC->setHasExternalVisibleStorage(true); + if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets, + Loc.F->DeclContextInfos[DC])) return 0; - DeclContextInfos &Infos = DeclContextOffsets[DC]; - // Reading the TU will happen after reading its lexical update blocks, - // so we need to make sure we insert in front. For all other contexts, - // the vector is empty here anyway, so there's no loss in efficiency. - Infos.insert(Infos.begin(), Info); } // Now add the pending visible updates for this decl context, if it has any. @@ -1713,20 +1732,32 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { // storage, even if the original stored version didn't. DC->setHasExternalVisibleStorage(true); DeclContextVisibleUpdates &U = I->second; - DeclContextInfos &Infos = DeclContextOffsets[DC]; - DeclContextInfo Info; - Info.LexicalDecls = 0; - Info.NumLexicalDecls = 0; for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end(); UI != UE; ++UI) { - Info.NameLookupTableData = *UI; - Infos.push_back(Info); + UI->second->DeclContextInfos[DC].NameLookupTableData = UI->first; } PendingVisibleUpdates.erase(I); } } assert(Idx == Record.size()); + // Load any relevant update records. + loadDeclUpdateRecords(ID, D); + + if (ObjCChainedCategoriesInterfaces.count(ID)) + loadObjCChainedCategories(ID, cast<ObjCInterfaceDecl>(D)); + + // If we have deserialized a declaration that has a definition the + // AST consumer might need to know about, queue it. + // We don't pass it to the consumer immediately because we may be in recursive + // loading, and some declarations may still be initializing. + if (isConsumerInterestedIn(D)) + InterestingDecls.push_back(D); + + return D; +} + +void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { // The declaration may have been modified by files later in the chain. // If this is the case, read the record containing the updates from each file // and pass it to ASTDeclReader to make the modifications. @@ -1734,8 +1765,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { if (UpdI != DeclUpdateOffsets.end()) { FileOffsetsTy &UpdateOffsets = UpdI->second; for (FileOffsetsTy::iterator - I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) { - PerFileData *F = I->first; + I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) { + Module *F = I->first; uint64_t Offset = I->second; llvm::BitstreamCursor &Cursor = F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); @@ -1745,45 +1776,166 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { unsigned RecCode = Cursor.ReadRecord(Code, Record); (void)RecCode; assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!"); + + unsigned Idx = 0; + ASTDeclReader Reader(*this, *F, Cursor, ID, Record, Idx); Reader.UpdateDecl(D, *F, Record); } } +} - // If we have deserialized a declaration that has a definition the - // AST consumer might need to know about, queue it. - // We don't pass it to the consumer immediately because we may be in recursive - // loading, and some declarations may still be initializing. - if (isConsumerInterestedIn(D)) - InterestingDecls.push_back(D); +namespace { + /// \brief Given an ObjC interface, goes through the modules and links to the + /// interface all the categories for it. + class ObjCChainedCategoriesVisitor { + ASTReader &Reader; + serialization::GlobalDeclID InterfaceID; + ObjCInterfaceDecl *Interface; + ObjCCategoryDecl *GlobHeadCat, *GlobTailCat; + llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap; - return D; + public: + ObjCChainedCategoriesVisitor(ASTReader &Reader, + serialization::GlobalDeclID InterfaceID, + ObjCInterfaceDecl *Interface) + : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface), + GlobHeadCat(0), GlobTailCat(0) { } + + static bool visit(Module &M, void *UserData) { + return static_cast<ObjCChainedCategoriesVisitor *>(UserData)->visit(M); + } + + bool visit(Module &M) { + if (Reader.isDeclIDFromModule(InterfaceID, M)) + return true; // We reached the module where the interface originated + // from. Stop traversing the imported modules. + + Module::ChainedObjCCategoriesMap::iterator + I = M.ChainedObjCCategories.find(InterfaceID); + if (I == M.ChainedObjCCategories.end()) + return false; + + ObjCCategoryDecl * + HeadCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.first); + ObjCCategoryDecl * + TailCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.second); + + addCategories(HeadCat, TailCat); + return false; + } + + void addCategories(ObjCCategoryDecl *HeadCat, + ObjCCategoryDecl *TailCat = 0) { + if (!HeadCat) { + assert(!TailCat); + return; + } + + if (!TailCat) { + TailCat = HeadCat; + while (TailCat->getNextClassCategory()) + TailCat = TailCat->getNextClassCategory(); + } + + if (!GlobHeadCat) { + GlobHeadCat = HeadCat; + GlobTailCat = TailCat; + } else { + ASTDeclReader::setNextObjCCategory(GlobTailCat, HeadCat); + GlobTailCat = TailCat; + } + + llvm::DenseSet<DeclarationName> Checked; + for (ObjCCategoryDecl *Cat = HeadCat, + *CatEnd = TailCat->getNextClassCategory(); + Cat != CatEnd; Cat = Cat->getNextClassCategory()) { + if (Checked.count(Cat->getDeclName())) + continue; + Checked.insert(Cat->getDeclName()); + checkForDuplicate(Cat); + } + } + + /// \brief Warns for duplicate categories that come from different modules. + void checkForDuplicate(ObjCCategoryDecl *Cat) { + DeclarationName Name = Cat->getDeclName(); + // Find the top category with the same name. We do not want to warn for + // duplicates along the established chain because there were already + // warnings for them when the module was created. We only want to warn for + // duplicates between non-dependent modules: + // + // MT // + // / \ // + // ML MR // + // + // We want to warn for duplicates between ML and MR,not between ML and MT. + // + // FIXME: We should not warn for duplicates in diamond: + // + // MT // + // / \ // + // ML MR // + // \ / // + // MB // + // + // If there are duplicates in ML/MR, there will be warning when creating + // MB *and* when importing MB. We should not warn when importing. + for (ObjCCategoryDecl *Next = Cat->getNextClassCategory(); Next; + Next = Next->getNextClassCategory()) { + if (Next->getDeclName() == Name) + Cat = Next; + } + + ObjCCategoryDecl *&PrevCat = NameCategoryMap[Name]; + if (!PrevCat) + PrevCat = Cat; + + if (PrevCat != Cat) { + Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def) + << Interface->getDeclName() << Name; + Reader.Diag(PrevCat->getLocation(), diag::note_previous_definition); + } + } + + ObjCCategoryDecl *getHeadCategory() const { return GlobHeadCat; } + }; +} + +void ASTReader::loadObjCChainedCategories(serialization::GlobalDeclID ID, + ObjCInterfaceDecl *D) { + ObjCChainedCategoriesVisitor Visitor(*this, ID, D); + ModuleMgr.visit(ObjCChainedCategoriesVisitor::visit, &Visitor); + // Also add the categories that the interface already links to. + Visitor.addCategories(D->getCategoryList()); + D->setCategoryList(Visitor.getHeadCategory()); } -void ASTDeclReader::UpdateDecl(Decl *D, ASTReader::PerFileData &Module, +void ASTDeclReader::UpdateDecl(Decl *D, Module &Module, const RecordData &Record) { unsigned Idx = 0; while (Idx < Record.size()) { switch ((DeclUpdateKind)Record[Idx++]) { case UPD_CXX_SET_DEFINITIONDATA: { CXXRecordDecl *RD = cast<CXXRecordDecl>(D); - CXXRecordDecl * - DefinitionDecl = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); + CXXRecordDecl *DefinitionDecl + = Reader.ReadDeclAs<CXXRecordDecl>(Module, Record, Idx); assert(!RD->DefinitionData && "DefinitionData is already set!"); InitializeCXXDefinitionData(RD, DefinitionDecl, Record, Idx); break; } case UPD_CXX_ADDED_IMPLICIT_MEMBER: - cast<CXXRecordDecl>(D)->addedMember(Reader.GetDecl(Record[Idx++])); + cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(Module, Record, Idx)); break; case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: // It will be added to the template's specializations set when loaded. - Reader.GetDecl(Record[Idx++]); + (void)Reader.ReadDecl(Module, Record, Idx); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { - NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(Record[Idx++])); + NamespaceDecl *Anon + = Reader.ReadDeclAs<NamespaceDecl>(Module, Record, Idx); // Guard against these being loaded out of original order. Don't use // getNextNamespace(), since it tries to access the context and can't in // the middle of deserialization. diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h new file mode 100644 index 0000000..99e8be5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h @@ -0,0 +1,243 @@ +//===--- ASTReaderInternals.h - AST Reader Internals ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides internal definitions used in the AST reader. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H +#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H + +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/AST/DeclarationName.h" +#include <utility> +#include <sys/stat.h> + +namespace clang { + +class ASTReader; +class HeaderSearch; +struct HeaderFileInfo; + +namespace serialization { + +class Module; + +namespace reader { + +/// \brief Class that performs name lookup into a DeclContext stored +/// in an AST file. +class ASTDeclContextNameLookupTrait { + ASTReader &Reader; + Module &F; + +public: + /// \brief Pair of begin/end iterators for DeclIDs. + /// + /// Note that these declaration IDs are local to the module that contains this + /// particular lookup t + typedef std::pair<DeclID *, DeclID *> data_type; + + /// \brief Special internal key for declaration names. + /// The hash table creates keys for comparison; we do not create + /// a DeclarationName for the internal key to avoid deserializing types. + struct DeclNameKey { + DeclarationName::NameKind Kind; + uint64_t Data; + DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { } + }; + + typedef DeclarationName external_key_type; + typedef DeclNameKey internal_key_type; + + explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, + Module &F) + : Reader(Reader), F(F) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a.Kind == b.Kind && a.Data == b.Data; + } + + unsigned ComputeHash(const DeclNameKey &Key) const; + internal_key_type GetInternalKey(const external_key_type& Name) const; + external_key_type GetExternalKey(const internal_key_type& Key) const; + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d); + + internal_key_type ReadKey(const unsigned char* d, unsigned); + + data_type ReadData(internal_key_type, const unsigned char* d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used for the DeclContext's Name lookup table. +typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait> + ASTDeclContextNameLookupTable; + +/// \brief Class that performs lookup for an identifier stored in an AST file. +class ASTIdentifierLookupTrait { + ASTReader &Reader; + Module &F; + + // If we know the IdentifierInfo in advance, it is here and we will + // not build a new one. Used when deserializing information about an + // identifier that was constructed before the AST file was read. + IdentifierInfo *KnownII; + +public: + typedef IdentifierInfo * data_type; + + typedef const std::pair<const char*, unsigned> external_key_type; + + typedef external_key_type internal_key_type; + + ASTIdentifierLookupTrait(ASTReader &Reader, Module &F, + IdentifierInfo *II = 0) + : Reader(Reader), F(F), KnownII(II) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 + : false; + } + + static unsigned ComputeHash(const internal_key_type& a); + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + // This hopefully will just get inlined and removed by the optimizer. + static const external_key_type& + GetExternalKey(const internal_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d); + + static std::pair<const char*, unsigned> + ReadKey(const unsigned char* d, unsigned n); + + IdentifierInfo *ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used to contain information about +/// all of the identifiers in the program. +typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait> + ASTIdentifierLookupTable; + +/// \brief Class that performs lookup for a selector's entries in the global +/// method pool stored in an AST file. +class ASTSelectorLookupTrait { + ASTReader &Reader; + Module &F; + +public: + struct data_type { + SelectorID ID; + llvm::SmallVector<ObjCMethodDecl *, 2> Instance; + llvm::SmallVector<ObjCMethodDecl *, 2> Factory; + }; + + typedef Selector external_key_type; + typedef external_key_type internal_key_type; + + ASTSelectorLookupTrait(ASTReader &Reader, Module &F) + : Reader(Reader), F(F) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(Selector Sel); + + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d); + + internal_key_type ReadKey(const unsigned char* d, unsigned); + data_type ReadData(Selector, const unsigned char* d, unsigned DataLen); +}; + +/// \brief The on-disk hash table used for the global method pool. +typedef OnDiskChainedHashTable<ASTSelectorLookupTrait> + ASTSelectorLookupTable; + +/// \brief Trait class used to search the on-disk hash table containing all of +/// the header search information. +/// +/// The on-disk hash table contains a mapping from each header path to +/// information about that header (how many times it has been included, its +/// controlling macro, etc.). Note that we actually hash based on the +/// filename, and support "deep" comparisons of file names based on current +/// inode numbers, so that the search can cope with non-normalized path names +/// and symlinks. +class HeaderFileInfoTrait { + ASTReader &Reader; + Module &M; + HeaderSearch *HS; + const char *FrameworkStrings; + const char *SearchPath; + struct stat SearchPathStatBuf; + llvm::Optional<int> SearchPathStatResult; + + int StatSimpleCache(const char *Path, struct stat *StatBuf) { + if (Path == SearchPath) { + if (!SearchPathStatResult) + SearchPathStatResult = stat(Path, &SearchPathStatBuf); + + *StatBuf = SearchPathStatBuf; + return *SearchPathStatResult; + } + + return stat(Path, StatBuf); + } + +public: + typedef const char *external_key_type; + typedef const char *internal_key_type; + + typedef HeaderFileInfo data_type; + + HeaderFileInfoTrait(ASTReader &Reader, Module &M, HeaderSearch *HS, + const char *FrameworkStrings, + const char *SearchPath = 0) + : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings), + SearchPath(SearchPath) { } + + static unsigned ComputeHash(const char *path); + static internal_key_type GetInternalKey(const char *path); + bool EqualKey(internal_key_type a, internal_key_type b); + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d); + + static internal_key_type ReadKey(const unsigned char *d, unsigned) { + return (const char *)d; + } + + data_type ReadData(const internal_key_type, const unsigned char *d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used for known header files. +typedef OnDiskChainedHashTable<HeaderFileInfoTrait> + HeaderFileInfoLookupTable; + +} // end namespace clang::serialization::reader +} // end namespace clang::serialization +} // end namespace clang + + +#endif diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp index 14927b9..ab07b85 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -22,34 +22,51 @@ using namespace clang::serialization; namespace clang { class ASTStmtReader : public StmtVisitor<ASTStmtReader> { + typedef ASTReader::RecordData RecordData; + ASTReader &Reader; - ASTReader::PerFileData &F; + Module &F; llvm::BitstreamCursor &DeclsCursor; const ASTReader::RecordData &Record; unsigned &Idx; - SourceLocation ReadSourceLocation(const ASTReader::RecordData &R, - unsigned &I) { + SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { return Reader.ReadSourceLocation(F, R, I); } - SourceRange ReadSourceRange(const ASTReader::RecordData &R, unsigned &I) { + + SourceRange ReadSourceRange(const RecordData &R, unsigned &I) { return Reader.ReadSourceRange(F, R, I); } - TypeSourceInfo *GetTypeSourceInfo(const ASTReader::RecordData &R, - unsigned &I) { + + TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) { return Reader.GetTypeSourceInfo(F, R, I); } + + serialization::DeclID ReadDeclID(const RecordData &R, unsigned &I) { + return Reader.ReadDeclID(F, R, I); + } + + Decl *ReadDecl(const RecordData &R, unsigned &I) { + return Reader.ReadDecl(F, R, I); + } + + template<typename T> + T *ReadDeclAs(const RecordData &R, unsigned &I) { + return Reader.ReadDeclAs<T>(F, R, I); + } + void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name, const ASTReader::RecordData &R, unsigned &I) { Reader.ReadDeclarationNameLoc(F, DNLoc, Name, R, I); } + void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo, const ASTReader::RecordData &R, unsigned &I) { Reader.ReadDeclarationNameInfo(F, NameInfo, R, I); } public: - ASTStmtReader(ASTReader &Reader, ASTReader::PerFileData &F, + ASTStmtReader(ASTReader &Reader, Module &F, llvm::BitstreamCursor &Cursor, const ASTReader::RecordData &Record, unsigned &Idx) : Reader(Reader), F(F), DeclsCursor(Cursor), Record(Record), Idx(Idx) { } @@ -63,7 +80,7 @@ namespace clang { static const unsigned NumExprFields = NumStmtFields + 7; /// \brief Read and initialize a ExplicitTemplateArgumentList structure. - void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList, + void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList, unsigned NumTemplateArgs); void VisitStmt(Stmt *S); @@ -74,7 +91,7 @@ namespace clang { } void ASTStmtReader:: -ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList, +ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList, unsigned NumTemplateArgs) { TemplateArgumentListInfo ArgInfo; ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx)); @@ -92,16 +109,16 @@ void ASTStmtReader::VisitStmt(Stmt *S) { void ASTStmtReader::VisitNullStmt(NullStmt *S) { VisitStmt(S); S->setSemiLoc(ReadSourceLocation(Record, Idx)); - S->LeadingEmptyMacro = ReadSourceLocation(Record, Idx); + S->HasLeadingEmptyMacro = Record[Idx++]; } void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { VisitStmt(S); - llvm::SmallVector<Stmt *, 16> Stmts; + SmallVector<Stmt *, 16> Stmts; unsigned NumStmts = Record[Idx++]; while (NumStmts--) Stmts.push_back(Reader.ReadSubStmt()); - S->setStmts(*Reader.getContext(), Stmts.data(), Stmts.size()); + S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size()); S->setLBracLoc(ReadSourceLocation(Record, Idx)); S->setRBracLoc(ReadSourceLocation(Record, Idx)); } @@ -130,7 +147,7 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) { void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { VisitStmt(S); - LabelDecl *LD = cast<LabelDecl>(Reader.GetDecl(Record[Idx++])); + LabelDecl *LD = ReadDeclAs<LabelDecl>(Record, Idx); LD->setStmt(S); S->setDecl(LD); S->setSubStmt(Reader.ReadSubStmt()); @@ -139,8 +156,8 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setConditionVariable(Reader.getContext(), + ReadDeclAs<VarDecl>(Record, Idx)); S->setCond(Reader.ReadSubExpr()); S->setThen(Reader.ReadSubStmt()); S->setElse(Reader.ReadSubStmt()); @@ -150,8 +167,8 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setConditionVariable(Reader.getContext(), + ReadDeclAs<VarDecl>(Record, Idx)); S->setCond(Reader.ReadSubExpr()); S->setBody(Reader.ReadSubStmt()); S->setSwitchLoc(ReadSourceLocation(Record, Idx)); @@ -172,8 +189,9 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { void ASTStmtReader::VisitWhileStmt(WhileStmt *S) { VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setConditionVariable(Reader.getContext(), + ReadDeclAs<VarDecl>(Record, Idx)); + S->setCond(Reader.ReadSubExpr()); S->setBody(Reader.ReadSubStmt()); S->setWhileLoc(ReadSourceLocation(Record, Idx)); @@ -192,8 +210,8 @@ void ASTStmtReader::VisitForStmt(ForStmt *S) { VisitStmt(S); S->setInit(Reader.ReadSubStmt()); S->setCond(Reader.ReadSubExpr()); - S->setConditionVariable(*Reader.getContext(), - cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setConditionVariable(Reader.getContext(), + ReadDeclAs<VarDecl>(Record, Idx)); S->setInc(Reader.ReadSubExpr()); S->setBody(Reader.ReadSubStmt()); S->setForLoc(ReadSourceLocation(Record, Idx)); @@ -203,7 +221,7 @@ void ASTStmtReader::VisitForStmt(ForStmt *S) { void ASTStmtReader::VisitGotoStmt(GotoStmt *S) { VisitStmt(S); - S->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++]))); + S->setLabel(ReadDeclAs<LabelDecl>(Record, Idx)); S->setGotoLoc(ReadSourceLocation(Record, Idx)); S->setLabelLoc(ReadSourceLocation(Record, Idx)); } @@ -229,7 +247,7 @@ void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) { VisitStmt(S); S->setRetValue(Reader.ReadSubExpr()); S->setReturnLoc(ReadSourceLocation(Record, Idx)); - S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setNRVOCandidate(ReadDeclAs<VarDecl>(Record, Idx)); } void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { @@ -239,13 +257,13 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { if (Idx + 1 == Record.size()) { // Single declaration - S->setDeclGroup(DeclGroupRef(Reader.GetDecl(Record[Idx++]))); + S->setDeclGroup(DeclGroupRef(ReadDecl(Record, Idx))); } else { - llvm::SmallVector<Decl *, 16> Decls; - Decls.reserve(Record.size() - Idx); - for (unsigned N = Record.size(); Idx != N; ++Idx) - Decls.push_back(Reader.GetDecl(Record[Idx])); - S->setDeclGroup(DeclGroupRef(DeclGroup::Create(*Reader.getContext(), + SmallVector<Decl *, 16> Decls; + Decls.reserve(Record.size() - Idx); + for (unsigned N = Record.size(); Idx != N; ) + Decls.push_back(ReadDecl(Record, Idx)); + S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Reader.getContext(), Decls.data(), Decls.size()))); } @@ -265,21 +283,21 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); // Outputs and inputs - llvm::SmallVector<IdentifierInfo *, 16> Names; - llvm::SmallVector<StringLiteral*, 16> Constraints; - llvm::SmallVector<Stmt*, 16> Exprs; + SmallVector<IdentifierInfo *, 16> Names; + SmallVector<StringLiteral*, 16> Constraints; + SmallVector<Stmt*, 16> Exprs; for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) { - Names.push_back(Reader.GetIdentifierInfo(Record, Idx)); + Names.push_back(Reader.GetIdentifierInfo(F, Record, Idx)); Constraints.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); Exprs.push_back(Reader.ReadSubStmt()); } // Constraints - llvm::SmallVector<StringLiteral*, 16> Clobbers; + SmallVector<StringLiteral*, 16> Clobbers; for (unsigned I = 0; I != NumClobbers; ++I) Clobbers.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); - S->setOutputsAndInputsAndClobbers(*Reader.getContext(), + S->setOutputsAndInputsAndClobbers(Reader.getContext(), Names.data(), Constraints.data(), Exprs.data(), NumOutputs, NumInputs, Clobbers.data(), NumClobbers); @@ -287,7 +305,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { void ASTStmtReader::VisitExpr(Expr *E) { VisitStmt(E); - E->setType(Reader.GetType(Record[Idx++])); + E->setType(Reader.readType(F, Record, Idx)); E->setTypeDependent(Record[Idx++]); E->setValueDependent(Record[Idx++]); E->setInstantiationDependent(Record[Idx++]); @@ -309,6 +327,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { E->DeclRefExprBits.HasQualifier = Record[Idx++]; E->DeclRefExprBits.HasFoundDecl = Record[Idx++]; E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++]; + E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++]; unsigned NumTemplateArgs = 0; if (E->hasExplicitTemplateArgs()) NumTemplateArgs = Record[Idx++]; @@ -318,13 +337,13 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); if (E->hasFoundDecl()) - E->getInternalFoundDecl() = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx); if (E->hasExplicitTemplateArgs()) ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), NumTemplateArgs); - E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); + E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record, Idx); } @@ -332,12 +351,12 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { VisitExpr(E); E->setLocation(ReadSourceLocation(Record, Idx)); - E->setValue(*Reader.getContext(), Reader.ReadAPInt(Record, Idx)); + E->setValue(Reader.getContext(), Reader.ReadAPInt(Record, Idx)); } void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); - E->setValue(*Reader.getContext(), Reader.ReadAPFloat(Record, Idx)); + E->setValue(Reader.getContext(), Reader.ReadAPFloat(Record, Idx)); E->setExact(Record[Idx++]); E->setLocation(ReadSourceLocation(Record, Idx)); } @@ -353,12 +372,12 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) { assert(Record[Idx] == E->getNumConcatenated() && "Wrong number of concatenated tokens!"); ++Idx; - E->IsWide = Record[Idx++]; + E->Kind = static_cast<StringLiteral::StringKind>(Record[Idx++]); E->IsPascal = Record[Idx++]; // Read string data llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len); - E->setString(*Reader.getContext(), Str.str()); + E->setString(Reader.getContext(), Str.str()); Idx += Len; // Read source locations @@ -370,7 +389,7 @@ void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { VisitExpr(E); E->setValue(Record[Idx++]); E->setLocation(ReadSourceLocation(Record, Idx)); - E->setWide(Record[Idx++]); + E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record[Idx++])); } void ASTStmtReader::VisitParenExpr(ParenExpr *E) { @@ -383,7 +402,7 @@ void ASTStmtReader::VisitParenExpr(ParenExpr *E) { void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) { VisitExpr(E); unsigned NumExprs = Record[Idx++]; - E->Exprs = new (*Reader.getContext()) Stmt*[NumExprs]; + E->Exprs = new (Reader.getContext()) Stmt*[NumExprs]; for (unsigned i = 0; i != NumExprs; ++i) E->Exprs[i] = Reader.ReadSubStmt(); E->NumExprs = NumExprs; @@ -418,18 +437,18 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { break; case Node::Field: - E->setComponent(I, - Node(Start, - dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])), - End)); + E->setComponent(I, Node(Start, ReadDeclAs<FieldDecl>(Record, Idx), End)); break; case Node::Identifier: - E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End)); + E->setComponent(I, + Node(Start, + Reader.GetIdentifierInfo(F, Record, Idx), + End)); break; case Node::Base: { - CXXBaseSpecifier *Base = new (*Reader.getContext()) CXXBaseSpecifier(); + CXXBaseSpecifier *Base = new (Reader.getContext()) CXXBaseSpecifier(); *Base = Reader.ReadCXXBaseSpecifier(F, Record, Idx); E->setComponent(I, Node(Base)); break; @@ -463,7 +482,7 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); - E->setNumArgs(*Reader.getContext(), Record[Idx++]); + E->setNumArgs(Reader.getContext(), Record[Idx++]); E->setRParenLoc(ReadSourceLocation(Record, Idx)); E->setCallee(Reader.ReadSubExpr()); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) @@ -509,7 +528,7 @@ void ASTStmtReader::VisitCastExpr(CastExpr *E) { E->setCastKind((CastExpr::CastKind)Record[Idx++]); CastExpr::path_iterator BaseI = E->path_begin(); while (NumBaseSpecs--) { - CXXBaseSpecifier *BaseSpec = new (*Reader.getContext()) CXXBaseSpecifier; + CXXBaseSpecifier *BaseSpec = new (Reader.getContext()) CXXBaseSpecifier; *BaseSpec = Reader.ReadCXXBaseSpecifier(F, Record, Idx); *BaseI++ = BaseSpec; } @@ -525,8 +544,8 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { VisitBinaryOperator(E); - E->setComputationLHSType(Reader.GetType(Record[Idx++])); - E->setComputationResultType(Reader.GetType(Record[Idx++])); + E->setComputationLHSType(Reader.readType(F, Record, Idx)); + E->setComputationResultType(Reader.readType(F, Record, Idx)); } void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) { @@ -578,7 +597,7 @@ void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { VisitExpr(E); E->setBase(Reader.ReadSubExpr()); - E->setAccessor(Reader.GetIdentifierInfo(Record, Idx)); + E->setAccessor(Reader.GetIdentifierInfo(F, Record, Idx)); E->setAccessorLoc(ReadSourceLocation(Record, Idx)); } @@ -593,19 +612,18 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { filler = Reader.ReadSubExpr(); E->ArrayFillerOrUnionFieldInit = filler; } else - E->ArrayFillerOrUnionFieldInit - = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); + E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx); E->sawArrayRangeDesignator(Record[Idx++]); unsigned NumInits = Record[Idx++]; - E->reserveInits(*Reader.getContext(), NumInits); + E->reserveInits(Reader.getContext(), NumInits); if (isArrayFiller) { for (unsigned I = 0; I != NumInits; ++I) { Expr *init = Reader.ReadSubExpr(); - E->updateInit(*Reader.getContext(), I, init ? init : filler); + E->updateInit(Reader.getContext(), I, init ? init : filler); } } else { for (unsigned I = 0; I != NumInits; ++I) - E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr()); + E->updateInit(Reader.getContext(), I, Reader.ReadSubExpr()); } } @@ -620,11 +638,11 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { E->setEqualOrColonLoc(ReadSourceLocation(Record, Idx)); E->setGNUSyntax(Record[Idx++]); - llvm::SmallVector<Designator, 4> Designators; + SmallVector<Designator, 4> Designators; while (Idx < Record.size()) { switch ((DesignatorTypes)Record[Idx++]) { case DESIG_FIELD_DECL: { - FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++])); + FieldDecl *Field = ReadDeclAs<FieldDecl>(Record, Idx); SourceLocation DotLoc = ReadSourceLocation(Record, Idx); SourceLocation FieldLoc @@ -636,7 +654,7 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { } case DESIG_FIELD_NAME: { - const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx); + const IdentifierInfo *Name = Reader.GetIdentifierInfo(F, Record, Idx); SourceLocation DotLoc = ReadSourceLocation(Record, Idx); SourceLocation FieldLoc @@ -669,7 +687,7 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { } } } - E->setDesignators(*Reader.getContext(), + E->setDesignators(Reader.getContext(), Designators.data(), Designators.size()); } @@ -689,7 +707,7 @@ void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { VisitExpr(E); E->setAmpAmpLoc(ReadSourceLocation(Record, Idx)); E->setLabelLoc(ReadSourceLocation(Record, Idx)); - E->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLabel(ReadDeclAs<LabelDecl>(Record, Idx)); } void ASTStmtReader::VisitStmtExpr(StmtExpr *E) { @@ -715,23 +733,23 @@ void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) { void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { VisitExpr(E); - llvm::SmallVector<Expr *, 16> Exprs; + SmallVector<Expr *, 16> Exprs; unsigned NumExprs = Record[Idx++]; while (NumExprs--) Exprs.push_back(Reader.ReadSubExpr()); - E->setExprs(*Reader.getContext(), Exprs.data(), Exprs.size()); + E->setExprs(Reader.getContext(), Exprs.data(), Exprs.size()); E->setBuiltinLoc(ReadSourceLocation(Record, Idx)); E->setRParenLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitBlockExpr(BlockExpr *E) { VisitExpr(E); - E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++]))); + E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx)); } void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { VisitExpr(E); - E->setDecl(cast<VarDecl>(Reader.GetDecl(Record[Idx++]))); + E->setDecl(ReadDeclAs<VarDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); E->setByRef(Record[Idx++]); E->setConstQualAdded(Record[Idx++]); @@ -740,9 +758,9 @@ void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { VisitExpr(E); E->NumAssocs = Record[Idx++]; - E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs]; + E->AssocTypes = new (Reader.getContext()) TypeSourceInfo*[E->NumAssocs]; E->SubExprs = - new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs]; + new(Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs]; E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr(); for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { @@ -756,6 +774,25 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { E->RParenLoc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) { + VisitExpr(E); + E->setOp(AtomicExpr::AtomicOp(Record[Idx++])); + E->setPtr(Reader.ReadSubExpr()); + E->setOrder(Reader.ReadSubExpr()); + E->setNumSubExprs(2); + if (E->getOp() != AtomicExpr::Load) { + E->setVal1(Reader.ReadSubExpr()); + E->setNumSubExprs(3); + } + if (E->isCmpXChg()) { + E->setOrderFail(Reader.ReadSubExpr()); + E->setVal2(Reader.ReadSubExpr()); + E->setNumSubExprs(5); + } + E->setBuiltinLoc(ReadSourceLocation(Record, Idx)); + E->setRParenLoc(ReadSourceLocation(Record, Idx)); +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements @@ -774,21 +811,21 @@ void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); - E->setSelector(Reader.GetSelector(Record, Idx)); + E->setSelector(Reader.ReadSelector(F, Record, Idx)); E->setAtLoc(ReadSourceLocation(Record, Idx)); E->setRParenLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { VisitExpr(E); - E->setProtocol(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + E->setProtocol(ReadDeclAs<ObjCProtocolDecl>(Record, Idx)); E->setAtLoc(ReadSourceLocation(Record, Idx)); E->setRParenLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); - E->setDecl(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); E->setBase(Reader.ReadSubExpr()); E->setIsArrow(Record[Idx++]); @@ -799,14 +836,11 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { VisitExpr(E); bool Implicit = Record[Idx++] != 0; if (Implicit) { - ObjCMethodDecl *Getter = - cast<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])); - ObjCMethodDecl *Setter = - cast<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])); + ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>(Record, Idx); + ObjCMethodDecl *Setter = ReadDeclAs<ObjCMethodDecl>(Record, Idx); E->setImplicitProperty(Getter, Setter); } else { - E->setExplicitProperty( - cast<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++]))); + E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx)); } E->setLocation(ReadSourceLocation(Record, Idx)); E->setReceiverLocation(ReadSourceLocation(Record, Idx)); @@ -815,11 +849,10 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { E->setBase(Reader.ReadSubExpr()); break; case 1: - E->setSuperReceiver(Reader.GetType(Record[Idx++])); + E->setSuperReceiver(Reader.readType(F, Record, Idx)); break; case 2: - E->setClassReceiver( - cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); break; } } @@ -828,6 +861,8 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { VisitExpr(E); assert(Record[Idx] == E->getNumArgs()); ++Idx; + unsigned NumStoredSelLocs = Record[Idx++]; + E->SelLocsKind = Record[Idx++]; E->setDelegateInitCall(Record[Idx++]); ObjCMessageExpr::ReceiverKind Kind = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]); @@ -842,7 +877,7 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { case ObjCMessageExpr::SuperClass: case ObjCMessageExpr::SuperInstance: { - QualType T = Reader.GetType(Record[Idx++]); + QualType T = Reader.readType(F, Record, Idx); SourceLocation SuperLoc = ReadSourceLocation(Record, Idx); E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); break; @@ -852,16 +887,19 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { assert(Kind == E->getReceiverKind()); if (Record[Idx++]) - E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>(Record, Idx)); else - E->setSelector(Reader.GetSelector(Record, Idx)); + E->setSelector(Reader.ReadSelector(F, Record, Idx)); E->LBracLoc = ReadSourceLocation(Record, Idx); E->RBracLoc = ReadSourceLocation(Record, Idx); - E->SelectorLoc = ReadSourceLocation(Record, Idx); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, Reader.ReadSubExpr()); + + SourceLocation *Locs = E->getStoredSelLocs(); + for (unsigned I = 0; I != NumStoredSelLocs; ++I) + Locs[I] = ReadSourceLocation(Record, Idx); } void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { @@ -876,7 +914,7 @@ void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { VisitStmt(S); S->setCatchBody(Reader.ReadSubStmt()); - S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setCatchParamDecl(ReadDeclAs<VarDecl>(Record, Idx)); S->setAtCatchLoc(ReadSourceLocation(Record, Idx)); S->setRParenLoc(ReadSourceLocation(Record, Idx)); } @@ -927,7 +965,7 @@ void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) { VisitStmt(S); S->CatchLoc = ReadSourceLocation(Record, Idx); - S->ExceptionDecl = cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])); + S->ExceptionDecl = ReadDeclAs<VarDecl>(Record, Idx); S->HandlerBlock = Reader.ReadSubStmt(); } @@ -963,12 +1001,13 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); E->NumArgs = Record[Idx++]; if (E->NumArgs) - E->Args = new (*Reader.getContext()) Stmt*[E->NumArgs]; + E->Args = new (Reader.getContext()) Stmt*[E->NumArgs]; for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, Reader.ReadSubExpr()); - E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); - E->setElidable(Record[Idx++]); + E->setElidable(Record[Idx++]); + E->setHadMultipleCandidates(Record[Idx++]); E->setRequiresZeroInitialization(Record[Idx++]); E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); E->ParenRange = ReadSourceRange(Record, Idx); @@ -1048,15 +1087,15 @@ void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { VisitExpr(E); - assert(Record[Idx] == E->Param.getInt() && "We messed up at creation ?"); + assert((bool)Record[Idx] == E->Param.getInt() && "We messed up at creation ?"); ++Idx; // HasOtherExprStored and SubExpr was handled during creation. - E->Param.setPointer(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + E->Param.setPointer(ReadDeclAs<ParmVarDecl>(Record, Idx)); E->Loc = ReadSourceLocation(Record, Idx); } void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); - E->setTemporary(Reader.ReadCXXTemporary(Record, Idx)); + E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx)); E->setSubExpr(Reader.ReadSubExpr()); } @@ -1072,13 +1111,12 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { E->Initializer = Record[Idx++]; E->UsualArrayDeleteWantsSize = Record[Idx++]; bool isArray = Record[Idx++]; + E->setHadMultipleCandidates(Record[Idx++]); unsigned NumPlacementArgs = Record[Idx++]; unsigned NumCtorArgs = Record[Idx++]; - E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); - E->setOperatorDelete( - cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); - E->setConstructor( - cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setOperatorNew(ReadDeclAs<FunctionDecl>(Record, Idx)); + E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx)); + E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx)); E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx); SourceRange TypeIdParens; TypeIdParens.setBegin(ReadSourceLocation(Record, Idx)); @@ -1089,7 +1127,7 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { E->ConstructorLParen = ReadSourceLocation(Record, Idx); E->ConstructorRParen = ReadSourceLocation(Record, Idx); - E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs, + E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs, NumCtorArgs); // Install all the subexpressions. @@ -1104,7 +1142,7 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) { E->ArrayForm = Record[Idx++]; E->ArrayFormAsWritten = Record[Idx++]; E->UsualArrayDeleteWantsSize = Record[Idx++]; - E->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])); + E->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx); E->Argument = Reader.ReadSubExpr(); E->Loc = ReadSourceLocation(Record, Idx); } @@ -1120,7 +1158,7 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { E->ColonColonLoc = ReadSourceLocation(Record, Idx); E->TildeLoc = ReadSourceLocation(Record, Idx); - IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx); + IdentifierInfo *II = Reader.GetIdentifierInfo(F, Record, Idx); if (II) E->setDestroyedType(II, ReadSourceLocation(Record, Idx)); else @@ -1131,9 +1169,9 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { VisitExpr(E); unsigned NumTemps = Record[Idx++]; if (NumTemps) { - E->setNumTemporaries(*Reader.getContext(), NumTemps); + E->setNumTemporaries(Reader.getContext(), NumTemps); for (unsigned i = 0; i != NumTemps; ++i) - E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx)); + E->setTemporary(i, Reader.ReadCXXTemporary(F, Record, Idx)); } E->setSubExpr(Reader.ReadSubExpr()); } @@ -1147,12 +1185,11 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ Record[Idx++]); E->Base = Reader.ReadSubExpr(); - E->BaseType = Reader.GetType(Record[Idx++]); + E->BaseType = Reader.readType(F, Record, Idx); E->IsArrow = Record[Idx++]; E->OperatorLoc = ReadSourceLocation(Record, Idx); E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); - E->FirstQualifierFoundInScope - = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); + E->FirstQualifierFoundInScope = ReadDeclAs<NamedDecl>(Record, Idx); ReadDeclarationNameInfo(E->MemberNameInfo, Record, Idx); } @@ -1191,11 +1228,11 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { unsigned NumDecls = Record[Idx++]; UnresolvedSet<8> Decls; for (unsigned i = 0; i != NumDecls; ++i) { - NamedDecl *D = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); + NamedDecl *D = ReadDeclAs<NamedDecl>(Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; Decls.addDecl(D, AS); } - E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end()); + E->initializeResults(Reader.getContext(), Decls.begin(), Decls.end()); ReadDeclarationNameInfo(E->NameInfo, Record, Idx); E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); @@ -1206,7 +1243,7 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { E->IsArrow = Record[Idx++]; E->HasUnresolvedUsing = Record[Idx++]; E->Base = Reader.ReadSubExpr(); - E->BaseType = Reader.GetType(Record[Idx++]); + E->BaseType = Reader.readType(F, Record, Idx); E->OperatorLoc = ReadSourceLocation(Record, Idx); } @@ -1216,7 +1253,7 @@ void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { if (E->RequiresADL) E->StdIsAssociatedNamespace = Record[Idx++]; E->Overloaded = Record[Idx++]; - E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); + E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx); } void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { @@ -1280,14 +1317,13 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { E->PackLoc = ReadSourceLocation(Record, Idx); E->RParenLoc = ReadSourceLocation(Record, Idx); E->Length = Record[Idx++]; - E->Pack = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); + E->Pack = ReadDeclAs<NamedDecl>(Record, Idx); } void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { VisitExpr(E); - E->Param - = cast_or_null<NonTypeTemplateParmDecl>(Reader.GetDecl(Record[Idx++])); + E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx); E->NameLoc = ReadSourceLocation(Record, Idx); E->Replacement = Reader.ReadSubExpr(); } @@ -1295,8 +1331,7 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr( void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E) { VisitExpr(E); - E->Param - = cast_or_null<NonTypeTemplateParmDecl>(Reader.GetDecl(Record[Idx++])); + E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(Record, Idx); TemplateArgument ArgPack = Reader.ReadTemplateArgument(F, Record, Idx); if (ArgPack.getKind() != TemplateArgument::Pack) return; @@ -1377,7 +1412,7 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) { // ASTReader Implementation //===----------------------------------------------------------------------===// -Stmt *ASTReader::ReadStmt(PerFileData &F) { +Stmt *ASTReader::ReadStmt(Module &F) { switch (ReadingKind) { case Read_Decl: case Read_Type: @@ -1390,7 +1425,7 @@ Stmt *ASTReader::ReadStmt(PerFileData &F) { return 0; } -Expr *ASTReader::ReadExpr(PerFileData &F) { +Expr *ASTReader::ReadExpr(Module &F) { return cast_or_null<Expr>(ReadStmt(F)); } @@ -1405,7 +1440,7 @@ Expr *ASTReader::ReadSubExpr() { // the stack, with expressions having operands removing those operands from the // stack. Evaluation terminates when we see a STMT_STOP record, and // the single remaining expression on the stack is our result. -Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { +Stmt *ASTReader::ReadStmtFromStream(Module &F) { ReadingKindTracker ReadingKind(Read_Stmt, *this); llvm::BitstreamCursor &Cursor = F.DeclsCursor; @@ -1531,20 +1566,20 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_DECL_REF: S = DeclRefExpr::CreateEmpty( - *Context, + Context, /*HasQualifier=*/Record[ASTStmtReader::NumExprFields], /*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1], /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2], /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ? - Record[ASTStmtReader::NumExprFields + 3] : 0); + Record[ASTStmtReader::NumExprFields + 4] : 0); break; case EXPR_INTEGER_LITERAL: - S = IntegerLiteral::Create(*Context, Empty); + S = IntegerLiteral::Create(Context, Empty); break; case EXPR_FLOATING_LITERAL: - S = FloatingLiteral::Create(*Context, Empty); + S = FloatingLiteral::Create(Context, Empty); break; case EXPR_IMAGINARY_LITERAL: @@ -1552,7 +1587,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_STRING_LITERAL: - S = StringLiteral::CreateEmpty(*Context, + S = StringLiteral::CreateEmpty(Context, Record[ASTStmtReader::NumExprFields + 1]); break; @@ -1573,7 +1608,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_OFFSETOF: - S = OffsetOfExpr::CreateEmpty(*Context, + S = OffsetOfExpr::CreateEmpty(Context, Record[ASTStmtReader::NumExprFields], Record[ASTStmtReader::NumExprFields + 1]); break; @@ -1587,7 +1622,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CALL: - S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty); + S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty); break; case EXPR_MEMBER: { @@ -1610,25 +1645,29 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { for (unsigned i = 0; i != NumTemplateArgs; ++i) ArgInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Idx)); } - - NamedDecl *FoundD = cast_or_null<NamedDecl>(GetDecl(Record[Idx++])); + + bool HadMultipleCandidates = Record[Idx++]; + + NamedDecl *FoundD = ReadDeclAs<NamedDecl>(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS); - QualType T = GetType(Record[Idx++]); + QualType T = readType(F, Record, Idx); ExprValueKind VK = static_cast<ExprValueKind>(Record[Idx++]); ExprObjectKind OK = static_cast<ExprObjectKind>(Record[Idx++]); Expr *Base = ReadSubExpr(); - ValueDecl *MemberD = cast<ValueDecl>(GetDecl(Record[Idx++])); + ValueDecl *MemberD = ReadDeclAs<ValueDecl>(F, Record, Idx); SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx); DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc); bool IsArrow = Record[Idx++]; - S = MemberExpr::Create(*Context, Base, IsArrow, QualifierLoc, + S = MemberExpr::Create(Context, Base, IsArrow, QualifierLoc, MemberD, FoundDecl, MemberNameInfo, HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK); ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc, MemberD->getDeclName(), Record, Idx); + if (HadMultipleCandidates) + cast<MemberExpr>(S)->setHadMultipleCandidates(true); break; } @@ -1649,12 +1688,12 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_IMPLICIT_CAST: - S = ImplicitCastExpr::CreateEmpty(*Context, + S = ImplicitCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; case EXPR_CSTYLE_CAST: - S = CStyleCastExpr::CreateEmpty(*Context, + S = CStyleCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; @@ -1667,11 +1706,11 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_INIT_LIST: - S = new (Context) InitListExpr(*getContext(), Empty); + S = new (Context) InitListExpr(getContext(), Empty); break; case EXPR_DESIGNATED_INIT: - S = DesignatedInitExpr::CreateEmpty(*Context, + S = DesignatedInitExpr::CreateEmpty(Context, Record[ASTStmtReader::NumExprFields] - 1); break; @@ -1738,8 +1777,9 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { llvm_unreachable("mismatching AST file"); break; case EXPR_OBJC_MESSAGE_EXPR: - S = ObjCMessageExpr::CreateEmpty(*Context, - Record[ASTStmtReader::NumExprFields]); + S = ObjCMessageExpr::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields], + Record[ASTStmtReader::NumExprFields + 1]); break; case EXPR_OBJC_ISA: S = new (Context) ObjCIsaExpr(Empty); @@ -1760,7 +1800,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) ObjCAtFinallyStmt(Empty); break; case STMT_OBJC_AT_TRY: - S = ObjCAtTryStmt::CreateEmpty(*Context, + S = ObjCAtTryStmt::CreateEmpty(Context, Record[ASTStmtReader::NumStmtFields], Record[ASTStmtReader::NumStmtFields + 1]); break; @@ -1787,7 +1827,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case STMT_CXX_TRY: - S = CXXTryStmt::Create(*Context, Empty, + S = CXXTryStmt::Create(Context, Empty, /*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]); break; @@ -1796,11 +1836,11 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_OPERATOR_CALL: - S = new (Context) CXXOperatorCallExpr(*Context, Empty); + S = new (Context) CXXOperatorCallExpr(Context, Empty); break; case EXPR_CXX_MEMBER_CALL: - S = new (Context) CXXMemberCallExpr(*Context, Empty); + S = new (Context) CXXMemberCallExpr(Context, Empty); break; case EXPR_CXX_CONSTRUCT: @@ -1812,26 +1852,26 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_STATIC_CAST: - S = CXXStaticCastExpr::CreateEmpty(*Context, + S = CXXStaticCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; case EXPR_CXX_DYNAMIC_CAST: - S = CXXDynamicCastExpr::CreateEmpty(*Context, + S = CXXDynamicCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; case EXPR_CXX_REINTERPRET_CAST: - S = CXXReinterpretCastExpr::CreateEmpty(*Context, + S = CXXReinterpretCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; case EXPR_CXX_CONST_CAST: - S = CXXConstCastExpr::CreateEmpty(*Context); + S = CXXConstCastExpr::CreateEmpty(Context); break; case EXPR_CXX_FUNCTIONAL_CAST: - S = CXXFunctionalCastExpr::CreateEmpty(*Context, + S = CXXFunctionalCastExpr::CreateEmpty(Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); break; @@ -1864,7 +1904,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields]; if (HasOtherExprStored) { Expr *SubExpr = ReadSubExpr(); - S = CXXDefaultArgExpr::Create(*Context, SourceLocation(), 0, SubExpr); + S = CXXDefaultArgExpr::Create(Context, SourceLocation(), 0, SubExpr); } else S = new (Context) CXXDefaultArgExpr(Empty); break; @@ -1891,7 +1931,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: - S = CXXDependentScopeMemberExpr::CreateEmpty(*Context, + S = CXXDependentScopeMemberExpr::CreateEmpty(Context, /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] ? Record[ASTStmtReader::NumExprFields + 1] @@ -1899,7 +1939,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: - S = DependentScopeDeclRefExpr::CreateEmpty(*Context, + S = DependentScopeDeclRefExpr::CreateEmpty(Context, /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] ? Record[ASTStmtReader::NumExprFields + 1] @@ -1907,12 +1947,12 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_UNRESOLVED_CONSTRUCT: - S = CXXUnresolvedConstructExpr::CreateEmpty(*Context, + S = CXXUnresolvedConstructExpr::CreateEmpty(Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields]); break; case EXPR_CXX_UNRESOLVED_MEMBER: - S = UnresolvedMemberExpr::CreateEmpty(*Context, + S = UnresolvedMemberExpr::CreateEmpty(Context, /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] ? Record[ASTStmtReader::NumExprFields + 1] @@ -1920,7 +1960,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_CXX_UNRESOLVED_LOOKUP: - S = UnresolvedLookupExpr::CreateEmpty(*Context, + S = UnresolvedLookupExpr::CreateEmpty(Context, /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields], /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] ? Record[ASTStmtReader::NumExprFields + 1] @@ -1983,12 +2023,16 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { } case EXPR_CUDA_KERNEL_CALL: - S = new (Context) CUDAKernelCallExpr(*Context, Empty); + S = new (Context) CUDAKernelCallExpr(Context, Empty); break; case EXPR_ASTYPE: S = new (Context) AsTypeExpr(Empty); break; + + case EXPR_ATOMIC: + S = new (Context) AtomicExpr(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 39f2fbd..b31262d 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" -#include "clang/Serialization/ASTSerializationListener.h" #include "ASTCommon.h" #include "clang/Sema/Sema.h" #include "clang/Sema/IdentifierResolver.h" @@ -45,21 +44,23 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include <algorithm> #include <cstdio> #include <string.h> +#include <utility> using namespace clang; using namespace clang::serialization; template <typename T, typename Allocator> -static llvm::StringRef data(const std::vector<T, Allocator> &v) { - if (v.empty()) return llvm::StringRef(); - return llvm::StringRef(reinterpret_cast<const char*>(&v[0]), +static StringRef data(const std::vector<T, Allocator> &v) { + if (v.empty()) return StringRef(); + return StringRef(reinterpret_cast<const char*>(&v[0]), sizeof(T) * v.size()); } template <typename T> -static llvm::StringRef data(const llvm::SmallVectorImpl<T> &v) { - return llvm::StringRef(reinterpret_cast<const char*>(v.data()), +static StringRef data(const SmallVectorImpl<T> &v) { + return StringRef(reinterpret_cast<const char*>(v.data()), sizeof(T) * v.size()); } @@ -90,7 +91,7 @@ namespace { } void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { - assert(false && "Built-in types are never serialized"); + llvm_unreachable("Built-in types are never serialized"); } void ASTTypeWriter::VisitComplexType(const ComplexType *T) { @@ -304,7 +305,7 @@ void ASTTypeWriter::VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { // FIXME: Serialize this type (C++ only) - assert(false && "Cannot serialize dependent sized extended vector types"); + llvm_unreachable("Cannot serialize dependent sized extended vector types"); } void @@ -387,6 +388,12 @@ ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Code = TYPE_OBJC_OBJECT_POINTER; } +void +ASTTypeWriter::VisitAtomicType(const AtomicType *T) { + Writer.AddTypeRef(T->getValueType(), Record); + Code = TYPE_ATOMIC; +} + namespace { class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { @@ -595,6 +602,11 @@ void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); } +void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); +} //===----------------------------------------------------------------------===// // ASTWriter Implementation @@ -762,8 +774,8 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); RECORD(VERSION_CONTROL_BRANCH_REVISION); - RECORD(MACRO_DEFINITION_OFFSETS); - RECORD(CHAINED_METADATA); + RECORD(PPD_ENTITIES_OFFSETS); + RECORD(IMPORTS); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); RECORD(REDECLS_UPDATE_LATEST); @@ -778,11 +790,14 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DIAG_PRAGMA_MAPPINGS); RECORD(CUDA_SPECIAL_DECL_REFS); RECORD(HEADER_SEARCH_TABLE); + RECORD(ORIGINAL_PCH_DIR); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); RECORD(DELEGATING_CTORS); RECORD(FILE_SOURCE_LOCATION_OFFSETS); RECORD(KNOWN_NAMESPACES); + RECORD(MODULE_OFFSET_MAP); + RECORD(SOURCE_MANAGER_LINE_TABLE); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -790,7 +805,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(SM_SLOC_BUFFER_ENTRY); RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_EXPANSION_ENTRY); - RECORD(SM_LINE_TABLE); // Preprocessor Block. BLOCK(PREPROCESSOR_BLOCK); @@ -837,7 +851,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(TYPE_PACK_EXPANSION); RECORD(TYPE_ATTRIBUTED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK); - RECORD(DECL_TRANSLATION_UNIT); + RECORD(TYPE_ATOMIC); RECORD(DECL_TYPEDEF); RECORD(DECL_ENUM); RECORD(DECL_RECORD); @@ -916,15 +930,15 @@ void ASTWriter::WriteBlockInfoBlock() { /// \returns either the original filename (if it needs no adjustment) or the /// adjusted filename (which points into the @p Filename parameter). static const char * -adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) { +adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) { assert(Filename && "No file name to adjust?"); - if (!isysroot) + if (isysroot.empty()) return Filename; // Verify that the filename and the system root have the same prefix. unsigned Pos = 0; - for (; Filename[Pos] && isysroot[Pos]; ++Pos) + for (; Filename[Pos] && Pos < isysroot.size(); ++Pos) if (Filename[Pos] != isysroot[Pos]) return Filename; // Prefixes don't match. @@ -942,34 +956,52 @@ adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) { } /// \brief Write the AST metadata (e.g., i686-apple-darwin9). -void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot, +void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, const std::string &OutputFile) { using namespace llvm; // Metadata - const TargetInfo &Target = Context.Target; + const TargetInfo &Target = Context.getTargetInfo(); BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); - MetaAbbrev->Add(BitCodeAbbrevOp( - Chain ? CHAINED_METADATA : METADATA)); + MetaAbbrev->Add(BitCodeAbbrevOp(METADATA)); MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable - // Target triple or chained PCH name - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); RecordData Record; - Record.push_back(Chain ? CHAINED_METADATA : METADATA); + Record.push_back(METADATA); Record.push_back(VERSION_MAJOR); Record.push_back(VERSION_MINOR); Record.push_back(CLANG_VERSION_MAJOR); Record.push_back(CLANG_VERSION_MINOR); - Record.push_back(isysroot != 0); - // FIXME: This writes the absolute path for chained headers. - const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple(); - Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr); + Record.push_back(!isysroot.empty()); + const std::string &Triple = Target.getTriple().getTriple(); + Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple); + + if (Chain) { + serialization::ModuleManager &Mgr = Chain->getModuleManager(); + llvm::SmallVector<char, 128> ModulePaths; + Record.clear(); + + for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end(); + M != MEnd; ++M) { + // Skip modules that weren't directly imported. + if (!(*M)->isDirectlyImported()) + continue; + + Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding + // FIXME: Write import location, once it matters. + // FIXME: This writes the absolute path for AST files we depend on. + const std::string &FileName = (*M)->FileName; + Record.push_back(FileName.size()); + Record.append(FileName.begin(), FileName.end()); + } + Stream.EmitRecord(IMPORTS, Record); + } // Original file name and file ID SourceManager &SM = Context.getSourceManager(); @@ -1026,94 +1058,11 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot, /// \brief Write the LangOptions structure. void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { RecordData Record; - Record.push_back(LangOpts.Trigraphs); - Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments. - Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. - Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. - Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) - Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords - Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. - Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ - Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. - Record.push_back(LangOpts.C99); // C99 Support - Record.push_back(LangOpts.C1X); // C1X Support - Record.push_back(LangOpts.Microsoft); // Microsoft extensions. - // LangOpts.MSCVersion is ignored because all it does it set a macro, which is - // already saved elsewhere. - Record.push_back(LangOpts.CPlusPlus); // C++ Support - Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support - Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords. - - Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. - Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. - Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C - // modern abi enabled. - Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced - // modern abi enabled. - Record.push_back(LangOpts.AppleKext); // Apple's kernel extensions ABI - Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized - // properties enabled. - Record.push_back(LangOpts.ObjCInferRelatedResultType); - Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. - - Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings - Record.push_back(LangOpts.WritableStrings); // Allow writable strings - Record.push_back(LangOpts.LaxVectorConversions); - Record.push_back(LangOpts.AltiVec); - Record.push_back(LangOpts.Exceptions); // Support exception handling. - Record.push_back(LangOpts.ObjCExceptions); - Record.push_back(LangOpts.CXXExceptions); - Record.push_back(LangOpts.SjLjExceptions); - - Record.push_back(LangOpts.MSBitfields); // MS-compatible structure layout - Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. - Record.push_back(LangOpts.Freestanding); // Freestanding implementation - Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin) - - // Whether static initializers are protected by locks. - Record.push_back(LangOpts.ThreadsafeStatics); - Record.push_back(LangOpts.POSIXThreads); - Record.push_back(LangOpts.Blocks); // block extension to C - Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if - // they are unused. - Record.push_back(LangOpts.MathErrno); // Math functions must respect errno - // (modulo the platform support). - - Record.push_back(LangOpts.getSignedOverflowBehavior()); - Record.push_back(LangOpts.HeinousExtensions); - - Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. - Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be - // defined. - Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as - // opposed to __DYNAMIC__). - Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero. - - Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be - // used (instead of C99 semantics). - Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. - Record.push_back(LangOpts.Deprecated); // Should __DEPRECATED be defined. - Record.push_back(LangOpts.AccessControl); // Whether C++ access control should - // be enabled. - Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or - // unsigned type - Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short - Record.push_back(LangOpts.ShortEnums); // Should the enum type be equivalent - // to the smallest integer type with - // enough room. - Record.push_back(LangOpts.getGCMode()); - Record.push_back(LangOpts.getVisibilityMode()); - Record.push_back(LangOpts.getStackProtectorMode()); - Record.push_back(LangOpts.InstantiationDepth); - Record.push_back(LangOpts.OpenCL); - Record.push_back(LangOpts.CUDA); - Record.push_back(LangOpts.CatchUndefined); - Record.push_back(LangOpts.DefaultFPContract); - Record.push_back(LangOpts.ElideConstructors); - Record.push_back(LangOpts.SpellChecking); - Record.push_back(LangOpts.MRTD); - Record.push_back(LangOpts.ObjCAutoRefCount); - Record.push_back(LangOpts.ObjCInferRelatedReturnType); +#define LANGOPT(Name, Bits, Default, Description) \ + Record.push_back(LangOpts.Name); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Record.push_back(static_cast<unsigned>(LangOpts.get##Name())); +#include "clang/Basic/LangOptions.def" Stream.EmitRecord(LANGUAGE_OPTIONS, Record); } @@ -1136,7 +1085,7 @@ public: } std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, const char *path, + EmitKeyDataLength(raw_ostream& Out, const char *path, data_type_ref Data) { unsigned StrLen = strlen(path); clang::io::Emit16(Out, StrLen); @@ -1145,11 +1094,11 @@ public: return std::make_pair(StrLen + 1, DataLen); } - void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) { + void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { Out.write(path, KeyLen); } - void EmitData(llvm::raw_ostream &Out, key_type_ref, + void EmitData(raw_ostream &Out, key_type_ref, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; @@ -1174,7 +1123,7 @@ void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) { for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), StatEnd = StatCalls.end(); Stat != StatEnd; ++Stat, ++NumStatEntries) { - llvm::StringRef Filename = Stat->first(); + StringRef Filename = Stat->first(); Generator.insert(Filename.data(), Stat->second); } @@ -1222,6 +1171,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { // FileEntry fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name return Stream.EmitAbbrev(Abbrev); } @@ -1270,6 +1220,10 @@ namespace { ASTWriter &Writer; HeaderSearch &HS; + // Keep track of the framework names we've used during serialization. + SmallVector<char, 128> FrameworkStringData; + llvm::StringMap<unsigned> FrameworkNameOffset; + public: HeaderFileInfoTrait(ASTWriter &Writer, HeaderSearch &HS) : Writer(Writer), HS(HS) { } @@ -1289,28 +1243,29 @@ namespace { } std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, const char *path, + EmitKeyDataLength(raw_ostream& Out, const char *path, data_type_ref Data) { unsigned StrLen = strlen(path); clang::io::Emit16(Out, StrLen); - unsigned DataLen = 1 + 2 + 4; + unsigned DataLen = 1 + 2 + 4 + 4; clang::io::Emit8(Out, DataLen); return std::make_pair(StrLen + 1, DataLen); } - void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) { + void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { Out.write(path, KeyLen); } - void EmitData(llvm::raw_ostream &Out, key_type_ref, + void EmitData(raw_ostream &Out, key_type_ref, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.isImport << 4) - | (Data.isPragmaOnce << 3) - | (Data.DirInfo << 1) - | Data.Resolved; + unsigned char Flags = (Data.isImport << 5) + | (Data.isPragmaOnce << 4) + | (Data.DirInfo << 2) + | (Data.Resolved << 1) + | Data.IndexHeaderMapHeader; Emit8(Out, (uint8_t)Flags); Emit16(Out, (uint16_t) Data.NumIncludes); @@ -1318,8 +1273,29 @@ namespace { Emit32(Out, (uint32_t)Data.ControllingMacroID); else Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro)); + + unsigned Offset = 0; + if (!Data.Framework.empty()) { + // If this header refers into a framework, save the framework name. + llvm::StringMap<unsigned>::iterator Pos + = FrameworkNameOffset.find(Data.Framework); + if (Pos == FrameworkNameOffset.end()) { + Offset = FrameworkStringData.size() + 1; + FrameworkStringData.append(Data.Framework.begin(), + Data.Framework.end()); + FrameworkStringData.push_back(0); + + FrameworkNameOffset[Data.Framework] = Offset; + } else + Offset = Pos->second; + } + Emit32(Out, Offset); + assert(Out.tell() - Start == DataLen && "Wrong data length"); } + + const char *strings_begin() const { return FrameworkStringData.begin(); } + const char *strings_end() const { return FrameworkStringData.end(); } }; } // end anonymous namespace @@ -1328,8 +1304,8 @@ namespace { /// \param HS The header search structure to save. /// /// \param Chain Whether we're creating a chained AST file. -void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) { - llvm::SmallVector<const FileEntry *, 16> FilesByUID; +void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot) { + SmallVector<const FileEntry *, 16> FilesByUID; HS.getFileMgr().GetUniqueIDMapping(FilesByUID); if (FilesByUID.size() > HS.header_file_size()) @@ -1337,7 +1313,7 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) { HeaderFileInfoTrait GeneratorTrait(*this, HS); OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; - llvm::SmallVector<const char *, 4> SavedStrings; + SmallVector<const char *, 4> SavedStrings; unsigned NumHeaderSearchEntries = 0; for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { const FileEntry *File = FilesByUID[UID]; @@ -1379,14 +1355,17 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) { Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev); - // Write the stat cache + // Write the header search table RecordData Record; Record.push_back(HEADER_SEARCH_TABLE); Record.push_back(BucketOffset); Record.push_back(NumHeaderSearchEntries); + Record.push_back(TableData.size()); + TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end()); Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str()); // Free all of the strings we had to duplicate. @@ -1404,7 +1383,7 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, const char* isysroot) { /// the files in the AST. void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP, - const char *isysroot) { + StringRef isysroot) { RecordData Record; // Enter the source manager block. @@ -1416,43 +1395,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream); unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream); - // Write the line table. - if (SourceMgr.hasLineTable()) { - LineTableInfo &LineTable = SourceMgr.getLineTable(); - - // Emit the file names - Record.push_back(LineTable.getNumFilenames()); - for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { - // Emit the file name - const char *Filename = LineTable.getFilename(I); - Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); - unsigned FilenameLen = Filename? strlen(Filename) : 0; - Record.push_back(FilenameLen); - if (FilenameLen) - Record.insert(Record.end(), Filename, Filename + FilenameLen); - } - - // Emit the line entries - for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); - L != LEnd; ++L) { - // Emit the file ID - Record.push_back(L->first); - - // Emit the line entries - Record.push_back(L->second.size()); - for (std::vector<LineEntry>::iterator LE = L->second.begin(), - LEEnd = L->second.end(); - LE != LEEnd; ++LE) { - Record.push_back(LE->FileOffset); - Record.push_back(LE->LineNo); - Record.push_back(LE->FilenameID); - Record.push_back((unsigned)LE->FileKind); - Record.push_back(LE->IncludeOffset); - } - } - Stream.EmitRecord(SM_LINE_TABLE, Record); - } - // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector<uint32_t> SLocEntryOffsets; @@ -1460,12 +1402,11 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // We will go through them in ASTReader::validateFileEntries(). std::vector<uint32_t> SLocFileEntryOffsets; RecordData PreloadSLocs; - unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0; - SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID); - for (unsigned I = BaseSLocID + 1, N = SourceMgr.sloc_entry_size(); + SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1); + for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. - const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); @@ -1483,7 +1424,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.clear(); Record.push_back(Code); - Record.push_back(SLoc->getOffset()); + // Starting offset of this entry within this module, so skip the dummy. + Record.push_back(SLoc->getOffset() - 2); if (SLoc->isFile()) { const SrcMgr::FileInfo &File = SLoc->getFile(); Record.push_back(File.getIncludeLoc().getRawEncoding()); @@ -1502,6 +1444,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(Content->OrigEntry->getSize()); Record.push_back(Content->OrigEntry->getModificationTime()); + Record.push_back(File.NumCreatedFIDs); + // Turn the file name into an absolute path, if it isn't already. const char *Filename = Content->OrigEntry->getName(); llvm::SmallString<128> FilePath(Filename); @@ -1528,27 +1472,29 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); const char *Name = Buffer->getBufferIdentifier(); Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, - llvm::StringRef(Name, strlen(Name) + 1)); + StringRef(Name, strlen(Name) + 1)); Record.clear(); Record.push_back(SM_SLOC_BUFFER_BLOB); Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, - llvm::StringRef(Buffer->getBufferStart(), + StringRef(Buffer->getBufferStart(), Buffer->getBufferSize() + 1)); - if (strcmp(Name, "<built-in>") == 0) - PreloadSLocs.push_back(BaseSLocID + SLocEntryOffsets.size()); + if (strcmp(Name, "<built-in>") == 0) { + PreloadSLocs.push_back(SLocEntryOffsets.size()); + } } } else { // The source location entry is a macro expansion. - const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation(); - Record.push_back(Inst.getSpellingLoc().getRawEncoding()); - Record.push_back(Inst.getInstantiationLocStart().getRawEncoding()); - Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding()); + const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion(); + Record.push_back(Expansion.getSpellingLoc().getRawEncoding()); + Record.push_back(Expansion.getExpansionLocStart().getRawEncoding()); + Record.push_back(Expansion.isMacroArgExpansion() ? 0 + : Expansion.getExpansionLocEnd().getRawEncoding()); // Compute the token length for this macro expansion. - unsigned NextOffset = SourceMgr.getNextOffset(); + unsigned NextOffset = SourceMgr.getNextLocalOffset(); if (I + 1 != N) - NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset(); + NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset(); Record.push_back(NextOffset - SLoc->getOffset() - 1); Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record); } @@ -1565,15 +1511,14 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(SOURCE_LOCATION_OFFSETS); Record.push_back(SLocEntryOffsets.size()); - unsigned BaseOffset = Chain ? Chain->getNextSLocOffset() : 0; - Record.push_back(SourceMgr.getNextOffset() - BaseOffset); + Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); Abbrev = new BitCodeAbbrev(); @@ -1591,6 +1536,49 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); + + // Write the line table. It depends on remapping working, so it must come + // after the source location offsets. + if (SourceMgr.hasLineTable()) { + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + Record.clear(); + // Emit the file names + Record.push_back(LineTable.getNumFilenames()); + for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { + // Emit the file name + const char *Filename = LineTable.getFilename(I); + Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); + unsigned FilenameLen = Filename? strlen(Filename) : 0; + Record.push_back(FilenameLen); + if (FilenameLen) + Record.insert(Record.end(), Filename, Filename + FilenameLen); + } + + // Emit the line entries + for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); + L != LEnd; ++L) { + // Only emit entries for local files. + if (L->first < 0) + continue; + + // Emit the file ID + Record.push_back(L->first); + + // Emit the line entries + Record.push_back(L->second.size()); + for (std::vector<LineEntry>::iterator LE = L->second.begin(), + LEEnd = L->second.end(); + LE != LEEnd; ++LE) { + Record.push_back(LE->FileOffset); + Record.push_back(LE->LineNo); + Record.push_back(LE->FilenameID); + Record.push_back((unsigned)LE->FileKind); + Record.push_back(LE->IncludeOffset); + } + } + Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record); + } } //===----------------------------------------------------------------------===// @@ -1608,7 +1596,11 @@ static int compareMacroDefinitions(const void *XPtr, const void *YPtr) { /// \brief Writes the block containing the serialized form of the /// preprocessor. /// -void ASTWriter::WritePreprocessor(const Preprocessor &PP) { +void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { + PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); + if (PPRec) + WritePreprocessorDetail(*PPRec); + RecordData Record; // If the preprocessor __COUNTER__ value has been bumped, remember it. @@ -1629,17 +1621,18 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. - PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); // Construct the list of macro definitions that need to be serialized. - llvm::SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2> + SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2> MacrosToEmit; llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen; for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), E = PP.macro_end(Chain == 0); I != E; ++I) { - MacroDefinitionsSeen.insert(I->first); - MacrosToEmit.push_back(std::make_pair(I->first, I->second)); + if (!IsModule || I->second->isExported()) { + MacroDefinitionsSeen.insert(I->first); + MacrosToEmit.push_back(std::make_pair(I->first, I->second)); + } } // Sort the set of macro definitions that need to be serialized by the @@ -1671,14 +1664,15 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { // chained PCH, by storing the offset into the original PCH rather than // writing the macro definition a second time. if (MI->isBuiltinMacro() || - (Chain && Name->isFromAST() && MI->isFromAST())) + (Chain && Name->isFromAST() && MI->isFromAST() && + !MI->hasChangedAfterLoad())) continue; AddIdentifierRef(Name, Record); MacroOffsets[Name] = Stream.GetCurrentBitNo(); Record.push_back(MI->getDefinitionLoc().getRawEncoding()); Record.push_back(MI->isUsed()); - + AddSourceLocation(MI->getExportLocation(), Record); unsigned Code; if (MI->isObjectLike()) { Code = PP_MACRO_OBJECT_LIKE; @@ -1696,7 +1690,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { // If we have a detailed preprocessing record, record the macro definition // ID that corresponds to this macro. if (PPRec) - Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI))); + Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); Stream.EmitRecord(Code, Record); Record.clear(); @@ -1725,15 +1719,14 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { ++NumMacros; } Stream.ExitBlock(); - - if (PPRec) - WritePreprocessorDetail(*PPRec); } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { - if (PPRec.begin(Chain) == PPRec.end(Chain)) + if (PPRec.local_begin() == PPRec.local_end()) return; - + + SmallVector<PPEntityOffset, 64> PreprocessedEntityOffsets; + // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3); @@ -1746,9 +1739,6 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // start location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // end location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind @@ -1756,65 +1746,41 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { InclusionAbbrev = Stream.EmitAbbrev(Abbrev); } - unsigned IndexBase = Chain ? PPRec.getNumPreallocatedEntities() : 0; + unsigned FirstPreprocessorEntityID + = (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0) + + NUM_PREDEF_PP_ENTITY_IDS; + unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID; RecordData Record; - for (PreprocessingRecord::iterator E = PPRec.begin(Chain), - EEnd = PPRec.end(Chain); - E != EEnd; ++E) { + for (PreprocessingRecord::iterator E = PPRec.local_begin(), + EEnd = PPRec.local_end(); + E != EEnd; + (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) { Record.clear(); + PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(), + Stream.GetCurrentBitNo())); + if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) { - // Record this macro definition's location. - MacroID ID = getMacroDefinitionID(MD); - - // Don't write the macro definition if it is from another AST file. - if (ID < FirstMacroID) - continue; + // Record this macro definition's ID. + MacroDefinitions[MD] = NextPreprocessorEntityID; - // Notify the serialization listener that we're serializing this entity. - if (SerializationListener) - SerializationListener->SerializedPreprocessedEntity(*E, - Stream.GetCurrentBitNo()); - - unsigned Position = ID - FirstMacroID; - if (Position != MacroDefinitionOffsets.size()) { - if (Position > MacroDefinitionOffsets.size()) - MacroDefinitionOffsets.resize(Position + 1); - - MacroDefinitionOffsets[Position] = Stream.GetCurrentBitNo(); - } else - MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); - - Record.push_back(IndexBase + NumPreprocessingRecords++); - Record.push_back(ID); - AddSourceLocation(MD->getSourceRange().getBegin(), Record); - AddSourceLocation(MD->getSourceRange().getEnd(), Record); AddIdentifierRef(MD->getName(), Record); - AddSourceLocation(MD->getLocation(), Record); Stream.EmitRecord(PPD_MACRO_DEFINITION, Record); continue; } - // Notify the serialization listener that we're serializing this entity. - if (SerializationListener) - SerializationListener->SerializedPreprocessedEntity(*E, - Stream.GetCurrentBitNo()); - if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) { - Record.push_back(IndexBase + NumPreprocessingRecords++); - AddSourceLocation(ME->getSourceRange().getBegin(), Record); - AddSourceLocation(ME->getSourceRange().getEnd(), Record); - AddIdentifierRef(ME->getName(), Record); - Record.push_back(getMacroDefinitionID(ME->getDefinition())); + Record.push_back(ME->isBuiltinMacro()); + if (ME->isBuiltinMacro()) + AddIdentifierRef(ME->getName(), Record); + else + Record.push_back(MacroDefinitions[ME->getDefinition()]); Stream.EmitRecord(PPD_MACRO_EXPANSION, Record); continue; } if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) { Record.push_back(PPD_INCLUSION_DIRECTIVE); - Record.push_back(IndexBase + NumPreprocessingRecords++); - AddSourceLocation(ID->getSourceRange().getBegin(), Record); - AddSourceLocation(ID->getSourceRange().getEnd(), Record); Record.push_back(ID->getFileName().size()); Record.push_back(ID->wasInQuotes()); Record.push_back(static_cast<unsigned>(ID->getKind())); @@ -1831,40 +1797,39 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { // Write the offsets table for the preprocessing record. if (NumPreprocessingRecords > 0) { + assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords); + // Write the offsets table for identifier IDs. using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(MACRO_DEFINITION_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs + Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); - Record.push_back(MACRO_DEFINITION_OFFSETS); - Record.push_back(NumPreprocessingRecords); - Record.push_back(MacroDefinitionOffsets.size()); - Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, - data(MacroDefinitionOffsets)); + Record.push_back(PPD_ENTITIES_OFFSETS); + Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS); + Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, + data(PreprocessedEntityOffsets)); } } -void ASTWriter::WritePragmaDiagnosticMappings(const Diagnostic &Diag) { +void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) { RecordData Record; - for (Diagnostic::DiagStatePointsTy::const_iterator + for (DiagnosticsEngine::DiagStatePointsTy::const_iterator I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end(); I != E; ++I) { - const Diagnostic::DiagStatePoint &point = *I; + const DiagnosticsEngine::DiagStatePoint &point = *I; if (point.Loc.isInvalid()) continue; Record.push_back(point.Loc.getRawEncoding()); - for (Diagnostic::DiagState::iterator + for (DiagnosticsEngine::DiagState::const_iterator I = point.State->begin(), E = point.State->end(); I != E; ++I) { - unsigned diag = I->first, map = I->second; - if (map & 0x10) { // mapping from a diagnostic pragma. - Record.push_back(diag); - Record.push_back(map & 0x7); + if (I->second.isPragma()) { + Record.push_back(I->first); + Record.push_back(I->second.getMapping()); } } Record.push_back(-1); // mark the end of the diag/map pairs for this @@ -1890,7 +1855,7 @@ void ASTWriter::WriteCXXBaseSpecifiersOffsets() { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - // Write the selector offsets table. + // Write the base specifier offsets table. Record.clear(); Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); Record.push_back(CXXBaseSpecifiersOffsets.size()); @@ -1964,7 +1929,7 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, uint64_t Offset = Stream.GetCurrentBitNo(); RecordData Record; Record.push_back(DECL_CONTEXT_LEXICAL); - llvm::SmallVector<KindDeclIDPair, 64> Decls; + SmallVector<KindDeclIDPair, 64> Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D))); @@ -1982,22 +1947,26 @@ void ASTWriter::WriteTypeDeclOffsets() { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(TYPE_OFFSET); Record.push_back(TypeOffsets.size()); + Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS); Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets)); // Write the declaration offsets array Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(DECL_OFFSET); Record.push_back(DeclOffsets.size()); + Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS); Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets)); } @@ -2027,7 +1996,7 @@ public: } std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel, + EmitKeyDataLength(raw_ostream& Out, Selector Sel, data_type_ref Methods) { unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); clang::io::Emit16(Out, KeyLen); @@ -2044,7 +2013,7 @@ public: return std::make_pair(KeyLen, DataLen); } - void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) { + void EmitKey(raw_ostream& Out, Selector Sel, unsigned) { uint64_t Start = Out.tell(); assert((Start >> 32) == 0 && "Selector key offset too large"); Writer.SetSelectorOffset(Sel, Start); @@ -2057,7 +2026,7 @@ public: Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); } - void EmitData(llvm::raw_ostream& Out, key_type_ref, + void EmitData(raw_ostream& Out, key_type_ref, data_type_ref Methods, unsigned DataLen) { uint64_t Start = Out.tell(); (void)Start; clang::io::Emit32(Out, Methods.ID); @@ -2130,12 +2099,12 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { bool changed = false; for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method; M = M->Next) { - if (M->Method->getPCHLevel() == 0) + if (!M->Method->isFromASTFile()) changed = true; } for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method; M = M->Next) { - if (M->Method->getPCHLevel() == 0) + if (!M->Method->isFromASTFile()) changed = true; } if (!changed) @@ -2177,6 +2146,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); @@ -2184,6 +2154,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { Record.clear(); Record.push_back(SELECTOR_OFFSETS); Record.push_back(SelectorOffsets.size()); + Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS); Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, data(SelectorOffsets)); } @@ -2219,41 +2190,53 @@ namespace { class ASTIdentifierTableTrait { ASTWriter &Writer; Preprocessor &PP; - + bool IsModule; + /// \brief Determines whether this is an "interesting" identifier /// that needs a full IdentifierInfo structure written into the hash /// table. - static bool isInterestingIdentifier(const IdentifierInfo *II) { - return II->isPoisoned() || - II->isExtensionToken() || - II->hasMacroDefinition() || - II->getObjCOrBuiltinID() || - II->getFETokenInfo<void>(); + bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) { + if (II->isPoisoned() || + II->isExtensionToken() || + II->getObjCOrBuiltinID() || + II->getFETokenInfo<void>()) + return true; + + return hasMacroDefinition(II, Macro); + } + + bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) { + if (!II->hasMacroDefinition()) + return false; + + if (Macro || (Macro = PP.getMacroInfo(II))) + return !Macro->isBuiltinMacro() && (!IsModule || Macro->isExported()); + + return false; } public: - typedef const IdentifierInfo* key_type; + typedef IdentifierInfo* key_type; typedef key_type key_type_ref; typedef IdentID data_type; typedef data_type data_type_ref; - ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP) - : Writer(Writer), PP(PP) { } + ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, bool IsModule) + : Writer(Writer), PP(PP), IsModule(IsModule) { } static unsigned ComputeHash(const IdentifierInfo* II) { return llvm::HashString(II->getName()); } std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, - IdentID ID) { + EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 - if (isInterestingIdentifier(II)) { + MacroInfo *Macro = 0; + if (isInterestingIdentifier(II, Macro)) { DataLen += 2; // 2 bytes for builtin ID, flags - if (II->hasMacroDefinition() && - !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro()) + if (hasMacroDefinition(II, Macro)) DataLen += 4; for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), DEnd = IdentifierResolver::end(); @@ -2268,7 +2251,7 @@ public: return std::make_pair(KeyLen, DataLen); } - void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II, + void EmitKey(raw_ostream& Out, const IdentifierInfo* II, unsigned KeyLen) { // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. @@ -2276,27 +2259,26 @@ public: Out.write(II->getNameStart(), KeyLen); } - void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, + void EmitData(raw_ostream& Out, IdentifierInfo* II, IdentID ID, unsigned) { - if (!isInterestingIdentifier(II)) { + MacroInfo *Macro = 0; + if (!isInterestingIdentifier(II, Macro)) { clang::io::Emit32(Out, ID << 1); return; } clang::io::Emit32(Out, (ID << 1) | 0x01); uint32_t Bits = 0; - bool hasMacroDefinition = - II->hasMacroDefinition() && - !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro(); + bool HasMacroDefinition = hasMacroDefinition(II, Macro); Bits = (uint32_t)II->getObjCOrBuiltinID(); - Bits = (Bits << 1) | unsigned(hasMacroDefinition); + Bits = (Bits << 1) | unsigned(HasMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); clang::io::Emit16(Out, Bits); - if (hasMacroDefinition) + if (HasMacroDefinition) clang::io::Emit32(Out, Writer.getMacroOffset(II)); // Emit the declaration IDs in reverse order, because the @@ -2306,9 +2288,9 @@ public: // adds declarations to the end of the list (so we need to see the // struct "status" before the function "status"). // Only emit declarations that aren't from a chained PCH, though. - llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II), + SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II), IdentifierResolver::end()); - for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), + for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) clang::io::Emit32(Out, Writer.getDeclID(*D)); @@ -2321,14 +2303,14 @@ public: /// The identifier table consists of a blob containing string data /// (the actual identifiers themselves) and a separate "offsets" index /// that maps identifier IDs to locations within the blob. -void ASTWriter::WriteIdentifierTable(Preprocessor &PP) { +void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) { using namespace llvm; // Create and write out the blob that contains the identifier // strings. { OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; - ASTIdentifierTableTrait Trait(*this, PP); + ASTIdentifierTableTrait Trait(*this, PP, IsModule); // Look for any identifiers that were named while processing the // headers, but are otherwise not needed. We add these to the hash @@ -2348,14 +2330,15 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) { ID != IDEnd; ++ID) { assert(ID->first && "NULL identifier in identifier table"); if (!Chain || !ID->first->isFromAST()) - Generator.insert(ID->first, ID->second, Trait); + Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second, + Trait); } // Create the on-disk hash table in a buffer. llvm::SmallString<4096> IdentifierTable; uint32_t BucketOffset; { - ASTIdentifierTableTrait Trait(*this, PP); + ASTIdentifierTableTrait Trait(*this, PP, IsModule); llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); @@ -2380,12 +2363,14 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); RecordData Record; Record.push_back(IDENTIFIER_OFFSET); Record.push_back(IdentifierOffsets.size()); + Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS); Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, data(IdentifierOffsets)); } @@ -2424,7 +2409,6 @@ public: case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: - ID.AddInteger(Writer.GetOrCreateTypeID(Name.getCXXNameType())); break; case DeclarationName::CXXOperatorName: ID.AddInteger(Name.getCXXOverloadedOperator()); @@ -2439,7 +2423,7 @@ public: } std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, DeclarationName Name, + EmitKeyDataLength(raw_ostream& Out, DeclarationName Name, data_type_ref Lookup) { unsigned KeyLen = 1; switch (Name.getNameKind()) { @@ -2447,15 +2431,15 @@ public: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXLiteralOperatorName: KeyLen += 4; break; case DeclarationName::CXXOperatorName: KeyLen += 1; break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } @@ -2468,7 +2452,7 @@ public: return std::make_pair(KeyLen, DataLen); } - void EmitKey(llvm::raw_ostream& Out, DeclarationName Name, unsigned) { + void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { using namespace clang::io; assert(Name.getNameKind() < 0x100 && "Invalid name kind ?"); @@ -2482,11 +2466,6 @@ public: case DeclarationName::ObjCMultiArgSelector: Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector())); break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - Emit32(Out, Writer.getTypeID(Name.getCXXNameType())); - break; case DeclarationName::CXXOperatorName: assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?"); Emit8(Out, Name.getCXXOverloadedOperator()); @@ -2494,12 +2473,15 @@ public: case DeclarationName::CXXLiteralOperatorName: Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } } - void EmitData(llvm::raw_ostream& Out, key_type_ref, + void EmitData(raw_ostream& Out, key_type_ref, data_type Lookup, unsigned DataLen) { uint64_t Start = Out.tell(); (void)Start; clang::io::Emit16(Out, Lookup.second - Lookup.first); @@ -2534,9 +2516,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, return 0; // Force the DeclContext to build a its name-lookup table. - if (DC->hasExternalVisibleStorage()) - DC->MaterializeVisibleDeclsFromExternalStorage(); - else + if (!DC->hasExternalVisibleStorage()) DC->lookup(DeclarationName()); // Serialize the contents of the mapping used for lookup. Note that, @@ -2553,13 +2533,37 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, ASTDeclContextNameLookupTrait Trait(*this); // Create the on-disk hash table representation. + DeclarationName ConversionName; + llvm::SmallVector<NamedDecl *, 4> ConversionDecls; for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { DeclarationName Name = D->first; DeclContext::lookup_result Result = D->second.getLookupResult(); - Generator.insert(Name, Result, Trait); + if (Result.first != Result.second) { + if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + // Hash all conversion function names to the same name. The actual + // type information in conversion function name is not used in the + // key (since such type information is not stable across different + // modules), so the intended effect is to coalesce all of the conversion + // functions under a single key. + if (!ConversionName) + ConversionName = Name; + ConversionDecls.append(Result.first, Result.second); + continue; + } + + Generator.insert(Name, Result, Trait); + } } + // Add the conversion functions + if (!ConversionDecls.empty()) { + Generator.insert(ConversionName, + DeclContext::lookup_result(ConversionDecls.begin(), + ConversionDecls.end()), + Trait); + } + // Create the on-disk hash table in a buffer. llvm::SmallString<4096> LookupTable; uint32_t BucketOffset; @@ -2602,7 +2606,8 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { DeclContext::lookup_result Result = D->second.getLookupResult(); // For any name that appears in this table, the results are complete, i.e. // they overwrite results from previous PCHs. Merging is always a mess. - Generator.insert(Name, Result, Trait); + if (Result.first != Result.second) + Generator.insert(Name, Result, Trait); } // Create the on-disk hash table in a buffer. @@ -2652,14 +2657,14 @@ void ASTWriter::WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record) { for (AttrVec::const_iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i){ const Attr * A = *i; Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs - AddSourceLocation(A->getLocation(), Record); + AddSourceRange(A->getRange(), Record); #include "clang/Serialization/AttrPCHWrite.inc" } } -void ASTWriter::AddString(llvm::StringRef Str, RecordDataImpl &Record) { +void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { Record.push_back(Str.size()); Record.insert(Record.end(), Str.begin(), Str.end()); } @@ -2700,15 +2705,15 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) - : Stream(Stream), Chain(0), SerializationListener(0), - FirstDeclID(1), NextDeclID(FirstDeclID), + : Stream(Stream), Context(0), Chain(0), WritingAST(false), + FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), - FirstIdentID(1), NextIdentID(FirstIdentID), FirstSelectorID(1), - NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID), + FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), + FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumVisibleDeclContexts(0), - FirstCXXBaseSpecifiersID(1), NextCXXBaseSpecifiersID(1), + NextCXXBaseSpecifiersID(1), DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0), DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0), @@ -2721,7 +2726,9 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, const std::string &OutputFile, - const char *isysroot) { + bool IsModule, StringRef isysroot) { + WritingAST = true; + // Emit the file header. Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'P', 8); @@ -2730,30 +2737,53 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteBlockInfoBlock(); - if (Chain) - WriteASTChain(SemaRef, StatCalls, isysroot); - else - WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile); + Context = &SemaRef.Context; + WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, IsModule); + Context = 0; + + WritingAST = false; +} + +template<typename Vector> +static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, + ASTWriter::RecordData &Record) { + for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end(); + I != E; ++I) { + Writer.AddDeclRef(*I, Record); + } } void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char *isysroot, - const std::string &OutputFile) { + StringRef isysroot, + const std::string &OutputFile, bool IsModule) { using namespace llvm; ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; - // The translation unit is the first declaration we'll emit. - DeclIDs[Context.getTranslationUnitDecl()] = 1; - ++NextDeclID; - DeclTypesToEmit.push(Context.getTranslationUnitDecl()); - - // Make sure that we emit IdentifierInfos (and any attached - // declarations) for builtins. - { + // Set up predefined declaration IDs. + DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID; + if (Context.ObjCIdDecl) + DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID; + if (Context.ObjCSelDecl) + DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID; + if (Context.ObjCClassDecl) + DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID; + if (Context.Int128Decl) + DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID; + if (Context.UInt128Decl) + DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID; + if (Context.ObjCInstanceTypeDecl) + DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; + + if (!Chain) { + // Make sure that we emit IdentifierInfos (and any attached + // declarations) for builtins. We don't need to do this when we're + // emitting chained PCH files, because all of the builtins will be + // in the original PCH file. + // FIXME: Modules won't like this at all. IdentifierTable &Table = PP.getIdentifierTable(); - llvm::SmallVector<const char *, 32> BuiltinNames; + SmallVector<const char *, 32> BuiltinNames; Context.BuiltinInfo.GetBuiltinNames(BuiltinNames, Context.getLangOptions().NoBuiltin); for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I) @@ -2764,24 +2794,24 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // TentativeDefinitions order. Generally, this record will be empty for // headers. RecordData TentativeDefinitions; - for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) { - AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions); - } - + AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions); + // Build a record containing all of the file scoped decls in this file. RecordData UnusedFileScopedDecls; - for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) - AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); + AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, + UnusedFileScopedDecls); + // Build a record containing all of the delegating constructors we still need + // to resolve. RecordData DelegatingCtorDecls; - for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) - AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); + AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); + // Write the set of weak, undeclared identifiers. We always write the + // entire table, since later PCH files in a PCH chain are only interested in + // the results at the end of the chain. RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { - WeakUndeclaredIdentifiers.push_back( - SemaRef.WeakUndeclaredIdentifiers.size()); - for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator + for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = SemaRef.WeakUndeclaredIdentifiers.begin(), E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) { AddIdentifierRef(I->first, WeakUndeclaredIdentifiers); @@ -2800,18 +2830,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator TD = SemaRef.LocallyScopedExternalDecls.begin(), TDEnd = SemaRef.LocallyScopedExternalDecls.end(); - TD != TDEnd; ++TD) - AddDeclRef(TD->second, LocallyScopedExternalDecls); - + TD != TDEnd; ++TD) { + if (!TD->second->isFromASTFile()) + AddDeclRef(TD->second, LocallyScopedExternalDecls); + } + // Build a record containing all of the ext_vector declarations. RecordData ExtVectorDecls; - for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) - AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls); + AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls); // Build a record containing all of the VTable uses information. RecordData VTableUses; if (!SemaRef.VTableUses.empty()) { - VTableUses.push_back(SemaRef.VTableUses.size()); for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); @@ -2821,8 +2851,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Build a record containing all of dynamic classes declarations. RecordData DynamicClasses; - for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I) - AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses); + AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses); // Build a record containing all of pending implicit instantiations. RecordData PendingInstantiations; @@ -2862,155 +2891,65 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, Stream.EnterSubblock(AST_BLOCK_ID, 5); WriteMetadata(Context, isysroot, OutputFile); WriteLanguageOptions(Context.getLangOptions()); - if (StatCalls && !isysroot) + if (StatCalls && isysroot.empty()) WriteStatCache(*StatCalls); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - // Write the record of special types. - Record.clear(); - - AddTypeRef(Context.getBuiltinVaListType(), Record); - AddTypeRef(Context.getObjCIdType(), Record); - AddTypeRef(Context.getObjCSelType(), Record); - AddTypeRef(Context.getObjCProtoType(), Record); - AddTypeRef(Context.getObjCClassType(), Record); - AddTypeRef(Context.getRawCFConstantStringType(), Record); - AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record); - AddTypeRef(Context.getFILEType(), Record); - AddTypeRef(Context.getjmp_bufType(), Record); - AddTypeRef(Context.getsigjmp_bufType(), Record); - AddTypeRef(Context.ObjCIdRedefinitionType, Record); - AddTypeRef(Context.ObjCClassRedefinitionType, Record); - AddTypeRef(Context.getRawBlockdescriptorType(), Record); - AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); - AddTypeRef(Context.ObjCSelRedefinitionType, Record); - AddTypeRef(Context.getRawNSConstantStringType(), Record); - Record.push_back(Context.isInt128Installed()); - AddTypeRef(Context.AutoDeductTy, Record); - AddTypeRef(Context.AutoRRefDeductTy, Record); - Stream.EmitRecord(SPECIAL_TYPES, Record); - - // Keep writing types and declarations until all types and - // declarations have been written. - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); - WriteDeclsBlockAbbrevs(); - while (!DeclTypesToEmit.empty()) { - DeclOrType DOT = DeclTypesToEmit.front(); - DeclTypesToEmit.pop(); - if (DOT.isType()) - WriteType(DOT.getType()); - else - WriteDecl(Context, DOT.getDecl()); - } - Stream.ExitBlock(); - - WritePreprocessor(PP); - WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); - WriteSelectors(SemaRef); - WriteReferencedSelectorsPool(SemaRef); - WriteIdentifierTable(PP); - WriteFPPragmaOptions(SemaRef.getFPOptions()); - WriteOpenCLExtensions(SemaRef); - - WriteTypeDeclOffsets(); - WritePragmaDiagnosticMappings(Context.getDiagnostics()); - - WriteCXXBaseSpecifiersOffsets(); - - // Write the record containing external, unnamed definitions. - if (!ExternalDefinitions.empty()) - Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions); - - // Write the record containing tentative definitions. - if (!TentativeDefinitions.empty()) - Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions); - - // Write the record containing unused file scoped decls. - if (!UnusedFileScopedDecls.empty()) - Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls); - - // Write the record containing weak undeclared identifiers. - if (!WeakUndeclaredIdentifiers.empty()) - Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS, - WeakUndeclaredIdentifiers); - - // Write the record containing locally-scoped external definitions. - if (!LocallyScopedExternalDecls.empty()) - Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS, - LocallyScopedExternalDecls); - - // Write the record containing ext_vector type names. - if (!ExtVectorDecls.empty()) - Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls); - - // Write the record containing VTable uses information. - if (!VTableUses.empty()) - Stream.EmitRecord(VTABLE_USES, VTableUses); - - // Write the record containing dynamic classes declarations. - if (!DynamicClasses.empty()) - Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses); - - // Write the record containing pending implicit instantiations. - if (!PendingInstantiations.empty()) - Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations); - - // Write the record containing declaration references of Sema. - if (!SemaDeclRefs.empty()) - Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); - - // Write the record containing CUDA-specific declaration references. - if (!CUDASpecialDeclRefs.empty()) - Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); - // Write the delegating constructors. - if (!DelegatingCtorDecls.empty()) - Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); - - // Write the known namespaces. - if (!KnownNamespaces.empty()) - Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces); - - // Some simple statistics - Record.clear(); - Record.push_back(NumStatements); - Record.push_back(NumMacros); - Record.push_back(NumLexicalDeclContexts); - Record.push_back(NumVisibleDeclContexts); - Stream.EmitRecord(STATISTICS, Record); - Stream.ExitBlock(); -} - -void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char *isysroot) { - using namespace llvm; - - ASTContext &Context = SemaRef.Context; - Preprocessor &PP = SemaRef.PP; - - RecordData Record; - Stream.EnterSubblock(AST_BLOCK_ID, 5); - WriteMetadata(Context, isysroot, ""); - if (StatCalls && !isysroot) - WriteStatCache(*StatCalls); - // FIXME: Source manager block should only write new stuff, which could be - // done by tracking the largest ID in the chain - WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - - // The special types are in the chained PCH. + if (Chain) { + // Write the mapping information describing our module dependencies and how + // each of those modules were mapped into our own offset/ID space, so that + // the reader can build the appropriate mapping to its own offset/ID space. + // The map consists solely of a blob with the following format: + // *(module-name-len:i16 module-name:len*i8 + // source-location-offset:i32 + // identifier-id:i32 + // preprocessed-entity-id:i32 + // macro-definition-id:i32 + // selector-id:i32 + // declaration-id:i32 + // c++-base-specifiers-id:i32 + // type-id:i32) + // + llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); + llvm::SmallString<2048> Buffer; + { + llvm::raw_svector_ostream Out(Buffer); + for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(), + MEnd = Chain->ModuleMgr.end(); + M != MEnd; ++M) { + StringRef FileName = (*M)->FileName; + io::Emit16(Out, FileName.size()); + Out.write(FileName.data(), FileName.size()); + io::Emit32(Out, (*M)->SLocEntryBaseOffset); + io::Emit32(Out, (*M)->BaseIdentifierID); + io::Emit32(Out, (*M)->BasePreprocessedEntityID); + io::Emit32(Out, (*M)->BaseSelectorID); + io::Emit32(Out, (*M)->BaseDeclID); + io::Emit32(Out, (*M)->BaseTypeIndex); + } + } + Record.clear(); + Record.push_back(MODULE_OFFSET_MAP); + Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, + Buffer.data(), Buffer.size()); + } - // We don't start with the translation unit, but with its decls that - // don't come from the chained PCH. + // Create a lexical update block containing all of the declarations in the + // translation unit that do not come from other AST files. const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - llvm::SmallVector<KindDeclIDPair, 64> NewGlobalDecls; + SmallVector<KindDeclIDPair, 64> NewGlobalDecls; for (DeclContext::decl_iterator I = TU->noload_decls_begin(), E = TU->noload_decls_end(); I != E; ++I) { - if ((*I)->getPCHLevel() == 0) + if (!(*I)->isFromASTFile()) NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I))); else if ((*I)->isChangedSinceDeserialization()) (void)GetDeclRef(*I); // Make sure it's written, but don't record it. } - // We also need to write a lexical updates block for the TU. + llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); @@ -3019,7 +2958,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, Record.push_back(TU_UPDATE_LEXICAL); Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, data(NewGlobalDecls)); - // And a visible updates block for the DeclContexts. + + // And a visible updates block for the translation unit. Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); @@ -3027,108 +2967,41 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv); WriteDeclContextVisibleUpdate(TU); - - // Build a record containing all of the new tentative definitions in this - // file, in TentativeDefinitions order. - RecordData TentativeDefinitions; - for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) { - if (SemaRef.TentativeDefinitions[i]->getPCHLevel() == 0) - AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions); - } - - // Build a record containing all of the file scoped decls in this file. - RecordData UnusedFileScopedDecls; - for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) { - if (SemaRef.UnusedFileScopedDecls[i]->getPCHLevel() == 0) - AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls); - } - - // Build a record containing all of the delegating constructor decls in this - // file. - RecordData DelegatingCtorDecls; - for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) { - if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0) - AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls); - } - - // We write the entire table, overwriting the tables from the chain. - RecordData WeakUndeclaredIdentifiers; - if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { - WeakUndeclaredIdentifiers.push_back( - SemaRef.WeakUndeclaredIdentifiers.size()); - for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator - I = SemaRef.WeakUndeclaredIdentifiers.begin(), - E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) { - AddIdentifierRef(I->first, WeakUndeclaredIdentifiers); - AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers); - AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers); - WeakUndeclaredIdentifiers.push_back(I->second.getUsed()); - } - } - - // Build a record containing all of the locally-scoped external - // declarations in this header file. Generally, this record will be - // empty. - RecordData LocallyScopedExternalDecls; - // FIXME: This is filling in the AST file in densemap order which is - // nondeterminstic! - for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator - TD = SemaRef.LocallyScopedExternalDecls.begin(), - TDEnd = SemaRef.LocallyScopedExternalDecls.end(); - TD != TDEnd; ++TD) { - if (TD->second->getPCHLevel() == 0) - AddDeclRef(TD->second, LocallyScopedExternalDecls); - } - - // Build a record containing all of the ext_vector declarations. - RecordData ExtVectorDecls; - for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) { - if (SemaRef.ExtVectorDecls[I]->getPCHLevel() == 0) - AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls); - } - - // Build a record containing all of the VTable uses information. - // We write everything here, because it's too hard to determine whether - // a use is new to this part. - RecordData VTableUses; - if (!SemaRef.VTableUses.empty()) { - VTableUses.push_back(SemaRef.VTableUses.size()); - for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { - AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); - AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); - VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]); + + // If the translation unit has an anonymous namespace, and we don't already + // have an update block for it, write it as an update block. + if (NamespaceDecl *NS = TU->getAnonymousNamespace()) { + ASTWriter::UpdateRecord &Record = DeclUpdates[TU]; + if (Record.empty()) { + Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE); + Record.push_back(reinterpret_cast<uint64_t>(NS)); } } - - // Build a record containing all of dynamic classes declarations. - RecordData DynamicClasses; - for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I) - if (SemaRef.DynamicClasses[I]->getPCHLevel() == 0) - AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses); - - // Build a record containing all of pending implicit instantiations. - RecordData PendingInstantiations; - for (std::deque<Sema::PendingImplicitInstantiation>::iterator - I = SemaRef.PendingInstantiations.begin(), - N = SemaRef.PendingInstantiations.end(); I != N; ++I) { - AddDeclRef(I->first, PendingInstantiations); - AddSourceLocation(I->second, PendingInstantiations); - } - assert(SemaRef.PendingLocalImplicitInstantiations.empty() && - "There are local ones at end of translation unit!"); - - // Build a record containing some declaration references. - // It's not worth the effort to avoid duplication here. - RecordData SemaDeclRefs; - if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) { - AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs); - AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); - } - + + // Resolve any declaration pointers within the declaration updates block and + // chained Objective-C categories block to declaration IDs. + ResolveDeclUpdatesBlocks(); + ResolveChainedObjCCategories(); + + // Form the record of special types. + RecordData SpecialTypes; + AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes); + AddTypeRef(Context.ObjCProtoType, SpecialTypes); + AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); + AddTypeRef(Context.getFILEType(), SpecialTypes); + AddTypeRef(Context.getjmp_bufType(), SpecialTypes); + AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes); + AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes); + AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); + AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); + + // Keep writing types and declarations until all types and + // declarations have been written. Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); WriteDeclsBlockAbbrevs(); - for (DeclsToRewriteTy::iterator - I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I) + for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), + E = DeclsToRewrite.end(); + I != E; ++I) DeclTypesToEmit.push(const_cast<Decl*>(*I)); while (!DeclTypesToEmit.empty()) { DeclOrType DOT = DeclTypesToEmit.front(); @@ -3140,30 +3013,31 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, } Stream.ExitBlock(); - WritePreprocessor(PP); + WritePreprocessor(PP, IsModule); + WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); - WriteIdentifierTable(PP); + WriteIdentifierTable(PP, IsModule); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); WriteTypeDeclOffsets(); - // FIXME: For chained PCH only write the new mappings (we currently - // write all of them again). WritePragmaDiagnosticMappings(Context.getDiagnostics()); WriteCXXBaseSpecifiersOffsets(); + + Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes); /// Build a record containing first declarations from a chained PCH and the /// most recent declarations in this AST that they point to. RecordData FirstLatestDeclIDs; - for (FirstLatestDeclMap::iterator - I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) { - assert(I->first->getPCHLevel() > I->second->getPCHLevel() && - "Expected first & second to be in different PCHs"); + for (FirstLatestDeclMap::iterator I = FirstLatestDecls.begin(), + E = FirstLatestDecls.end(); + I != E; ++I) { AddDeclRef(I->first, FirstLatestDeclIDs); AddDeclRef(I->second, FirstLatestDeclIDs); } + if (!FirstLatestDeclIDs.empty()) Stream.EmitRecord(REDECLS_UPDATE_LATEST, FirstLatestDeclIDs); @@ -3208,30 +3082,70 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing declaration references of Sema. if (!SemaDeclRefs.empty()) Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); + + // Write the record containing CUDA-specific declaration references. + if (!CUDASpecialDeclRefs.empty()) + Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); // Write the delegating constructors. if (!DelegatingCtorDecls.empty()) Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); - // Write the updates to DeclContexts. + // Write the known namespaces. + if (!KnownNamespaces.empty()) + Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces); + + // Write the visible updates to DeclContexts. for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator - I = UpdatedDeclContexts.begin(), - E = UpdatedDeclContexts.end(); - I != E; ++I) + I = UpdatedDeclContexts.begin(), + E = UpdatedDeclContexts.end(); + I != E; ++I) WriteDeclContextVisibleUpdate(*I); WriteDeclUpdatesBlocks(); + WriteDeclReplacementsBlock(); + WriteChainedObjCCategories(); + // Some simple statistics Record.clear(); Record.push_back(NumStatements); Record.push_back(NumMacros); Record.push_back(NumLexicalDeclContexts); Record.push_back(NumVisibleDeclContexts); - WriteDeclReplacementsBlock(); Stream.EmitRecord(STATISTICS, Record); Stream.ExitBlock(); } +/// \brief Go through the declaration update blocks and resolve declaration +/// pointers into declaration IDs. +void ASTWriter::ResolveDeclUpdatesBlocks() { + for (DeclUpdateMap::iterator + I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { + const Decl *D = I->first; + UpdateRecord &URec = I->second; + + if (DeclsToRewrite.count(D)) + continue; // The decl will be written completely + + unsigned Idx = 0, N = URec.size(); + while (Idx < N) { + switch ((DeclUpdateKind)URec[Idx++]) { + case UPD_CXX_SET_DEFINITIONDATA: + case UPD_CXX_ADDED_IMPLICIT_MEMBER: + case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: + case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: + URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx])); + ++Idx; + break; + + case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: + ++Idx; + break; + } + } + } +} + void ASTWriter::WriteDeclUpdatesBlocks() { if (DeclUpdates.empty()) return; @@ -3261,7 +3175,7 @@ void ASTWriter::WriteDeclReplacementsBlock() { return; RecordData Record; - for (llvm::SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator + for (SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) { Record.push_back(I->first); Record.push_back(I->second); @@ -3269,6 +3183,37 @@ void ASTWriter::WriteDeclReplacementsBlock() { Stream.EmitRecord(DECL_REPLACEMENTS, Record); } +void ASTWriter::ResolveChainedObjCCategories() { + for (SmallVector<ChainedObjCCategoriesData, 16>::iterator + I = LocalChainedObjCCategories.begin(), + E = LocalChainedObjCCategories.end(); I != E; ++I) { + ChainedObjCCategoriesData &Data = *I; + Data.InterfaceID = GetDeclRef(Data.Interface); + Data.TailCategoryID = GetDeclRef(Data.TailCategory); + } + +} + +void ASTWriter::WriteChainedObjCCategories() { + if (LocalChainedObjCCategories.empty()) + return; + + RecordData Record; + for (SmallVector<ChainedObjCCategoriesData, 16>::iterator + I = LocalChainedObjCCategories.begin(), + E = LocalChainedObjCCategories.end(); I != E; ++I) { + ChainedObjCCategoriesData &Data = *I; + serialization::DeclID + HeadCatID = getDeclID(Data.Interface->getCategoryList()); + assert(HeadCatID != 0 && "Category not written ?"); + + Record.push_back(Data.InterfaceID); + Record.push_back(HeadCatID); + Record.push_back(Data.TailCategoryID); + } + Stream.EmitRecord(OBJC_CHAINED_CATEGORIES, Record); +} + void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) { Record.push_back(Loc.getRawEncoding()); } @@ -3307,16 +3252,6 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } -MacroID ASTWriter::getMacroDefinitionID(MacroDefinition *MD) { - if (MD == 0) - return 0; - - MacroID &ID = MacroDefinitions[MD]; - if (ID == 0) - ID = NextMacroID++; - return ID; -} - void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { Record.push_back(getSelectorRef(SelRef)); } @@ -3416,13 +3351,13 @@ void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) { Record.push_back(GetOrCreateTypeID(T)); } -TypeID ASTWriter::GetOrCreateTypeID(QualType T) { - return MakeTypeID(T, +TypeID ASTWriter::GetOrCreateTypeID( QualType T) { + return MakeTypeID(*Context, T, std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this)); } TypeID ASTWriter::getTypeID(QualType T) const { - return MakeTypeID(T, + return MakeTypeID(*Context, T, std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this)); } @@ -3456,6 +3391,8 @@ void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) { } DeclID ASTWriter::GetDeclRef(const Decl *D) { + assert(WritingAST && "Cannot request a declaration ID before AST writing"); + if (D == 0) { return 0; } @@ -3571,7 +3508,7 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. - llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames; + SmallVector<NestedNameSpecifier *, 8> NestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. while (NNS) { @@ -3614,7 +3551,7 @@ void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. - llvm::SmallVector<NestedNameSpecifierLoc , 8> NestedNames; + SmallVector<NestedNameSpecifierLoc , 8> NestedNames; // Push each of the nested-name-specifiers's onto a stack for // serialization in reverse order. @@ -3805,7 +3742,7 @@ void ASTWriter::FlushCXXBaseSpecifiers() { Record.clear(); // Record the offset of this base-specifier set. - unsigned Index = CXXBaseSpecifiersToWrite[I].ID - FirstCXXBaseSpecifiersID; + unsigned Index = CXXBaseSpecifiersToWrite[I].ID - 1; if (Index == CXXBaseSpecifiersOffsets.size()) CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo()); else { @@ -3871,7 +3808,9 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; Record.push_back(Data.UserDeclaredConstructor); Record.push_back(Data.UserDeclaredCopyConstructor); + Record.push_back(Data.UserDeclaredMoveConstructor); Record.push_back(Data.UserDeclaredCopyAssignment); + Record.push_back(Data.UserDeclaredMoveAssignment); Record.push_back(Data.UserDeclaredDestructor); Record.push_back(Data.Aggregate); Record.push_back(Data.PlainOldData); @@ -3885,7 +3824,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasPublicFields); Record.push_back(Data.HasMutableFields); Record.push_back(Data.HasTrivialDefaultConstructor); - Record.push_back(Data.HasConstExprNonCopyMoveConstructor); + Record.push_back(Data.HasConstexprNonCopyMoveConstructor); Record.push_back(Data.HasTrivialCopyConstructor); Record.push_back(Data.HasTrivialMoveConstructor); Record.push_back(Data.HasTrivialCopyAssignment); @@ -3896,8 +3835,12 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.UserProvidedDefaultConstructor); Record.push_back(Data.DeclaredDefaultConstructor); Record.push_back(Data.DeclaredCopyConstructor); + Record.push_back(Data.DeclaredMoveConstructor); Record.push_back(Data.DeclaredCopyAssignment); + Record.push_back(Data.DeclaredMoveAssignment); Record.push_back(Data.DeclaredDestructor); + Record.push_back(Data.FailedImplicitMoveConstructor); + Record.push_back(Data.FailedImplicitMoveAssignment); Record.push_back(Data.NumBases); if (Data.NumBases > 0) @@ -3918,28 +3861,23 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec void ASTWriter::ReaderInitialized(ASTReader *Reader) { assert(Reader && "Cannot remove chain"); - assert(!Chain && "Cannot replace chain"); + assert((!Chain || Chain == Reader) && "Cannot replace chain"); assert(FirstDeclID == NextDeclID && FirstTypeID == NextTypeID && FirstIdentID == NextIdentID && FirstSelectorID == NextSelectorID && - FirstMacroID == NextMacroID && - FirstCXXBaseSpecifiersID == NextCXXBaseSpecifiersID && "Setting chain after writing has started."); + Chain = Reader; - FirstDeclID += Chain->getTotalNumDecls(); - FirstTypeID += Chain->getTotalNumTypes(); - FirstIdentID += Chain->getTotalNumIdentifiers(); - FirstSelectorID += Chain->getTotalNumSelectors(); - FirstMacroID += Chain->getTotalNumMacroDefinitions(); - FirstCXXBaseSpecifiersID += Chain->getTotalNumCXXBaseSpecifiers(); + FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls(); + FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); + FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers(); + FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors(); NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; NextSelectorID = FirstSelectorID; - NextMacroID = FirstMacroID; - NextCXXBaseSpecifiersID = FirstCXXBaseSpecifiersID; } void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { @@ -3967,16 +3905,18 @@ void ASTWriter::SelectorRead(SelectorID ID, Selector S) { SelectorIDs[S] = ID; } -void ASTWriter::MacroDefinitionRead(serialization::MacroID ID, +void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID, MacroDefinition *MD) { + assert(MacroDefinitions.find(MD) == MacroDefinitions.end()); MacroDefinitions[MD] = ID; } void ASTWriter::CompletedTagDefinition(const TagDecl *D) { - assert(D->isDefinition()); + assert(D->isCompleteDefinition()); + assert(!WritingAST && "Already writing the AST!"); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { // We are interested when a PCH decl is modified. - if (RD->getPCHLevel() > 0) { + if (RD->isFromASTFile()) { // A forward reference was mutated into a definition. Rewrite it. // FIXME: This happens during template instantiation, should we // have created a new definition decl instead ? @@ -3990,67 +3930,73 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) { continue; // We are interested when a PCH decl is modified. - if (Redecl->getPCHLevel() > 0) { + if (Redecl->isFromASTFile()) { UpdateRecord &Record = DeclUpdates[Redecl]; Record.push_back(UPD_CXX_SET_DEFINITIONDATA); assert(Redecl->DefinitionData); assert(Redecl->DefinitionData->Definition == D); - AddDeclRef(D, Record); // the DefinitionDecl + Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl } } } } void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { + assert(!WritingAST && "Already writing the AST!"); + // TU and namespaces are handled elsewhere. if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC)) return; - if (!(D->getPCHLevel() == 0 && cast<Decl>(DC)->getPCHLevel() > 0)) + if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile())) return; // Not a source decl added to a DeclContext from PCH. AddUpdatedDeclContext(DC); } void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { + assert(!WritingAST && "Already writing the AST!"); assert(D->isImplicit()); - if (!(D->getPCHLevel() == 0 && RD->getPCHLevel() > 0)) + if (!(!D->isFromASTFile() && RD->isFromASTFile())) return; // Not a source member added to a class from PCH. if (!isa<CXXMethodDecl>(D)) return; // We are interested in lazily declared implicit methods. // A decl coming from PCH was modified. - assert(RD->isDefinition()); + assert(RD->isCompleteDefinition()); UpdateRecord &Record = DeclUpdates[RD]; Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER); - AddDeclRef(D, Record); + Record.push_back(reinterpret_cast<uint64_t>(D)); } void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { // The specializations set is kept in the canonical template. + assert(!WritingAST && "Already writing the AST!"); TD = TD->getCanonicalDecl(); - if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0)) + if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. UpdateRecord &Record = DeclUpdates[TD]; Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); - AddDeclRef(D, Record); + Record.push_back(reinterpret_cast<uint64_t>(D)); } void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) { // The specializations set is kept in the canonical template. + assert(!WritingAST && "Already writing the AST!"); TD = TD->getCanonicalDecl(); - if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0)) + if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. UpdateRecord &Record = DeclUpdates[TD]; Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); - AddDeclRef(D, Record); + Record.push_back(reinterpret_cast<uint64_t>(D)); } void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { - if (D->getPCHLevel() == 0) + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) return; // Declaration not imported from PCH. // Implicit decl from a PCH was defined. @@ -4059,7 +4005,8 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { } void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { - if (D->getPCHLevel() == 0) + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) return; // Since the actual instantiation is delayed, this really means that we need @@ -4070,4 +4017,16 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record); } -ASTSerializationListener::~ASTSerializationListener() { } +void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD) { + assert(!WritingAST && "Already writing the AST!"); + if (!IFD->isFromASTFile()) + return; // Declaration not imported from PCH. + if (CatD->getNextClassCategory() && + !CatD->getNextClassCategory()->isFromASTFile()) + return; // We already recorded that the tail of a category chain should be + // attached to an interface. + + ChainedObjCCategoriesData Data = { IFD, CatD, 0, 0 }; + LocalChainedObjCCategories.push_back(Data); +} diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp index 2b83494..a8243e5 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -65,6 +65,8 @@ namespace clang { ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); + void VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); @@ -153,13 +155,11 @@ void ASTDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isUsed(false)); Record.push_back(D->isReferenced()); Record.push_back(D->getAccess()); - Record.push_back(D->getPCHLevel()); + Record.push_back(D->ModulePrivate); } void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - VisitDecl(D); - Writer.AddDeclRef(D->getAnonymousNamespace(), Record); - Code = serialization::DECL_TRANSLATION_UNIT; + llvm_unreachable("Translation units aren't directly serialized"); } void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) { @@ -180,11 +180,11 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && - D->getPCHLevel() == 0 && D->RedeclLink.getNext() == D && !D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none && + !D->isModulePrivate() && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclTypedefAbbrev(); @@ -202,8 +202,9 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) { VisitRedeclarable(D); Record.push_back(D->getIdentifierNamespace()); Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding - Record.push_back(D->isDefinition()); + Record.push_back(D->isCompleteDefinition()); Record.push_back(D->isEmbeddedInDeclarator()); + Record.push_back(D->isFreeStanding()); Writer.AddSourceLocation(D->getRBraceLoc(), Record); Record.push_back(D->hasExtInfo()); if (D->hasExtInfo()) @@ -228,12 +229,12 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && - D->getPCHLevel() == 0 && !D->hasExtInfo() && D->RedeclLink.getNext() == D && !D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none && + !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && D->getDeclName().getNameKind() == DeclarationName::Identifier) @@ -251,12 +252,12 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && - D->getPCHLevel() == 0 && !D->hasExtInfo() && D->RedeclLink.getNext() == D && !D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none && + !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclRecordAbbrev(); @@ -295,8 +296,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->getIdentifierNamespace()); Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { - default: assert(false && "Unhandled TemplatedKind!"); - break; + default: llvm_unreachable("Unhandled TemplatedKind!"); case FunctionDecl::TK_NonTemplate: break; case FunctionDecl::TK_FunctionTemplate: @@ -321,13 +321,14 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { // Template args as written. Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0); if (FTSInfo->TemplateArgumentsAsWritten) { - Record.push_back(FTSInfo->TemplateArgumentsAsWritten->size()); - for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->size(); i!=e; ++i) + Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs); + for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs; + i!=e; ++i) Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i], Record); - Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getLAngleLoc(), + Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc, Record); - Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getRAngleLoc(), + Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc, Record); } @@ -375,6 +376,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->isDefaulted()); Record.push_back(D->isExplicitlyDefaulted()); Record.push_back(D->hasImplicitReturnZero()); + Record.push_back(D->isConstexpr()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->param_size()); @@ -400,12 +402,19 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Record.push_back(D->isVariadic()); Record.push_back(D->isSynthesized()); Record.push_back(D->isDefined()); + + Record.push_back(D->IsRedeclaration); + Record.push_back(D->HasRedeclaration); + if (D->HasRedeclaration) { + assert(Context.getObjCMethodRedeclaration(D)); + Writer.AddDeclRef(Context.getObjCMethodRedeclaration(D), Record); + } + // FIXME: stable encoding for @required/@optional Record.push_back(D->getImplementationControl()); // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway Record.push_back(D->getObjCDeclQualifier()); Record.push_back(D->hasRelatedResultType()); - Record.push_back(D->getNumSelectorArgs()); Writer.AddTypeRef(D->getResultType(), Record); Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); @@ -413,11 +422,20 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { for (ObjCMethodDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + + Record.push_back(D->SelLocsKind); + unsigned NumStoredSelLocs = D->getNumStoredSelLocs(); + SourceLocation *SelLocs = D->getStoredSelLocs(); + Record.push_back(NumStoredSelLocs); + for (unsigned i = 0; i != NumStoredSelLocs; ++i) + Writer.AddSourceLocation(SelLocs[i], Record); + Code = serialization::DECL_OBJC_METHOD; } void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAtStartLoc(), Record); Writer.AddSourceRange(D->getAtEndRange(), Record); // Abstract class (no need to define a stable serialization::DECL code). } @@ -454,7 +472,6 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { Writer.AddDeclRef(D->getCategoryList(), Record); Record.push_back(D->isForwardDecl()); Record.push_back(D->isImplicitInterfaceDecl()); - Writer.AddSourceLocation(D->getClassLoc(), Record); Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); Code = serialization::DECL_OBJC_INTERFACE; @@ -471,7 +488,7 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && - D->getPCHLevel() == 0 && + !D->isModulePrivate() && !D->getBitWidth() && !D->hasExtInfo() && D->getDeclName()) @@ -502,11 +519,8 @@ void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { void ASTDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { VisitDecl(D); - Record.push_back(D->size()); - for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddDeclRef(I->getInterface(), Record); - for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddSourceLocation(I->getLocation(), Record); + Writer.AddDeclRef(D->getForwardInterfaceDecl(), Record); + Writer.AddSourceLocation(D->getForwardDecl()->getLocation(), Record); Code = serialization::DECL_OBJC_CLASS; } @@ -536,7 +550,6 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { Writer.AddSourceLocation(*PL, Record); Writer.AddDeclRef(D->getNextClassCategory(), Record); Record.push_back(D->hasSynthBitfield()); - Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Code = serialization::DECL_OBJC_CATEGORY; } @@ -612,7 +625,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && - D->getPCHLevel() == 0 && + !D->isModulePrivate() && !D->getBitWidth() && !D->hasInClassInitializer() && !D->hasExtInfo() && @@ -665,7 +678,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none && - D->getPCHLevel() == 0 && + !D->isModulePrivate() && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && D->RedeclLink.getNext() == D && @@ -706,7 +719,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { !D->isImplicit() && !D->isUsed(false) && D->getAccess() == AS_none && - D->getPCHLevel() == 0 && + !D->isModulePrivate() && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? D->getFunctionScopeDepth() == 0 && @@ -793,7 +806,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { Code = serialization::DECL_NAMESPACE; if (Writer.hasChain() && !D->isOriginalNamespace() && - D->getOriginalNamespace()->getPCHLevel() > 0) { + D->getOriginalNamespace()->isFromASTFile()) { NamespaceDecl *NS = D->getOriginalNamespace(); Writer.AddUpdatedDeclContext(NS); @@ -819,7 +832,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { // anonymous namespace. Decl *Parent = cast<Decl>( D->getParent()->getRedeclContext()->getPrimaryContext()); - if (Parent->getPCHLevel() > 0) { + if (Parent->isFromASTFile() || isa<TranslationUnitDecl>(Parent)) { ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent]; Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE); Writer.AddDeclRef(D, Record); @@ -909,7 +922,7 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { // Store the key function to avoid deserializing every method so we can // compute it. - if (D->IsDefinition) + if (D->IsCompleteDefinition) Writer.AddDeclRef(Context.getKeyFunction(D), Record); Code = serialization::DECL_CXX_RECORD; @@ -1015,7 +1028,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // in a chained PCH, keep track of the association with the map so we can // update the first decl during AST reading. if (First->getMostRecentDeclaration() == D && - First->getPCHLevel() > D->getPCHLevel()) { + First->isFromASTFile() && !D->isFromASTFile()) { assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end() && "The latest is already set"); Writer.FirstLatestDecls[First] = D; @@ -1058,16 +1071,12 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl( llvm::PointerUnion<ClassTemplateDecl *, ClassTemplatePartialSpecializationDecl *> InstFrom = D->getSpecializedTemplateOrPartial(); - Decl *InstFromD; - if (InstFrom.is<ClassTemplateDecl *>()) { - InstFromD = InstFrom.get<ClassTemplateDecl *>(); + if (Decl *InstFromD = InstFrom.dyn_cast<ClassTemplateDecl *>()) { Writer.AddDeclRef(InstFromD, Record); } else { - InstFromD = InstFrom.get<ClassTemplatePartialSpecializationDecl *>(); - Writer.AddDeclRef(InstFromD, Record); + Writer.AddDeclRef(InstFrom.get<ClassTemplatePartialSpecializationDecl *>(), + Record); Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); - InstFromD = cast<ClassTemplatePartialSpecializationDecl>(InstFromD)-> - getSpecializedTemplate(); } // Explicit info. @@ -1110,6 +1119,14 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } +void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D) { + VisitDecl(D); + Writer.AddDeclRef(D->getSpecialization(), Record); + Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION; +} + + void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); @@ -1233,7 +1250,7 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { // in a chained PCH, keep track of the association with the map so we can // update the first decl during AST reading. if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl && - First->getPCHLevel() > ThisDecl->getPCHLevel()) { + First->isFromASTFile() && !ThisDecl->isFromASTFile()) { assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end() && "The latest is already set"); Writer.FirstLatestDecls[First] = ThisDecl; @@ -1262,7 +1279,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1293,7 +1310,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1327,7 +1344,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1339,8 +1356,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { // TagDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl @@ -1372,7 +1390,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1384,8 +1402,9 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { // TagDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl @@ -1411,7 +1430,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1459,7 +1478,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1484,7 +1503,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name @@ -1527,6 +1546,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location DeclRefExprAbbrev = Stream.EmitAbbrev(Abv); @@ -1592,8 +1612,11 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { /// relatively painless since they would presumably only do it for top-level /// decls. static bool isRequiredDecl(const Decl *D, ASTContext &Context) { + // An ObjCMethodDecl is never considered as "required" because its + // implementation container always is. + // File scoped assembly or obj-c implementation must be seen. - if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplementationDecl>(D)) + if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D)) return true; return Context.DeclMustBeEmitted(D); @@ -1648,7 +1671,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); if (!W.Code) - llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") + + llvm::report_fatal_error(StringRef("unexpected declaration kind '") + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp index 1d73ed4..7e2d45c 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -36,7 +36,7 @@ namespace clang { : Writer(Writer), Record(Record) { } void - AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args); + AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args); void VisitStmt(Stmt *S); #define STMT(Type, Base) \ @@ -46,7 +46,7 @@ namespace clang { } void ASTStmtWriter:: -AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args) { +AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args) { Writer.AddSourceLocation(Args.LAngleLoc, Record); Writer.AddSourceLocation(Args.RAngleLoc, Record); for (unsigned i=0; i != Args.NumTemplateArgs; ++i) @@ -59,7 +59,7 @@ void ASTStmtWriter::VisitStmt(Stmt *S) { void ASTStmtWriter::VisitNullStmt(NullStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getSemiLoc(), Record); - Writer.AddSourceLocation(S->LeadingEmptyMacro, Record); + Record.push_back(S->HasLeadingEmptyMacro); Code = serialization::STMT_NULL; } @@ -265,6 +265,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { Record.push_back(E->hasQualifier()); Record.push_back(E->getDecl() != E->getFoundDecl()); Record.push_back(E->hasExplicitTemplateArgs()); + Record.push_back(E->hadMultipleCandidates()); if (E->hasExplicitTemplateArgs()) { unsigned NumTemplateArgs = E->getNumTemplateArgs(); @@ -324,7 +325,7 @@ void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) { VisitExpr(E); Record.push_back(E->getByteLength()); Record.push_back(E->getNumConcatenated()); - Record.push_back(E->isWide()); + Record.push_back(E->getKind()); Record.push_back(E->isPascal()); // FIXME: String data should be stored as a blob at the end of the // StringLiteral. However, we can't do so now because we have no @@ -340,7 +341,7 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { VisitExpr(E); Record.push_back(E->getValue()); Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->isWide()); + Record.push_back(E->getKind()); AbbrevToUse = Writer.getCharacterLiteralAbbrev(); @@ -457,7 +458,9 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) { for (unsigned i=0; i != NumTemplateArgs; ++i) Writer.AddTemplateArgumentLoc(E->getTemplateArgs()[i], Record); } - + + Record.push_back(E->hadMultipleCandidates()); + DeclAccessPair FoundDecl = E->getFoundDecl(); Writer.AddDeclRef(FoundDecl.getDecl(), Record); Record.push_back(FoundDecl.getAccess()); @@ -733,6 +736,21 @@ void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) { Code = serialization::EXPR_GENERIC_SELECTION; } +void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) { + VisitExpr(E); + Record.push_back(E->getOp()); + Writer.AddStmt(E->getPtr()); + Writer.AddStmt(E->getOrder()); + if (E->getOp() != AtomicExpr::Load) + Writer.AddStmt(E->getVal1()); + if (E->isCmpXChg()) { + Writer.AddStmt(E->getOrderFail()); + Writer.AddStmt(E->getVal2()); + } + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements. //===----------------------------------------------------------------------===// @@ -806,6 +824,8 @@ void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); + Record.push_back(E->getNumStoredSelLocs()); + Record.push_back(E->SelLocsKind); Record.push_back(E->isDelegateInitCall()); Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding switch (E->getReceiverKind()) { @@ -834,11 +854,15 @@ void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { Writer.AddSourceLocation(E->getLeftLoc(), Record); Writer.AddSourceLocation(E->getRightLoc(), Record); - Writer.AddSourceLocation(E->getSelectorLoc(), Record); for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) Writer.AddStmt(*Arg); + + SourceLocation *Locs = E->getStoredSelLocs(); + for (unsigned i = 0, e = E->getNumStoredSelLocs(); i != e; ++i) + Writer.AddSourceLocation(Locs[i], Record); + Code = serialization::EXPR_OBJC_MESSAGE_EXPR; } @@ -952,6 +976,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Writer.AddDeclRef(E->getConstructor(), Record); Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isElidable()); + Record.push_back(E->hadMultipleCandidates()); Record.push_back(E->requiresZeroInitialization()); Record.push_back(E->getConstructionKind()); // FIXME: stable encoding Writer.AddSourceRange(E->getParenRange(), Record); @@ -1071,6 +1096,7 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { Record.push_back(E->hasInitializer()); Record.push_back(E->doesUsualArrayDeleteWantSize()); Record.push_back(E->isArray()); + Record.push_back(E->hadMultipleCandidates()); Record.push_back(E->getNumPlacementArgs()); Record.push_back(E->getNumConstructorArgs()); Writer.AddDeclRef(E->getOperatorNew(), Record); @@ -1142,7 +1168,7 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); + const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs(); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); } @@ -1168,7 +1194,7 @@ ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { // emitted first. Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); + const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs(); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); } @@ -1197,7 +1223,7 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) { // Don't emit anything here, hasExplicitTemplateArgs() must be emitted first. Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); + const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs(); Record.push_back(Args.NumTemplateArgs); AddExplicitTemplateArgumentList(Args); } @@ -1428,7 +1454,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) { } // Redirect ASTWriter::AddStmt to collect sub stmts. - llvm::SmallVector<Stmt *, 16> SubStmts; + SmallVector<Stmt *, 16> SubStmts; CollectedStmts = &SubStmts; Writer.Code = serialization::STMT_NULL_PTR; @@ -1440,7 +1466,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) { SourceManager &SrcMgr = DeclIDs.begin()->first->getASTContext().getSourceManager(); S->dump(SrcMgr); - assert(0 && "Unhandled sub statement writing AST file"); + llvm_unreachable("Unhandled sub statement writing AST file"); } #endif diff --git a/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp index 3b7cd23..5fcf11a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp @@ -26,17 +26,20 @@ using namespace clang; static ASTReader *createASTReader(CompilerInstance &CI, - llvm::StringRef pchFile, - llvm::MemoryBuffer **memBufs, - unsigned numBufs, + StringRef pchFile, + SmallVector<llvm::MemoryBuffer *, 4> &memBufs, + SmallVector<std::string, 4> &bufNames, ASTDeserializationListener *deserialListener = 0) { Preprocessor &PP = CI.getPreprocessor(); llvm::OwningPtr<ASTReader> Reader; - Reader.reset(new ASTReader(PP, &CI.getASTContext(), /*isysroot=*/0, + Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"", /*DisableValidation=*/true)); - Reader->setASTMemoryBuffers(memBufs, numBufs); + for (unsigned ti = 0; ti < bufNames.size(); ++ti) { + StringRef sr(bufNames[ti]); + Reader->addInMemoryBuffer(sr, memBufs[ti]); + } Reader->setDeserializationListener(deserialListener); - switch (Reader->ReadAST(pchFile, ASTReader::PCH)) { + switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. PP.setPredefines(Reader->getSuggestedPredefines()); @@ -62,7 +65,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource()); InputKind IK = CI.getFrontendOpts().Inputs[0].first; - llvm::SmallVector<llvm::MemoryBuffer *, 4> serialBufs; + SmallVector<llvm::MemoryBuffer *, 4> serialBufs; + SmallVector<std::string, 4> serialBufNames; for (unsigned i = 0, e = includes.size(); i != e; ++i) { bool firstInclude = (i == 0); @@ -83,8 +87,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, - DiagClient)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient)); llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); Clang->setInvocation(CInvok.take()); @@ -98,16 +102,15 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { &Clang->getPreprocessor()); Clang->createASTContext(); - llvm::SmallVector<char, 256> serialAST; + SmallVector<char, 256> serialAST; llvm::raw_svector_ostream OS(serialAST); llvm::OwningPtr<ASTConsumer> consumer; consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", - /*Chaining=*/!firstInclude, - /*isysroot=*/0, &OS)); + /*IsModule=*/false, /*isysroot=*/"", &OS)); Clang->getASTContext().setASTMutationListener( consumer->GetASTMutationListener()); Clang->setASTConsumer(consumer.take()); - Clang->createSema(/*CompleteTranslationUnit=*/false, 0); + Clang->createSema(TU_Prefix, 0); if (firstInclude) { Preprocessor &PP = Clang->getPreprocessor(); @@ -115,19 +118,23 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { PP.getLangOptions()); } else { assert(!serialBufs.empty()); - llvm::SmallVector<llvm::MemoryBuffer *, 4> bufs; + SmallVector<llvm::MemoryBuffer *, 4> bufs; for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) { bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy( - llvm::StringRef(serialBufs[si]->getBufferStart(), + StringRef(serialBufs[si]->getBufferStart(), serialBufs[si]->getBufferSize()))); } std::string pchName = includes[i-1]; llvm::raw_string_ostream os(pchName); os << ".pch" << i-1; os.flush(); + + serialBufNames.push_back(pchName); + llvm::OwningPtr<ExternalASTSource> Reader; - Reader.reset(createASTReader(*Clang, pchName, bufs.data(), bufs.size(), - Clang->getASTConsumer().GetASTDeserializationListener())); + + Reader.reset(createASTReader(*Clang, pchName, bufs, serialBufNames, + Clang->getASTConsumer().GetASTDeserializationListener())); if (!Reader) return 0; Clang->getASTContext().setExternalSource(Reader); @@ -140,16 +147,16 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { OS.flush(); Clang->getDiagnosticClient().EndSourceFile(); serialBufs.push_back( - llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(serialAST.data(), + llvm::MemoryBuffer::getMemBufferCopy(StringRef(serialAST.data(), serialAST.size()))); source->CIs.push_back(Clang.take()); } assert(!serialBufs.empty()); std::string pchName = includes.back() + ".pch-final"; + serialBufNames.push_back(pchName); llvm::OwningPtr<ASTReader> Reader; - Reader.reset(createASTReader(CI, pchName, - serialBufs.data(), serialBufs.size())); + Reader.reset(createASTReader(CI, pchName, serialBufs, serialBufNames)); if (!Reader) return 0; @@ -182,13 +189,10 @@ ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { return getFinalReader().FindExternalVisibleDeclsByName(DC, Name); } -void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) { - return getFinalReader().MaterializeVisibleDecls(DC); -} ExternalLoadResult ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), - llvm::SmallVectorImpl<Decl*> &Result) { + SmallVectorImpl<Decl*> &Result) { return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result); } void ChainedIncludesSource::CompleteType(TagDecl *Tag) { diff --git a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp index b8833ce..a2534db 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp @@ -27,31 +27,29 @@ using namespace clang; PCHGenerator::PCHGenerator(const Preprocessor &PP, - const std::string &OutputFile, - bool Chaining, - const char *isysroot, - llvm::raw_ostream *OS) - : PP(PP), OutputFile(OutputFile), isysroot(isysroot), Out(OS), SemaPtr(0), - StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) { + StringRef OutputFile, + bool IsModule, + StringRef isysroot, + raw_ostream *OS) + : PP(PP), OutputFile(OutputFile), IsModule(IsModule), + isysroot(isysroot.str()), Out(OS), + SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) { // Install a stat() listener to keep track of all of the stat() // calls. StatCalls = new MemorizeStatCalls(); - // If we have a chain, we want new stat calls only, so install the memorizer - // *after* the already installed ASTReader's stat cache. - PP.getFileManager().addStatCache(StatCalls, - /*AtBeginning=*/!Chaining); + PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false); +} + +PCHGenerator::~PCHGenerator() { } void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { if (PP.getDiagnostics().hasErrorOccurred()) return; - - // Set up the serialization listener. - Writer.SetSerializationListener(GetASTSerializationListener()); // Emit the PCH file assert(SemaPtr && "No Sema?"); - Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, isysroot); + Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, IsModule, isysroot); // Write the generated bitstream to "Out". Out->write((char *)&Buffer.front(), Buffer.size()); @@ -64,13 +62,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { } ASTMutationListener *PCHGenerator::GetASTMutationListener() { - if (Chaining) - return &Writer; - return 0; -} - -ASTSerializationListener *PCHGenerator::GetASTSerializationListener() { - return 0; + return &Writer; } ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { diff --git a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp new file mode 100644 index 0000000..0a721c4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp @@ -0,0 +1,109 @@ +//===--- Module.cpp - Module description ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Module class, which describes a module that has +// been loaded from an AST file. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/Module.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "ASTReaderInternals.h" + +using namespace clang; +using namespace serialization; +using namespace reader; + +Module::Module(ModuleKind Kind) + : Kind(Kind), DirectlyImported(false), SizeInBits(0), + LocalNumSLocEntries(0), SLocEntryBaseID(0), + SLocEntryBaseOffset(0), SLocEntryOffsets(0), + SLocFileOffsets(0), LocalNumIdentifiers(0), + IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0), + IdentifierLookupTable(0), BasePreprocessedEntityID(0), + PreprocessedEntityOffsets(0), NumPreprocessedEntities(0), + LocalNumHeaderFileInfos(0), + HeaderFileInfoTableData(0), HeaderFileInfoTable(0), + HeaderFileFrameworkStrings(0), + LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0), + SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), + DeclOffsets(0), BaseDeclID(0), + LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), + LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0) +{} + +Module::~Module() { + for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(), + E = DeclContextInfos.end(); + I != E; ++I) { + if (I->second.NameLookupTableData) + delete static_cast<ASTDeclContextNameLookupTable*>( + I->second.NameLookupTableData); + } + + delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable); + delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable); + delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable); +} + +template<typename Key, typename Offset, unsigned InitialCapacity> +static void +dumpLocalRemap(StringRef Name, + const ContinuousRangeMap<Key, Offset, InitialCapacity> &Map) { + if (Map.begin() == Map.end()) + return; + + typedef ContinuousRangeMap<Key, Offset, InitialCapacity> MapType; + llvm::errs() << " " << Name << ":\n"; + for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); + I != IEnd; ++I) { + llvm::errs() << " " << I->first << " -> " << I->second << "\n"; + } +} + +void Module::dump() { + llvm::errs() << "\nModule: " << FileName << "\n"; + if (!Imports.empty()) { + llvm::errs() << " Imports: "; + for (unsigned I = 0, N = Imports.size(); I != N; ++I) { + if (I) + llvm::errs() << ", "; + llvm::errs() << Imports[I]->FileName; + } + llvm::errs() << "\n"; + } + + // Remapping tables. + llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset + << '\n'; + dumpLocalRemap("Source location offset local -> global map", SLocRemap); + + llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n' + << " Number of identifiers: " << LocalNumIdentifiers << '\n'; + dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap); + + llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n' + << " Number of selectors: " << LocalNumSelectors << '\n'; + dumpLocalRemap("Selector ID local -> global map", SelectorRemap); + + llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID + << '\n' + << " Number of preprocessed entities: " + << NumPreprocessedEntities << '\n'; + dumpLocalRemap("Preprocessed entity ID local -> global map", + PreprocessedEntityRemap); + + llvm::errs() << " Base type index: " << BaseTypeIndex << '\n' + << " Number of types: " << LocalNumTypes << '\n'; + dumpLocalRemap("Type index local -> global map", TypeRemap); + + llvm::errs() << " Base decl ID: " << BaseDeclID << '\n' + << " Number of decls: " << LocalNumDecls << '\n'; + dumpLocalRemap("Decl ID local -> global map", DeclRemap); +} diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp new file mode 100644 index 0000000..c4b1f71 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp @@ -0,0 +1,253 @@ +//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleManager class, which manages a set of loaded +// modules for the ASTReader. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/ModuleManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +#ifndef NDEBUG +#include "llvm/Support/GraphWriter.h" +#endif + +using namespace clang; +using namespace serialization; + +Module *ModuleManager::lookup(StringRef Name) { + const FileEntry *Entry = FileMgr.getFile(Name); + return Modules[Entry]; +} + +llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { + const FileEntry *Entry = FileMgr.getFile(Name); + return InMemoryBuffers[Entry]; +} + +std::pair<Module *, bool> +ModuleManager::addModule(StringRef FileName, ModuleKind Type, + Module *ImportedBy, std::string &ErrorStr) { + const FileEntry *Entry = FileMgr.getFile(FileName); + if (!Entry && FileName != "-") { + ErrorStr = "file not found"; + return std::make_pair(static_cast<Module*>(0), false); + } + + // Check whether we already loaded this module, before + Module *&ModuleEntry = Modules[Entry]; + bool NewModule = false; + if (!ModuleEntry) { + // Allocate a new module. + Module *New = new Module(Type); + New->FileName = FileName.str(); + Chain.push_back(New); + NewModule = true; + ModuleEntry = New; + + // Load the contents of the module + if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { + // The buffer was already provided for us. + assert(Buffer && "Passed null buffer"); + New->Buffer.reset(Buffer); + } else { + // Open the AST file. + llvm::error_code ec; + if (FileName == "-") { + ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); + if (ec) + ErrorStr = ec.message(); + } else + New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); + + if (!New->Buffer) + return std::make_pair(static_cast<Module*>(0), false); + } + + // Initialize the stream + New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), + (const unsigned char *)New->Buffer->getBufferEnd()); } + + if (ImportedBy) { + ModuleEntry->ImportedBy.insert(ImportedBy); + ImportedBy->Imports.insert(ModuleEntry); + } else { + ModuleEntry->DirectlyImported = true; + } + + return std::make_pair(ModuleEntry, NewModule); +} + +void ModuleManager::addInMemoryBuffer(StringRef FileName, + llvm::MemoryBuffer *Buffer) { + + const FileEntry *Entry = FileMgr.getVirtualFile(FileName, + Buffer->getBufferSize(), 0); + InMemoryBuffers[Entry] = Buffer; +} + +ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } + +ModuleManager::~ModuleManager() { + for (unsigned i = 0, e = Chain.size(); i != e; ++i) + delete Chain[e - i - 1]; +} + +void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData), + void *UserData) { + unsigned N = size(); + + // Record the number of incoming edges for each module. When we + // encounter a module with no incoming edges, push it into the queue + // to seed the queue. + SmallVector<Module *, 4> Queue; + Queue.reserve(N); + llvm::DenseMap<Module *, unsigned> UnusedIncomingEdges; + for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { + if (unsigned Size = (*M)->ImportedBy.size()) + UnusedIncomingEdges[*M] = Size; + else + Queue.push_back(*M); + } + + llvm::SmallPtrSet<Module *, 4> Skipped; + unsigned QueueStart = 0; + while (QueueStart < Queue.size()) { + Module *CurrentModule = Queue[QueueStart++]; + + // Check whether this module should be skipped. + if (Skipped.count(CurrentModule)) + continue; + + if (Visitor(*CurrentModule, UserData)) { + // The visitor has requested that cut off visitation of any + // module that the current module depends on. To indicate this + // behavior, we mark all of the reachable modules as having N + // incoming edges (which is impossible otherwise). + SmallVector<Module *, 4> Stack; + Stack.push_back(CurrentModule); + Skipped.insert(CurrentModule); + while (!Stack.empty()) { + Module *NextModule = Stack.back(); + Stack.pop_back(); + + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector<Module *>::iterator + M = NextModule->Imports.begin(), + MEnd = NextModule->Imports.end(); + M != MEnd; ++M) { + if (Skipped.insert(*M)) + Stack.push_back(*M); + } + } + continue; + } + + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector<Module *>::iterator M = CurrentModule->Imports.begin(), + MEnd = CurrentModule->Imports.end(); + M != MEnd; ++M) { + + // Remove our current module as an impediment to visiting the + // module we depend on. If we were the last unvisited module + // that depends on this particular module, push it into the + // queue to be visited. + unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; + if (NumUnusedEdges && (--NumUnusedEdges == 0)) + Queue.push_back(*M); + } + } +} + +/// \brief Perform a depth-first visit of the current module. +static bool visitDepthFirst(Module &M, + bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData, + llvm::SmallPtrSet<Module *, 4> &Visited) { + // Preorder visitation + if (Visitor(M, /*Preorder=*/true, UserData)) + return true; + + // Visit children + for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(), + IMEnd = M.Imports.end(); + IM != IMEnd; ++IM) { + if (!Visited.insert(*IM)) + continue; + + if (visitDepthFirst(**IM, Visitor, UserData, Visited)) + return true; + } + + // Postorder visitation + return Visitor(M, /*Preorder=*/false, UserData); +} + +void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData) { + llvm::SmallPtrSet<Module *, 4> Visited; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (!Visited.insert(Chain[I])) + continue; + + if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) + return; + } +} + +#ifndef NDEBUG +namespace llvm { + template<> + struct GraphTraits<ModuleManager> { + typedef Module NodeType; + typedef llvm::SetVector<Module *>::const_iterator ChildIteratorType; + typedef ModuleManager::ModuleConstIterator nodes_iterator; + + static ChildIteratorType child_begin(NodeType *Node) { + return Node->Imports.begin(); + } + + static ChildIteratorType child_end(NodeType *Node) { + return Node->Imports.end(); + } + + static nodes_iterator nodes_begin(const ModuleManager &Manager) { + return Manager.begin(); + } + + static nodes_iterator nodes_end(const ModuleManager &Manager) { + return Manager.end(); + } + }; + + template<> + struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { + explicit DOTGraphTraits(bool IsSimple = false) + : DefaultDOTGraphTraits(IsSimple) { } + + static bool renderGraphFromBottomUp() { + return true; + } + + std::string getNodeLabel(Module *M, const ModuleManager&) { + return llvm::sys::path::stem(M->FileName); + } + }; +} + +void ModuleManager::viewGraph() { + llvm::ViewGraph(*this, "Modules"); +} +#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/CMakeLists.txt b/contrib/llvm/tools/clang/lib/StaticAnalyzer/CMakeLists.txt deleted file mode 100644 index 3d15092..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(Core) -add_subdirectory(Checkers) -add_subdirectory(Frontend) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp index 8fc6d2a..dc524ba 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp @@ -37,7 +37,7 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, QualType expectedResultTy = CE->getType(); // Fetch the signature of the called function. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal V = state->getSVal(CE); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 983427a..cd977bf 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -80,7 +80,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { const NamedDecl *ND = cast<NamedDecl>(D); - output << ND; + output << *ND; } else if (isa<BlockDecl>(D)) { output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); @@ -94,7 +94,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, << (Eng.hasEmptyWorkList() ? "yes" : "no"); B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(), - D->getLocation()); + PathDiagnosticLocation(D, SM)); // Emit warning for each block we bailed out on typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; @@ -106,7 +106,8 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, const CFGElement &CE = Exit->front(); if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer " - "stopped analyzing at this point", CS->getStmt()->getLocStart()); + "stopped analyzing at this point", + PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC)); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index eb9665a..6935c5f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -27,11 +27,12 @@ class ArrayBoundChecker : public Checker<check::Location> { mutable llvm::OwningPtr<BuiltinBug> BT; public: - void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; + void checkLocation(SVal l, bool isLoad, const Stmt* S, + CheckerContext &C) const; }; } -void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, +void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS, CheckerContext &C) const { // Check for out of bound array element access. const MemRegion *R = l.getAsRegion(); @@ -50,15 +51,15 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, if (Idx.isZeroConstant()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // Get the size of the array. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); - const GRState *StInBound = state->assumeInBound(Idx, NumElements, true); - const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false); + const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true); + const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) @@ -73,10 +74,10 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, // reference is outside the range. // Generate a report for this bug. - RangedBugReport *report = - new RangedBugReport(*BT, BT->getDescription(), N); + BugReport *report = + new BugReport(*BT, BT->getDescription(), N); - report->addRange(C.getStmt()->getSourceRange()); + report->addRange(LoadS->getSourceRange()); C.EmitReport(report); return; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 65a6e63..6175028 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -30,11 +30,12 @@ class ArrayBoundCheckerV2 : enum OOB_Kind { OOB_Precedes, OOB_Excedes }; - void reportOOB(CheckerContext &C, const GRState *errorState, + void reportOOB(CheckerContext &C, const ProgramState *errorState, OOB_Kind kind) const; public: - void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; + void checkLocation(SVal l, bool isLoad, const Stmt*S, + CheckerContext &C) const; }; // FIXME: Eventually replace RegionRawOffset with this class. @@ -53,12 +54,12 @@ public: NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); } const SubRegion *getRegion() const { return baseRegion; } - static RegionRawOffsetV2 computeOffset(const GRState *state, + static RegionRawOffsetV2 computeOffset(const ProgramState *state, SValBuilder &svalBuilder, SVal location); void dump() const; - void dumpToStream(llvm::raw_ostream& os) const; + void dumpToStream(raw_ostream &os) const; }; } @@ -79,9 +80,10 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder, } void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, + const Stmt* LoadS, CheckerContext &checkerContext) const { - // NOTE: Instead of using GRState::assumeInBound(), we are prototyping + // NOTE: Instead of using ProgramState::assumeInBound(), we are prototyping // some new logic here that reasons directly about memory region extents. // Once that logic is more mature, we can bring it back to assumeInBound() // for all clients to use. @@ -90,8 +92,8 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, // memory access is within the extent of the base region. Since we // have some flexibility in defining the base region, we can achieve // various levels of conservatism in our buffer overflow checking. - const GRState *state = checkerContext.getState(); - const GRState *originalState = state; + const ProgramState *state = checkerContext.getState(); + const ProgramState *originalState = state; SValBuilder &svalBuilder = checkerContext.getSValBuilder(); const RegionRawOffsetV2 &rawOffset = @@ -116,7 +118,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, if (!lowerBoundToCheck) return; - const GRState *state_precedesLowerBound, *state_withinLowerBound; + const ProgramState *state_precedesLowerBound, *state_withinLowerBound; llvm::tie(state_precedesLowerBound, state_withinLowerBound) = state->assume(*lowerBoundToCheck); @@ -148,7 +150,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, if (!upperboundToCheck) break; - const GRState *state_exceedsUpperBound, *state_withinUpperBound; + const ProgramState *state_exceedsUpperBound, *state_withinUpperBound; llvm::tie(state_exceedsUpperBound, state_withinUpperBound) = state->assume(*upperboundToCheck); @@ -168,7 +170,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, } void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, - const GRState *errorState, + const ProgramState *errorState, OOB_Kind kind) const { ExplodedNode *errorNode = checkerContext.generateSink(errorState); @@ -187,14 +189,14 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, << (kind == OOB_Precedes ? "(accessed memory precedes memory block)" : "(access exceeds upper limit of memory block)"); - checkerContext.EmitReport(new RangedBugReport(*BT, os.str(), errorNode)); + checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode)); } void RegionRawOffsetV2::dump() const { dumpToStream(llvm::errs()); } -void RegionRawOffsetV2::dumpToStream(llvm::raw_ostream& os) const { +void RegionRawOffsetV2::dumpToStream(raw_ostream &os) const { os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}'; } @@ -219,7 +221,7 @@ static inline SVal getValue(SVal val, SValBuilder &svalBuilder) { // Scale a base value by a scaling factor, and return the scaled // value as an SVal. Used by 'computeOffset'. -static inline SVal scaleValue(const GRState *state, +static inline SVal scaleValue(const ProgramState *state, NonLoc baseVal, CharUnits scaling, SValBuilder &sb) { return sb.evalBinOpNN(state, BO_Mul, baseVal, @@ -229,7 +231,7 @@ static inline SVal scaleValue(const GRState *state, // Add an SVal to another, treating unknown and undefined values as // summing to UnknownVal. Used by 'computeOffset'. -static SVal addValue(const GRState *state, SVal x, SVal y, +static SVal addValue(const ProgramState *state, SVal x, SVal y, SValBuilder &svalBuilder) { // We treat UnknownVals and UndefinedVals the same here because we // only care about computing offsets. @@ -243,7 +245,7 @@ static SVal addValue(const GRState *state, SVal x, SVal y, /// Compute a raw byte offset from a base region. Used for array bounds /// checking. -RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state, +RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const ProgramState *state, SValBuilder &svalBuilder, SVal location) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index d88a111..8296eb9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -33,12 +33,12 @@ public: void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); - const FunctionDecl* FD = X.getAsFunctionDecl(); + const FunctionDecl *FD = X.getAsFunctionDecl(); if (!FD) return; @@ -85,7 +85,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, } ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotNull, *stateNull; + const ProgramState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (stateNull && !stateNotNull) { @@ -100,16 +100,15 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, BT.reset(new BugType("Argument with 'nonnull' attribute passed null", "API")); - EnhancedBugReport *R = - new EnhancedBugReport(*BT, - "Null pointer passed as an argument to a " - "'nonnull' parameter", errorNode); + BugReport *R = + new BugReport(*BT, "Null pointer passed as an argument to a " + "'nonnull' parameter", errorNode); // Highlight the range of the argument that was null. const Expr *arg = *I; R->addRange(arg->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg); - + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(errorNode, + arg)); // Emit the bug report. C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 9fc8163..08cff0f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -20,7 +20,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/AST/DeclObjC.h" @@ -49,7 +50,7 @@ static const char* GetReceiverNameType(const ObjCMessage &msg) { } static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID, - llvm::StringRef ClassName) { + StringRef ClassName) { if (ID->getIdentifier()->getName() == ClassName) return true; @@ -92,7 +93,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C, os << "Argument to '" << GetReceiverNameType(msg) << "' method '" << msg.getSelector().getAsString() << "' cannot be nil"; - RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); + BugReport *R = new BugReport(*BT, os.str(), N); R->addRange(msg.getArgSourceRange(Arg)); C.EmitReport(R); } @@ -114,7 +115,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg, // lexical comparisons. std::string NameStr = S.getAsString(); - llvm::StringRef Name(NameStr); + StringRef Name(NameStr); assert(!Name.empty()); // FIXME: Checking for initWithFormat: will not work in most cases @@ -148,7 +149,7 @@ public: void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; private: - void EmitError(const TypedRegion* R, const Expr* Ex, + void EmitError(const TypedRegion* R, const Expr *Ex, uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); }; } // end anonymous namespace @@ -194,7 +195,7 @@ namespace { }; } -static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { +static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) { static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; if (i < kCFNumberCharType) @@ -248,10 +249,10 @@ static const char* GetCFNumberTypeStr(uint64_t i) { void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { - const Expr* Callee = CE->getCallee(); - const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const ProgramState *state = C.getState(); SVal CallV = state->getSVal(Callee); - const FunctionDecl* FD = CallV.getAsFunctionDecl(); + const FunctionDecl *FD = CallV.getAsFunctionDecl(); if (!FD) return; @@ -290,7 +291,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, if (!LV) return; - const TypedRegion* R = dyn_cast<TypedRegion>(LV->stripCasts()); + const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts()); if (!R) return; @@ -335,7 +336,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, if (!BT) BT.reset(new APIMisuse("Bad use of CFNumberCreate")); - RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); C.EmitReport(report); } @@ -351,21 +352,21 @@ class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { mutable IdentifierInfo *Retain, *Release; public: CFRetainReleaseChecker(): Retain(0), Release(0) {} - void checkPreStmt(const CallExpr* CE, CheckerContext& C) const; + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; }; } // end anonymous namespace -void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE, - CheckerContext& C) const { +void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const { // If the CallExpr doesn't have exactly 1 argument just give up checking. if (CE->getNumArgs() != 1) return; // Get the function declaration of the callee. - const GRState* state = C.getState(); + const ProgramState *state = C.getState(); SVal X = state->getSVal(CE->getCallee()); - const FunctionDecl* FD = X.getAsFunctionDecl(); + const FunctionDecl *FD = X.getAsFunctionDecl(); if (!FD) return; @@ -400,7 +401,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE, DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal); // Are they equal? - const GRState *stateTrue, *stateFalse; + const ProgramState *stateTrue, *stateFalse; llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); if (stateTrue && !stateFalse) { @@ -412,9 +413,9 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE, ? "Null pointer argument in call to CFRetain" : "Null pointer argument in call to CFRelease"; - EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N); + BugReport *report = new BugReport(*BT, description, N); report->addRange(Arg->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg)); C.EmitReport(report); return; } @@ -471,7 +472,7 @@ void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg, "of class '" << Class->getName() << "' and not the class directly"; - RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(msg.getSourceRange()); C.EmitReport(report); } @@ -586,7 +587,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg, // Verify that all arguments have Objective-C types. llvm::Optional<ExplodedNode*> errorNode; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) { QualType ArgTy = msg.getArgType(I); @@ -629,7 +630,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg, << "' should be an Objective-C pointer type, not '" << ArgTy.getAsString() << "'"; - RangedBugReport *R = new RangedBugReport(*BT, os.str(), + BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue()); R->addRange(msg.getArgSourceRange(I)); C.EmitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 12ac652..a57d031 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -31,7 +31,7 @@ public: bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, CheckerContext &C) const{ - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); const FunctionDecl *FD = L.getAsFunctionDecl(); @@ -57,7 +57,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, // FIXME: Refactor into StoreManager itself? MemRegionManager& RM = C.getStoreManager().getRegionManager(); const AllocaRegion* R = - RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(), + RM.getAllocaRegion(CE, C.getCurrentBlockCount(), C.getPredecessor()->getLocationContext()); // Set the extent of the region in bytes. This enables us to use the diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt deleted file mode 100644 index e172a52..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ /dev/null @@ -1,70 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS Checkers.td) -tablegen(Checkers.inc - -gen-clang-sa-checkers - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../include) -add_custom_target(ClangSACheckers - DEPENDS Checkers.inc) - -set(LLVM_USED_LIBS clangBasic clangAST) - -add_clang_library(clangStaticAnalyzerCheckers - AdjustedReturnValueChecker.cpp - AnalyzerStatsChecker.cpp - ArrayBoundChecker.cpp - ArrayBoundCheckerV2.cpp - AttrNonNullChecker.cpp - BasicObjCFoundationChecks.cpp - BuiltinFunctionChecker.cpp - CStringChecker.cpp - CallAndMessageChecker.cpp - CastSizeChecker.cpp - CastToStructChecker.cpp - CheckObjCDealloc.cpp - CheckObjCInstMethSignature.cpp - CheckSecuritySyntaxOnly.cpp - CheckSizeofPointer.cpp - ChrootChecker.cpp - ClangSACheckerProvider.cpp - DeadStoresChecker.cpp - DebugCheckers.cpp - DereferenceChecker.cpp - DivZeroChecker.cpp - ExprEngine.cpp - ExperimentalChecks.cpp - FixedAddressChecker.cpp - IdempotentOperationChecker.cpp - LLVMConventionsChecker.cpp - MacOSXAPIChecker.cpp - MallocChecker.cpp - NSAutoreleasePoolChecker.cpp - NSErrorChecker.cpp - NoReturnFunctionChecker.cpp - OSAtomicChecker.cpp - ObjCAtSyncChecker.cpp - ObjCSelfInitChecker.cpp - ObjCUnusedIVarsChecker.cpp - PointerArithChecker.cpp - PointerSubChecker.cpp - PthreadLockChecker.cpp - ReturnPointerRangeChecker.cpp - ReturnUndefChecker.cpp - StackAddrLeakChecker.cpp - StreamChecker.cpp - UndefBranchChecker.cpp - UndefCapturedBlockVarChecker.cpp - UndefResultChecker.cpp - UndefinedArraySubscriptChecker.cpp - UndefinedAssignmentChecker.cpp - UnixAPIChecker.cpp - UnreachableCodeChecker.cpp - VLASizeChecker.cpp - ) - -add_dependencies(clangStaticAnalyzerCheckers - clangStaticAnalyzerCore - ClangAttrClasses - ClangAttrList - ClangDeclNodes - ClangStmtNodes - ClangSACheckers - ) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index c5dac5d..1625219 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1,4 +1,4 @@ -//= CStringChecker.h - Checks calls to C string functions ----------*- C++ -*-// +//= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// // // The LLVM Compiler Infrastructure // @@ -17,7 +17,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -40,14 +40,15 @@ public: bool evalCall(const CallExpr *CE, CheckerContext &C) const; void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; - void checkLiveSymbols(const GRState *state, SymbolReaper &SR) const; + void checkLiveSymbols(const ProgramState *state, SymbolReaper &SR) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; - bool wantsRegionChangeUpdate(const GRState *state) const; + bool wantsRegionChangeUpdate(const ProgramState *state) const; - const GRState *checkRegionChanges(const GRState *state, - const StoreManager::InvalidatedSymbols *, - const MemRegion * const *Begin, - const MemRegion * const *End) const; + const ProgramState * + checkRegionChanges(const ProgramState *state, + const StoreManager::InvalidatedSymbols *, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions) const; typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *) const; @@ -57,8 +58,10 @@ public: void evalMemmove(CheckerContext &C, const CallExpr *CE) const; void evalBcopy(CheckerContext &C, const CallExpr *CE) const; void evalCopyCommon(CheckerContext &C, const CallExpr *CE, - const GRState *state, - const Expr *Size, const Expr *Source, const Expr *Dest, + const ProgramState *state, + const Expr *Size, + const Expr *Source, + const Expr *Dest, bool Restricted = false, bool IsMempcpy = false) const; @@ -66,14 +69,18 @@ public: void evalstrLength(CheckerContext &C, const CallExpr *CE) const; void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; - void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, + void evalstrLengthCommon(CheckerContext &C, + const CallExpr *CE, bool IsStrnlen = false) const; void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; - void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, - bool isBounded, bool isAppending) const; + void evalStrcpyCommon(CheckerContext &C, + const CallExpr *CE, + bool returnEnd, + bool isBounded, + bool isAppending) const; void evalStrcat(CheckerContext &C, const CallExpr *CE) const; void evalStrncat(CheckerContext &C, const CallExpr *CE) const; @@ -82,64 +89,85 @@ public: void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; - void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, - bool isBounded = false, bool ignoreCase = false) const; + void evalStrcmpCommon(CheckerContext &C, + const CallExpr *CE, + bool isBounded = false, + bool ignoreCase = false) const; // Utility methods - std::pair<const GRState*, const GRState*> + std::pair<const ProgramState*, const ProgramState*> static assumeZero(CheckerContext &C, - const GRState *state, SVal V, QualType Ty); + const ProgramState *state, SVal V, QualType Ty); - static const GRState *setCStringLength(const GRState *state, - const MemRegion *MR, SVal strLength); + static const ProgramState *setCStringLength(const ProgramState *state, + const MemRegion *MR, + SVal strLength); static SVal getCStringLengthForRegion(CheckerContext &C, - const GRState *&state, - const Expr *Ex, const MemRegion *MR, + const ProgramState *&state, + const Expr *Ex, + const MemRegion *MR, bool hypothetical); - SVal getCStringLength(CheckerContext &C, const GRState *&state, - const Expr *Ex, SVal Buf, + SVal getCStringLength(CheckerContext &C, + const ProgramState *&state, + const Expr *Ex, + SVal Buf, bool hypothetical = false) const; const StringLiteral *getCStringLiteral(CheckerContext &C, - const GRState *&state, + const ProgramState *&state, const Expr *expr, SVal val) const; - static const GRState *InvalidateBuffer(CheckerContext &C, - const GRState *state, - const Expr *Ex, SVal V); + static const ProgramState *InvalidateBuffer(CheckerContext &C, + const ProgramState *state, + const Expr *Ex, SVal V); - static bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, + static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR); // Re-usable checks - const GRState *checkNonNull(CheckerContext &C, const GRState *state, - const Expr *S, SVal l) const; - const GRState *CheckLocation(CheckerContext &C, const GRState *state, - const Expr *S, SVal l, - const char *message = NULL) const; - const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state, - const Expr *Size, - const Expr *FirstBuf, - const Expr *SecondBuf, - const char *firstMessage = NULL, - const char *secondMessage = NULL, - bool WarnAboutSize = false) const; - const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state, - const Expr *Size, const Expr *Buf, - const char *message = NULL, - bool WarnAboutSize = false) const { + const ProgramState *checkNonNull(CheckerContext &C, + const ProgramState *state, + const Expr *S, + SVal l) const; + const ProgramState *CheckLocation(CheckerContext &C, + const ProgramState *state, + const Expr *S, + SVal l, + const char *message = NULL) const; + const ProgramState *CheckBufferAccess(CheckerContext &C, + const ProgramState *state, + const Expr *Size, + const Expr *FirstBuf, + const Expr *SecondBuf, + const char *firstMessage = NULL, + const char *secondMessage = NULL, + bool WarnAboutSize = false) const; + + const ProgramState *CheckBufferAccess(CheckerContext &C, + const ProgramState *state, + const Expr *Size, + const Expr *Buf, + const char *message = NULL, + bool WarnAboutSize = false) const { // This is a convenience override. return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL, WarnAboutSize); } - const GRState *CheckOverlap(CheckerContext &C, const GRState *state, - const Expr *Size, const Expr *First, - const Expr *Second) const; - void emitOverlapBug(CheckerContext &C, const GRState *state, - const Stmt *First, const Stmt *Second) const; - const GRState *checkAdditionOverflow(CheckerContext &C, const GRState *state, - NonLoc left, NonLoc right) const; + const ProgramState *CheckOverlap(CheckerContext &C, + const ProgramState *state, + const Expr *Size, + const Expr *First, + const Expr *Second) const; + void emitOverlapBug(CheckerContext &C, + const ProgramState *state, + const Stmt *First, + const Stmt *Second) const; + + const ProgramState *checkAdditionOverflow(CheckerContext &C, + const ProgramState *state, + NonLoc left, + NonLoc right) const; }; class CStringLength { @@ -151,8 +179,8 @@ public: namespace clang { namespace ento { template <> - struct GRStateTrait<CStringLength> - : public GRStatePartialTrait<CStringLength::EntryMap> { + struct ProgramStateTrait<CStringLength> + : public ProgramStatePartialTrait<CStringLength::EntryMap> { static void *GDMIndex() { return CStringChecker::getTag(); } }; } @@ -162,26 +190,26 @@ namespace ento { // Individual checks and utility methods. //===----------------------------------------------------------------------===// -std::pair<const GRState*, const GRState*> -CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V, +std::pair<const ProgramState*, const ProgramState*> +CStringChecker::assumeZero(CheckerContext &C, const ProgramState *state, SVal V, QualType Ty) { DefinedSVal *val = dyn_cast<DefinedSVal>(&V); if (!val) - return std::pair<const GRState*, const GRState *>(state, state); + return std::pair<const ProgramState*, const ProgramState *>(state, state); SValBuilder &svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); return state->assume(svalBuilder.evalEQ(state, *val, zero)); } -const GRState *CStringChecker::checkNonNull(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::checkNonNull(CheckerContext &C, + const ProgramState *state, const Expr *S, SVal l) const { // If a previous check has failed, propagate the failure. if (!state) return NULL; - const GRState *stateNull, *stateNonNull; + const ProgramState *stateNull, *stateNonNull; llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); if (stateNull && !stateNonNull) { @@ -200,10 +228,10 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C, // Generate a report for this bug. BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get()); - EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(S->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, S); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S)); C.EmitReport(report); return NULL; } @@ -214,8 +242,8 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C, } // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? -const GRState *CStringChecker::CheckLocation(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::CheckLocation(CheckerContext &C, + const ProgramState *state, const Expr *S, SVal l, const char *warningMsg) const { // If a previous check has failed, propagate the failure. @@ -244,8 +272,8 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, // Get the index of the accessed element. DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); - const GRState *StInBound = state->assumeInBound(Idx, Size, true); - const GRState *StOutBound = state->assumeInBound(Idx, Size, false); + const ProgramState *StInBound = state->assumeInBound(Idx, Size, true); + const ProgramState *StOutBound = state->assumeInBound(Idx, Size, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) @@ -258,9 +286,9 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get()); // Generate a report for this bug. - RangedBugReport *report; + BugReport *report; if (warningMsg) { - report = new RangedBugReport(*BT, warningMsg, N); + report = new BugReport(*BT, warningMsg, N); } else { assert(CurrentFunctionDescription); assert(CurrentFunctionDescription[0] != '\0'); @@ -270,7 +298,7 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, os << (char)toupper(CurrentFunctionDescription[0]) << &CurrentFunctionDescription[1] << " accesses out-of-bound array element"; - report = new RangedBugReport(*BT, os.str(), N); + report = new BugReport(*BT, os.str(), N); } // FIXME: It would be nice to eventually make this diagnostic more clear, @@ -287,8 +315,8 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, return StInBound; } -const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C, + const ProgramState *state, const Expr *Size, const Expr *FirstBuf, const Expr *SecondBuf, @@ -359,8 +387,8 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, return state; } -const GRState *CStringChecker::CheckOverlap(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C, + const ProgramState *state, const Expr *Size, const Expr *First, const Expr *Second) const { @@ -372,7 +400,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C, if (!state) return NULL; - const GRState *stateTrue, *stateFalse; + const ProgramState *stateTrue, *stateFalse; // Get the buffer values and make sure they're known locations. SVal firstVal = state->getSVal(First); @@ -470,7 +498,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C, return stateFalse; } -void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state, +void CStringChecker::emitOverlapBug(CheckerContext &C, const ProgramState *state, const Stmt *First, const Stmt *Second) const { ExplodedNode *N = C.generateSink(state); if (!N) @@ -480,8 +508,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state, BT_Overlap.reset(new BugType("Unix API", "Improper arguments")); // Generate a report for this bug. - RangedBugReport *report = - new RangedBugReport(*BT_Overlap, + BugReport *report = + new BugReport(*BT_Overlap, "Arguments must not be overlapping buffers", N); report->addRange(First->getSourceRange()); report->addRange(Second->getSourceRange()); @@ -489,8 +517,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state, C.EmitReport(report); } -const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C, + const ProgramState *state, NonLoc left, NonLoc right) const { // If a previous check has failed, propagate the failure. @@ -521,7 +549,7 @@ const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C, SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, *maxMinusRightNL, cmpTy); - const GRState *stateOverflow, *stateOkay; + const ProgramState *stateOverflow, *stateOkay; llvm::tie(stateOverflow, stateOkay) = state->assume(cast<DefinedOrUnknownSVal>(willOverflow)); @@ -557,7 +585,7 @@ const GRState *CStringChecker::checkAdditionOverflow(CheckerContext &C, return state; } -const GRState *CStringChecker::setCStringLength(const GRState *state, +const ProgramState *CStringChecker::setCStringLength(const ProgramState *state, const MemRegion *MR, SVal strLength) { assert(!strLength.isUndef() && "Attempt to set an undefined string length"); @@ -598,7 +626,7 @@ const GRState *CStringChecker::setCStringLength(const GRState *state, } SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, - const GRState *&state, + const ProgramState *&state, const Expr *Ex, const MemRegion *MR, bool hypothetical) { @@ -610,7 +638,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, } // Otherwise, get a new symbol and update the state. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); QualType sizeTy = svalBuilder.getContext().getSizeType(); SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), @@ -622,7 +650,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, return strLength; } -SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state, +SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&state, const Expr *Ex, SVal Buf, bool hypothetical) const { const MemRegion *MR = Buf.getAsRegion(); @@ -644,7 +672,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state, << "', which is not a null-terminated string"; // Generate a report for this bug. - EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString, + BugReport *report = new BugReport(*BT_NotCString, os.str(), N); report->addRange(Ex->getSourceRange()); @@ -705,7 +733,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state, os << "not a null-terminated string"; // Generate a report for this bug. - EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString, + BugReport *report = new BugReport(*BT_NotCString, os.str(), N); report->addRange(Ex->getSourceRange()); @@ -717,7 +745,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state, } const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, - const GRState *&state, const Expr *expr, SVal val) const { + const ProgramState *&state, const Expr *expr, SVal val) const { // Get the memory region pointed to by the val. const MemRegion *bufRegion = val.getAsRegion(); @@ -736,8 +764,8 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, return strRegion->getStringLiteral(); } -const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C, - const GRState *state, +const ProgramState *CStringChecker::InvalidateBuffer(CheckerContext &C, + const ProgramState *state, const Expr *E, SVal V) { Loc *L = dyn_cast<Loc>(&V); if (!L) @@ -757,8 +785,8 @@ const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C, } // Invalidate this region. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); - return state->invalidateRegion(R, E, Count, NULL); + unsigned Count = C.getCurrentBlockCount(); + return state->invalidateRegions(R, E, Count); } // If we have a non-region value by chance, just remove the binding. @@ -767,17 +795,15 @@ const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C, return state->unbindLoc(*L); } -bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, +bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR) { - const TypedRegion *TR = dyn_cast<TypedRegion>(MR); - if (!TR) - return false; + const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR); - switch (TR->getKind()) { + switch (MR->getKind()) { case MemRegion::FunctionTextRegionKind: { - const FunctionDecl *FD = cast<FunctionTextRegion>(TR)->getDecl(); + const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); if (FD) - os << "the address of the function '" << FD << "'"; + os << "the address of the function '" << *FD << '\''; else os << "the address of a function"; return true; @@ -790,16 +816,16 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, return true; case MemRegion::CXXThisRegionKind: case MemRegion::CXXTempObjectRegionKind: - os << "a C++ temp object of type " << TR->getValueType().getAsString(); + os << "a C++ temp object of type " << TVR->getValueType().getAsString(); return true; case MemRegion::VarRegionKind: - os << "a variable of type" << TR->getValueType().getAsString(); + os << "a variable of type" << TVR->getValueType().getAsString(); return true; case MemRegion::FieldRegionKind: - os << "a field of type " << TR->getValueType().getAsString(); + os << "a field of type " << TVR->getValueType().getAsString(); return true; case MemRegion::ObjCIvarRegionKind: - os << "an instance variable of type " << TR->getValueType().getAsString(); + os << "an instance variable of type " << TVR->getValueType().getAsString(); return true; default: return false; @@ -812,7 +838,7 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, - const GRState *state, + const ProgramState *state, const Expr *Size, const Expr *Dest, const Expr *Source, bool Restricted, bool IsMempcpy) const { @@ -822,7 +848,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, SVal sizeVal = state->getSVal(Size); QualType sizeTy = Size->getType(); - const GRState *stateZeroSize, *stateNonZeroSize; + const ProgramState *stateZeroSize, *stateNonZeroSize; llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy); @@ -887,7 +913,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, } else { // If we don't know how much we copied, we can at least // conjure a return value for later. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); SVal result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count); state = state->BindExpr(CE, result); @@ -914,7 +940,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { // void *memcpy(void *restrict dst, const void *restrict src, size_t n); // The return value is the address of the destination buffer. const Expr *Dest = CE->getArg(0); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); } @@ -923,7 +949,7 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); // The return value is a pointer to the byte following the last written byte. const Expr *Dest = CE->getArg(0); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); } @@ -932,7 +958,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { // void *memmove(void *dst, const void *src, size_t n); // The return value is the address of the destination buffer. const Expr *Dest = CE->getArg(0); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); } @@ -951,14 +977,14 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { const Expr *Right = CE->getArg(1); const Expr *Size = CE->getArg(2); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); // See if the size argument is zero. SVal sizeVal = state->getSVal(Size); QualType sizeTy = Size->getType(); - const GRState *stateZeroSize, *stateNonZeroSize; + const ProgramState *stateZeroSize, *stateNonZeroSize; llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy); @@ -981,7 +1007,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { // See if they are the same. DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); - const GRState *StSameBuf, *StNotSameBuf; + const ProgramState *StSameBuf, *StNotSameBuf; llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); // If the two arguments might be the same buffer, we know the result is 0, @@ -1002,7 +1028,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { state = CheckBufferAccess(C, state, Size, Left, Right); if (state) { // The return value is the comparison result, which we don't know. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count); state = state->BindExpr(CE, CmpV); C.addTransition(state); @@ -1026,13 +1052,13 @@ void CStringChecker::evalstrnLength(CheckerContext &C, void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, bool IsStrnlen) const { CurrentFunctionDescription = "string length function"; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (IsStrnlen) { const Expr *maxlenExpr = CE->getArg(1); SVal maxlenVal = state->getSVal(maxlenExpr); - const GRState *stateZeroSize, *stateNonZeroSize; + const ProgramState *stateZeroSize, *stateNonZeroSize; llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, maxlenVal, maxlenExpr->getType()); @@ -1084,7 +1110,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal); if (strLengthNL && maxlenValNL) { - const GRState *stateStringTooLong, *stateStringNotTooLong; + const ProgramState *stateStringTooLong, *stateStringNotTooLong; // Check if the strLength is greater than the maxlen. llvm::tie(stateStringTooLong, stateStringNotTooLong) = @@ -1108,7 +1134,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // no guarantee the full string length will actually be returned. // All we know is the return value is the min of the string length // and the limit. This is better than nothing. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count); NonLoc *resultNL = cast<NonLoc>(&result); @@ -1136,7 +1162,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (result.isUnknown()) { - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count); } } @@ -1191,7 +1217,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, bool isBounded, bool isAppending) const { CurrentFunctionDescription = "string copy function"; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // Check that the destination is non-null. const Expr *Dst = CE->getArg(0); @@ -1241,7 +1267,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // If we know both values, we might be able to figure out how much // we're copying. if (strLengthNL && lenValNL) { - const GRState *stateSourceTooLong, *stateSourceNotTooLong; + const ProgramState *stateSourceTooLong, *stateSourceNotTooLong; // Check if the max number to copy is less than the length of the src. // If the bound is equal to the source length, strncpy won't null- @@ -1480,7 +1506,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. if (returnEnd && Result.isUnknown()) { - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); Result = svalBuilder.getConjuredSymbolVal(NULL, CE, Count); } @@ -1514,7 +1540,7 @@ void CStringChecker::evalStrncasecmp(CheckerContext &C, void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool isBounded, bool ignoreCase) const { CurrentFunctionDescription = "string comparison function"; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // Check that the first string is non-null const Expr *s1 = CE->getArg(0); @@ -1549,7 +1575,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, // See if they are the same. SValBuilder &svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); - const GRState *StSameBuf, *StNotSameBuf; + const ProgramState *StSameBuf, *StNotSameBuf; llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); // If the two arguments might be the same buffer, we know the result is 0, @@ -1575,8 +1601,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool canComputeResult = false; if (s1StrLiteral && s2StrLiteral) { - llvm::StringRef s1StrRef = s1StrLiteral->getString(); - llvm::StringRef s2StrRef = s2StrLiteral->getString(); + StringRef s1StrRef = s1StrLiteral->getString(); + StringRef s2StrRef = s2StrLiteral->getString(); if (isBounded) { // Get the max number of characters to compare. @@ -1598,11 +1624,11 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, if (canComputeResult) { // Real strcmp stops at null characters. size_t s1Term = s1StrRef.find('\0'); - if (s1Term != llvm::StringRef::npos) + if (s1Term != StringRef::npos) s1StrRef = s1StrRef.substr(0, s1Term); size_t s2Term = s2StrRef.find('\0'); - if (s2Term != llvm::StringRef::npos) + if (s2Term != StringRef::npos) s2StrRef = s2StrRef.substr(0, s2Term); // Use StringRef's comparison methods to compute the actual result. @@ -1624,7 +1650,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, if (!canComputeResult) { // Conjure a symbolic value. It's the best we can do. - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + unsigned Count = C.getCurrentBlockCount(); SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, Count); state = state->BindExpr(CE, resultVal); } @@ -1640,7 +1666,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // Get the callee. All the functions we care about are C functions // with simple identifiers. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl(); @@ -1651,7 +1677,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { IdentifierInfo *II = FD->getIdentifier(); if (!II) // if no identifier, not a simple C function return false; - llvm::StringRef Name = II->getName(); + StringRef Name = II->getName(); if (Name.startswith("__builtin_")) Name = Name.substr(10); @@ -1689,7 +1715,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { // Record string length for char a[] = "abc"; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { @@ -1723,16 +1749,16 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { C.addTransition(state); } -bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const { +bool CStringChecker::wantsRegionChangeUpdate(const ProgramState *state) const { CStringLength::EntryMap Entries = state->get<CStringLength>(); return !Entries.isEmpty(); } -const GRState * -CStringChecker::checkRegionChanges(const GRState *state, +const ProgramState * +CStringChecker::checkRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *, - const MemRegion * const *Begin, - const MemRegion * const *End) const { + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions) const { CStringLength::EntryMap Entries = state->get<CStringLength>(); if (Entries.isEmpty()) return state; @@ -1741,8 +1767,9 @@ CStringChecker::checkRegionChanges(const GRState *state, llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; // First build sets for the changed regions and their super-regions. - for ( ; Begin != End; ++Begin) { - const MemRegion *MR = *Begin; + for (ArrayRef<const MemRegion *>::iterator + I = Regions.begin(), E = Regions.end(); I != E; ++I) { + const MemRegion *MR = *I; Invalidated.insert(MR); SuperRegions.insert(MR); @@ -1779,7 +1806,7 @@ CStringChecker::checkRegionChanges(const GRState *state, return state->set<CStringLength>(Entries); } -void CStringChecker::checkLiveSymbols(const GRState *state, +void CStringChecker::checkLiveSymbols(const ProgramState *state, SymbolReaper &SR) const { // Mark all symbols in our string length map as valid. CStringLength::EntryMap Entries = state->get<CStringLength>(); @@ -1799,7 +1826,7 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR, if (!SR.hasDeadSymbols()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); CStringLength::EntryMap Entries = state->get<CStringLength>(); if (Entries.isEmpty()) return; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 6c3dfac..4db6ac0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" @@ -47,7 +48,8 @@ private: void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, ExplodedNode *N) const; - void HandleNilReceiver(CheckerContext &C, const GRState *state, + void HandleNilReceiver(CheckerContext &C, + const ProgramState *state, ObjCMessage msg) const; static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) { @@ -63,9 +65,9 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, if (!N) return; - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetCalleeExpr(N)); + BugReport *R = new BugReport(*BT, BT->getName(), N); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + bugreporter::GetCalleeExpr(N))); C.EmitReport(R); } @@ -91,10 +93,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, LazyInit_BT(BT_desc, BT); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(argRange); if (argEx) - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx)); C.EmitReport(R); } return true; @@ -105,7 +107,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, class FindUninitializedField { public: - llvm::SmallVector<const FieldDecl *, 10> FieldChain; + SmallVector<const FieldDecl *, 10> FieldChain; private: ASTContext &C; StoreManager &StoreMgr; @@ -116,7 +118,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, MemRegionManager &mrMgr, Store s) : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} - bool Find(const TypedRegion *R) { + bool Find(const TypedValueRegion *R) { QualType T = R->getValueType(); if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl()->getDefinition(); @@ -157,23 +159,23 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, os << "Passed-by-value struct argument contains uninitialized data"; if (F.FieldChain.size() == 1) - os << " (e.g., field: '" << F.FieldChain[0] << "')"; + os << " (e.g., field: '" << *F.FieldChain[0] << "')"; else { os << " (e.g., via the field chain: '"; bool first = true; - for (llvm::SmallVectorImpl<const FieldDecl *>::iterator + for (SmallVectorImpl<const FieldDecl *>::iterator DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ if (first) first = false; else os << '.'; - os << *DI; + os << **DI; } os << "')"; } // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); + BugReport *R = new BugReport(*BT, os.str(), N); R->addRange(argRange); // FIXME: enhance track back for uninitialized value for arbitrary @@ -216,7 +218,7 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // FIXME: Handle 'super'? if (const Expr *receiver = msg.getInstanceReceiver()) { @@ -226,11 +228,11 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, if (!BT_msg_undef) BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is " "an uninitialized value")); - EnhancedBugReport *R = - new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); + BugReport *R = + new BugReport(*BT_msg_undef, BT_msg_undef->getName(), N); R->addRange(receiver->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - receiver); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + receiver)); C.EmitReport(R); } return; @@ -238,7 +240,7 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); - const GRState *notNilState, *nilState; + const ProgramState *notNilState, *nilState; llvm::tie(notNilState, nilState) = state->assume(receiverVal); // Handle receiver must be nil. @@ -271,11 +273,11 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, << "' is nil and returns a value of type '" << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; - EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); + BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); if (const Expr *receiver = msg.getInstanceReceiver()) { report->addRange(receiver->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - receiver); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + receiver)); } C.EmitReport(report); } @@ -288,7 +290,7 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) { } void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, - const GRState *state, + const ProgramState *state, ObjCMessage msg) const { ASTContext &Ctx = C.getASTContext(); @@ -303,7 +305,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, // have the "use of undefined value" be smarter about where the // undefined value came from. if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){ - if (ExplodedNode* N = C.generateSink(state)) + if (ExplodedNode *N = C.generateSink(state)) emitNilReceiverBug(C, msg, N); return; } @@ -322,13 +324,13 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); if (voidPtrSize < returnTypeSize && - !(supportsNilWithFloatRet(Ctx.Target.getTriple()) && + !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && (Ctx.FloatTy == CanRetTy || Ctx.DoubleTy == CanRetTy || Ctx.LongDoubleTy == CanRetTy || Ctx.LongLongTy == CanRetTy || Ctx.UnsignedLongLongTy == CanRetTy))) { - if (ExplodedNode* N = C.generateSink(state)) + if (ExplodedNode *N = C.generateSink(state)) emitNilReceiverBug(C, msg, N); return; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 585a87d..84a9e6b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -44,7 +44,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { if (ToPointeeTy->isIncompleteType()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const MemRegion *R = state->getSVal(E).getAsRegion(); if (R == 0) return; @@ -72,7 +72,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { BT.reset(new BuiltinBug("Cast region with wrong size.", "Cast a region whose size is not a multiple of the" " destination type size.")); - RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), + BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode); R->addRange(CE->getSourceRange()); C.EmitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 3210b0a..c855210 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -62,7 +62,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE, "Casting a non-structure type to a structure type " "and accessing a field can lead to memory access " "errors or data corruption.")); - RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N); + BugReport *R = new BugReport(*BT,BT->getDescription(), N); R->addRange(CE->getSourceRange()); C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 0c693a0..c325bb1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -27,9 +27,9 @@ using namespace clang; using namespace ento; -static bool scan_dealloc(Stmt* S, Selector Dealloc) { +static bool scan_dealloc(Stmt *S, Selector Dealloc) { - if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) if (ME->getSelector() == Dealloc) { switch (ME->getReceiverKind()) { case ObjCMessageExpr::Instance: return false; @@ -48,26 +48,26 @@ static bool scan_dealloc(Stmt* S, Selector Dealloc) { return false; } -static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, - const ObjCPropertyDecl* PD, +static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID, + const ObjCPropertyDecl *PD, Selector Release, IdentifierInfo* SelfII, - ASTContext& Ctx) { + ASTContext &Ctx) { // [mMyIvar release] - if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) if (ME->getSelector() == Release) if (ME->getInstanceReceiver()) - if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) - if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver)) + if (Expr *Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) + if (ObjCIvarRefExpr *E = dyn_cast<ObjCIvarRefExpr>(Receiver)) if (E->getDecl() == ID) return true; // [self setMyIvar:nil]; - if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) if (ME->getInstanceReceiver()) - if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) - if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver)) + if (Expr *Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) + if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(Receiver)) if (E->getDecl()->getIdentifier() == SelfII) if (ME->getMethodDecl() == PD->getSetterMethodDecl() && ME->getNumArgs() == 1 && @@ -78,7 +78,7 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, // self.myIvar = nil; if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S)) if (BO->isAssignmentOp()) - if (ObjCPropertyRefExpr* PRE = + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts())) if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD) if (BO->getRHS()->isNullPointerConstant(Ctx, @@ -96,13 +96,13 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, return false; } -static void checkObjCDealloc(const ObjCImplementationDecl* D, +static void checkObjCDealloc(const ObjCImplementationDecl *D, const LangOptions& LOpts, BugReporter& BR) { - assert (LOpts.getGCMode() != LangOptions::GCOnly); + assert (LOpts.getGC() != LangOptions::GCOnly); - ASTContext& Ctx = BR.getContext(); - const ObjCInterfaceDecl* ID = D->getClassInterface(); + ASTContext &Ctx = BR.getContext(); + const ObjCInterfaceDecl *ID = D->getClassInterface(); // Does the class contain any ivars that are pointers (or id<...>)? // If not, skip the check entirely. @@ -114,7 +114,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { - ObjCIvarDecl* ID = *I; + ObjCIvarDecl *ID = *I; QualType T = ID->getType(); if (!T->isObjCObjectPointerType() || @@ -154,7 +154,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, // Get the "dealloc" selector. IdentifierInfo* II = &Ctx.Idents.get("dealloc"); Selector S = Ctx.Selectors.getSelector(0, &II); - ObjCMethodDecl* MD = 0; + ObjCMethodDecl *MD = 0; // Scan the instance methods for "dealloc". for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), @@ -166,9 +166,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, } } + PathDiagnosticLocation DLoc = + PathDiagnosticLocation::createBegin(D, BR.getSourceManager()); + if (!MD) { // No dealloc found. - const char* name = LOpts.getGCMode() == LangOptions::NonGC + const char* name = LOpts.getGC() == LangOptions::NonGC ? "missing -dealloc" : "missing -dealloc (Hybrid MM, non-GC)"; @@ -176,14 +179,14 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, llvm::raw_string_ostream os(buf); os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method"; - BR.EmitBasicReport(name, os.str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), DLoc); return; } // dealloc found. Scan for missing [super dealloc]. if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) { - const char* name = LOpts.getGCMode() == LangOptions::NonGC + const char* name = LOpts.getGC() == LangOptions::NonGC ? "missing [super dealloc]" : "missing [super dealloc] (Hybrid MM, non-GC)"; @@ -193,7 +196,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - BR.EmitBasicReport(name, os.str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), DLoc); return; } @@ -213,7 +216,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, if ((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) continue; - ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl(); + ObjCIvarDecl *ID = (*I)->getPropertyIvarDecl(); if (!ID) continue; @@ -221,13 +224,13 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars continue; - const ObjCPropertyDecl* PD = (*I)->getPropertyDecl(); + const ObjCPropertyDecl *PD = (*I)->getPropertyDecl(); if (!PD) continue; // ivars cannot be set via read-only properties, so we'll skip them if (PD->isReadOnly()) - continue; + continue; // ivar must be released if and only if the kind of setter was not 'assign' bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign; @@ -240,24 +243,27 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, llvm::raw_string_ostream os(buf); if (requiresRelease) { - name = LOpts.getGCMode() == LangOptions::NonGC + name = LOpts.getGC() == LangOptions::NonGC ? "missing ivar release (leak)" : "missing ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID + os << "The '" << *ID << "' instance variable was retained by a synthesized property but " "wasn't released in 'dealloc'"; } else { - name = LOpts.getGCMode() == LangOptions::NonGC + name = LOpts.getGC() == LangOptions::NonGC ? "extra ivar release (use-after-release)" : "extra ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID + os << "The '" << *ID << "' instance variable was not retained by a synthesized property " "but was released in 'dealloc'"; } - BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation()); + PathDiagnosticLocation SDLoc = + PathDiagnosticLocation::createBegin((*I), BR.getSourceManager()); + + BR.EmitBasicReport(name, category, os.str(), SDLoc); } } } @@ -272,7 +278,7 @@ class ObjCDeallocChecker : public Checker< public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, BugReporter &BR) const { - if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) + if (mgr.getLangOptions().getGC() == LangOptions::GCOnly) return; checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index fec06a9..c076c1e3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -28,7 +28,7 @@ using namespace clang; using namespace ento; static bool AreTypesCompatible(QualType Derived, QualType Ancestor, - ASTContext& C) { + ASTContext &C) { // Right now don't compare the compatibility of pointers. That involves // looking at subtyping relationships. FIXME: Future patch. @@ -51,36 +51,40 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, llvm::raw_string_ostream os(sbuf); os << "The Objective-C class '" - << MethDerived->getClassInterface() + << *MethDerived->getClassInterface() << "', which is derived from class '" - << MethAncestor->getClassInterface() + << *MethAncestor->getClassInterface() << "', defines the instance method '" << MethDerived->getSelector().getAsString() << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" - << MethAncestor->getClassInterface() + << *MethAncestor->getClassInterface() << "' and has a return type of '" << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " "behavior for clients of these classes."; + PathDiagnosticLocation MethDLoc = + PathDiagnosticLocation::createBegin(MethDerived, + BR.getSourceManager()); + BR.EmitBasicReport("Incompatible instance method return type", - os.str(), MethDerived->getLocStart()); + os.str(), MethDLoc); } } -static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, +static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, BugReporter& BR) { - const ObjCInterfaceDecl* D = ID->getClassInterface(); - const ObjCInterfaceDecl* C = D->getSuperClass(); + const ObjCInterfaceDecl *D = ID->getClassInterface(); + const ObjCInterfaceDecl *C = D->getSuperClass(); if (!C) return; - ASTContext& Ctx = BR.getContext(); + ASTContext &Ctx = BR.getContext(); // Build a DenseMap of the methods for quick querying. typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; @@ -90,7 +94,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), E=ID->instmeth_end(); I!=E; ++I) { - ObjCMethodDecl* M = *I; + ObjCMethodDecl *M = *I; IMeths[M->getSelector()] = M; ++NumMethods; } @@ -101,7 +105,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(), E=C->instmeth_end(); I!=E; ++I) { - ObjCMethodDecl* M = *I; + ObjCMethodDecl *M = *I; Selector S = M->getSelector(); MapTy::iterator MI = IMeths.find(S); @@ -110,7 +114,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, continue; --NumMethods; - ObjCMethodDecl* MethDerived = MI->second; + ObjCMethodDecl *MethDerived = MI->second; MI->second = 0; CompareReturnTypes(MethDerived, M, BR, Ctx, ID); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 53810ee..bf7ba18 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -12,18 +12,20 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/AST/StmtVisitor.h" -#include "llvm/Support/raw_ostream.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; static bool isArc4RandomAvailable(const ASTContext &Ctx) { - const llvm::Triple &T = Ctx.Target.getTriple(); + const llvm::Triple &T = Ctx.getTargetInfo().getTriple(); return T.getVendor() == llvm::Triple::Apple || T.getOS() == llvm::Triple::FreeBSD || T.getOS() == llvm::Triple::NetBSD || @@ -34,14 +36,16 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) { namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; + AnalysisContext* AC; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; const bool CheckRand; public: - WalkAST(BugReporter &br) : BR(br), II_setid(), - CheckRand(isArc4RandomAvailable(BR.getContext())) {} + WalkAST(BugReporter &br, AnalysisContext* ac) + : BR(br), AC(ac), II_setid(), + CheckRand(isArc4RandomAvailable(BR.getContext())) {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -52,7 +56,6 @@ public: void VisitChildren(Stmt *S); // Helpers. - IdentifierInfo *getIdentifier(IdentifierInfo *& II, const char *str); bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD); typedef void (WalkAST::*FnCheck)(const CallExpr *, @@ -67,22 +70,12 @@ public: void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD); void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD); void checkCall_random(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD); void checkUncheckedReturnValue(CallExpr *CE); }; } // end anonymous namespace //===----------------------------------------------------------------------===// -// Helper methods. -//===----------------------------------------------------------------------===// - -IdentifierInfo *WalkAST::getIdentifier(IdentifierInfo *& II, const char *str) { - if (!II) - II = &BR.getContext().Idents.get(str); - - return II; -} - -//===----------------------------------------------------------------------===// // AST walking. //===----------------------------------------------------------------------===// @@ -103,7 +96,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { IdentifierInfo *II = FD->getIdentifier(); if (!II) // if no identifier, not a simple C function return; - llvm::StringRef Name = II->getName(); + StringRef Name = II->getName(); if (Name.startswith("__builtin_")) Name = Name.substr(10); @@ -124,6 +117,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { .Case("rand", &WalkAST::checkCall_rand) .Case("rand_r", &WalkAST::checkCall_rand) .Case("random", &WalkAST::checkCall_random) + .Case("vfork", &WalkAST::checkCall_vfork) .Default(NULL); // If the callee isn't defined, it is not of security concern. @@ -247,7 +241,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { // referenced the compared variable. const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS; - llvm::SmallVector<SourceRange, 2> ranges; + SmallVector<SourceRange, 2> ranges; llvm::SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -259,8 +253,11 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { ranges.push_back(drInc->getSourceRange()); const char *bugType = "Floating point variable used as loop counter"; + + PathDiagnosticLocation FSLoc = + PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC); BR.EmitBasicReport(bugType, "Security", os.str(), - FS->getLocStart(), ranges.data(), ranges.size()); + FSLoc, ranges.data(), ranges.size()); } //===----------------------------------------------------------------------===// @@ -290,11 +287,13 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential buffer overflow in call to 'gets'", "Security", "Call to function 'gets' is extremely insecure as it can " "always result in a buffer overflow", - CE->getLocStart(), &R, 1); + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -326,11 +325,13 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'", "Security", "The getpw() function is dangerous as it may overflow the " "provided buffer. It is obsoleted by getpwuid().", - CE->getLocStart(), &R, 1); + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -359,11 +360,13 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { // Issue a waring. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", "Security", "Call to function 'mktemp' is insecure as it always " "creates or uses insecure temporary file. Use 'mkstemp' instead", - CE->getLocStart(), &R, 1); + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -378,6 +381,8 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " "call 'strcpy'", "Security", @@ -385,7 +390,7 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { "provide bounding of the memory buffer. Replace " "unbounded copy functions with analogous functions that " "support length arguments such as 'strncpy'. CWE-119.", - CE->getLocStart(), &R, 1); + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -400,6 +405,8 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " "call 'strcat'", "Security", @@ -407,7 +414,7 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { "provide bounding of the memory buffer. Replace " "unbounded copy functions with analogous functions that " "support length arguments such as 'strncat'. CWE-119.", - CE->getLocStart(), &R, 1); + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -470,16 +477,18 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << '\'' << FD << "' is a poor random number generator"; + os1 << '\'' << *FD << "' is a poor random number generator"; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "Function '" << FD + os2 << "Function '" << *FD << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -502,11 +511,33 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport("'random' is not a secure random number generator", "Security", "The 'random' function produces a sequence of values that " "an adversary may be able to predict. Use 'arc4random' " - "instead", CE->getLocStart(), &R, 1); + "instead", CELoc, &R, 1); +} + +//===----------------------------------------------------------------------===// +// Check: 'vfork' should not be used. +// POS33-C: Do not use vfork(). +//===----------------------------------------------------------------------===// + +void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) { + // All calls to vfork() are insecure, issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + BR.EmitBasicReport("Potential insecure implementation-specific behavior in " + "call 'vfork'", + "Security", + "Call to function 'vfork' is insecure as it can lead to " + "denial of service situations in the parent process. " + "Replace calls to vfork with calls to the safer " + "'posix_spawn' function", + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -557,16 +588,18 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "Return value is not checked in call to '" << FD << '\''; + os1 << "Return value is not checked in call to '" << *FD << '\''; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "The return value from the call to '" << FD - << "' is not checked. If an error occurs in '" << FD + os2 << "The return value from the call to '" << *FD + << "' is not checked. If an error occurs in '" << *FD << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -578,7 +611,7 @@ class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - WalkAST walker(BR); + WalkAST walker(BR, mgr.getAnalysisContext(D)); walker.Visit(D->getBody()); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index abf53fd..469be05 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -13,9 +13,10 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "clang/AST/StmtVisitor.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/AST/StmtVisitor.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" using namespace clang; using namespace ento; @@ -23,9 +24,10 @@ using namespace ento; namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; + AnalysisContext* AC; public: - WalkAST(BugReporter &br) : BR(br) {} + WalkAST(BugReporter &br, AnalysisContext* ac) : BR(br), AC(ac) {} void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitChildren(Stmt *S); @@ -59,11 +61,13 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { return; SourceRange R = ArgEx->getSourceRange(); + PathDiagnosticLocation ELoc = + PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type", "Logic", "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", - E->getLocStart(), &R, 1); + ELoc, &R, 1); } } @@ -76,7 +80,7 @@ class SizeofPointerChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - WalkAST walker(BR); + WalkAST walker(BR, mgr.getAnalysisContext(D)); walker.Visit(D->getBody()); } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td index 2c196b5..d53e0b8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td @@ -10,41 +10,32 @@ include "clang/StaticAnalyzer/Checkers/CheckerBase.td" //===----------------------------------------------------------------------===// -// Groups. -//===----------------------------------------------------------------------===// - -def AllExperimental : CheckerGroup<"all-experimental">; - -//===----------------------------------------------------------------------===// // Packages. //===----------------------------------------------------------------------===// +def Experimental : Package<"experimental">; + def Core : Package<"core">; def CoreBuiltin : Package<"builtin">, InPackage<Core>; def CoreUninitialized : Package<"uninitialized">, InPackage<Core>; -def CoreExperimental : Package<"experimental">, InPackage<Core>, - InGroup<AllExperimental>, Hidden; +def CoreExperimental : Package<"core">, InPackage<Experimental>, Hidden; def Cplusplus : Package<"cplusplus">; -def CplusplusExperimental : Package<"experimental">, InPackage<Cplusplus>, - InGroup<AllExperimental>, Hidden; +def CplusplusExperimental : Package<"cplusplus">, InPackage<Experimental>, Hidden; def DeadCode : Package<"deadcode">; -def DeadCodeExperimental : Package<"experimental">, InPackage<DeadCode>, - InGroup<AllExperimental>, Hidden; +def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden; def Security : Package <"security">; -def SecurityExperimental : Package<"experimental">, InPackage<Security>, - InGroup<AllExperimental>, Hidden; +def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden; def Unix : Package<"unix">; -def UnixExperimental : Package<"experimental">, InPackage<Unix>, - InGroup<AllExperimental>, Hidden; +def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden; def OSX : Package<"osx">; +def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden; def Cocoa : Package<"cocoa">, InPackage<OSX>; -def CocoaExperimental : Package<"experimental">, InPackage<Cocoa>, - InGroup<AllExperimental>, Hidden; +def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden; def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>; def LLVM : Package<"llvm">; @@ -220,6 +211,10 @@ def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, HelpText<"Check for an out-of-bound pointer being returned to callers">, DescFile<"ReturnPointerRangeChecker.cpp">; +def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, + HelpText<"Check for overflows in the arguments to malloc()">, + DescFile<"MallocOverflowSecurityChecker.cpp">; + } // end "security.experimental" //===----------------------------------------------------------------------===// @@ -274,6 +269,11 @@ def OSAtomicChecker : Checker<"AtomicCAS">, HelpText<"Evaluate calls to OSAtomic functions">, DescFile<"OSAtomicChecker.cpp">; +def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, + InPackage<OSX>, + HelpText<"Check for proper uses of Secure Keychain APIs">, + DescFile<"MacOSKeychainAPIChecker.cpp">; + } // end "macosx" let ParentPackage = Cocoa in { @@ -311,6 +311,10 @@ def NSErrorChecker : Checker<"NSError">, HelpText<"Check usage of NSError** parameters">, DescFile<"NSErrorChecker.cpp">; +def RetainCountChecker : Checker<"RetainCount">, + HelpText<"Check for leaks and improper reference count management">, + DescFile<"RetainCountChecker.cpp">; + } // end "cocoa" let ParentPackage = CocoaExperimental in { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index 50b57d1..3c92381 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -16,8 +16,8 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -62,7 +62,7 @@ private: } // end anonymous namespace bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); const FunctionDecl *FD = L.getAsFunctionDecl(); @@ -88,8 +88,8 @@ bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { } void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); - GRStateManager &Mgr = state->getStateManager(); + const ProgramState *state = C.getState(); + ProgramStateManager &Mgr = state->getStateManager(); // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in // the GDM. @@ -98,11 +98,11 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const { } void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); - GRStateManager &Mgr = state->getStateManager(); + const ProgramState *state = C.getState(); + ProgramStateManager &Mgr = state->getStateManager(); // If there are no jail state in the GDM, just return. - const void* k = state->FindGDM(ChrootChecker::getTag()); + const void *k = state->FindGDM(ChrootChecker::getTag()); if (!k) return; @@ -125,7 +125,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const { // Check the jail state before any function call except chroot and chdir(). void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); const FunctionDecl *FD = L.getAsFunctionDecl(); @@ -143,7 +143,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { return; // If jail state is ROOT_CHANGED, generate BugReport. - void* const* k = state->FindGDM(ChrootChecker::getTag()); + void *const* k = state->FindGDM(ChrootChecker::getTag()); if (k) if (isRootChanged((intptr_t) *k)) if (ExplodedNode *N = C.generateNode()) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp new file mode 100644 index 0000000..77a5a72 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp @@ -0,0 +1,32 @@ +//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h" +#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" + +// FIXME: This is only necessary as long as there are checker registration +// functions that do additional work besides mgr.registerChecker<CLASS>(). +// The only checkers that currently do this are: +// - NSAutoreleasePoolChecker +// - NSErrorChecker +// - ObjCAtSyncChecker +// It's probably worth including this information in Checkers.td to minimize +// boilerplate code. +#include "ClangSACheckers.h" + +using namespace clang; +using namespace ento; + +void ento::registerBuiltinCheckers(CheckerRegistry ®istry) { +#define GET_CHECKERS +#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ + registry.addChecker(register##CLASS, FULLNAME, HELPTEXT); +#include "Checkers.inc" +#undef GET_CHECKERS +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp deleted file mode 100644 index 291f8e0..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp +++ /dev/null @@ -1,289 +0,0 @@ -//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the CheckerProvider for the checkers defined in -// libclangStaticAnalyzerCheckers. -// -//===----------------------------------------------------------------------===// - -#include "ClangSACheckerProvider.h" -#include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/DenseSet.h" -#include "map" - -using namespace clang; -using namespace ento; - -namespace { - -/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers. -class ClangSACheckerProvider : public CheckerProvider { -public: - virtual void registerCheckers(CheckerManager &checkerMgr, - CheckerOptInfo *checkOpts, unsigned numCheckOpts); - virtual void printHelp(llvm::raw_ostream &OS); -}; - -} - -CheckerProvider *ento::createClangSACheckerProvider() { - return new ClangSACheckerProvider(); -} - -namespace { - -struct StaticCheckerInfoRec { - const char *FullName; - void (*RegFunc)(CheckerManager &mgr); - const char *HelpText; - int GroupIndex; - bool Hidden; -}; - -struct StaticPackageInfoRec { - const char *FullName; - int GroupIndex; - bool Hidden; -}; - -struct StaticGroupInfoRec { - const char *FullName; -}; - -} // end anonymous namespace. - -static const StaticPackageInfoRec StaticPackageInfo[] = { -#define GET_PACKAGES -#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \ - { FULLNAME, GROUPINDEX, HIDDEN }, -#include "Checkers.inc" - { 0, -1, 0 } -#undef PACKAGE -#undef GET_PACKAGES -}; - -static const unsigned NumPackages = sizeof(StaticPackageInfo) - / sizeof(StaticPackageInfoRec) - 1; - -static const StaticGroupInfoRec StaticGroupInfo[] = { -#define GET_GROUPS -#define GROUP(FULLNAME) \ - { FULLNAME }, -#include "Checkers.inc" - { 0 } -#undef GROUP -#undef GET_GROUPS -}; - -static const unsigned NumGroups = sizeof(StaticGroupInfo) - / sizeof(StaticGroupInfoRec) - 1; - -static const StaticCheckerInfoRec StaticCheckerInfo[] = { -#define GET_CHECKERS -#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ - { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN }, -#include "Checkers.inc" - { 0, 0, 0, -1, 0} -#undef CHECKER -#undef GET_CHECKERS -}; - -static const unsigned NumCheckers = sizeof(StaticCheckerInfo) - / sizeof(StaticCheckerInfoRec) - 1; - -namespace { - -struct CheckNameOption { - const char *Name; - const short *Members; - const short *SubGroups; - bool Hidden; -}; - -} // end anonymous namespace. - -#define GET_MEMBER_ARRAYS -#include "Checkers.inc" -#undef GET_MEMBER_ARRAYS - -// The table of check name options, sorted by name for fast binary lookup. -static const CheckNameOption CheckNameTable[] = { -#define GET_CHECKNAME_TABLE -#include "Checkers.inc" -#undef GET_CHECKNAME_TABLE -}; -static const size_t - CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]); - -static bool CheckNameOptionCompare(const CheckNameOption &LHS, - const CheckNameOption &RHS) { - return strcmp(LHS.Name, RHS.Name) < 0; -} - -static void collectCheckers(const CheckNameOption *checkName, - bool enable, - llvm::DenseSet<const StaticCheckerInfoRec *> &checkers, - bool collectHidden) { - if (checkName->Hidden && !collectHidden) - return; - - if (const short *member = checkName->Members) { - if (enable) { - for (; *member != -1; ++member) - if (collectHidden || !StaticCheckerInfo[*member].Hidden) - checkers.insert(&StaticCheckerInfo[*member]); - } else { - for (; *member != -1; ++member) - checkers.erase(&StaticCheckerInfo[*member]); - } - } - - // Enable/disable all subgroups along with this one. - if (const short *subGroups = checkName->SubGroups) { - for (; *subGroups != -1; ++subGroups) { - const CheckNameOption *sub = &CheckNameTable[*subGroups]; - collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden); - } - } -} - -static void collectCheckers(CheckerOptInfo &opt, - llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) { - const char *optName = opt.getName(); - CheckNameOption key = { optName, 0, 0, false }; - const CheckNameOption *found = - std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key, - CheckNameOptionCompare); - if (found == CheckNameTable + CheckNameTableSize || - strcmp(found->Name, optName) != 0) - return; // Check name not found. - - opt.claim(); - collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true); -} - -void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr, - CheckerOptInfo *checkOpts, unsigned numCheckOpts) { - llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers; - for (unsigned i = 0; i != numCheckOpts; ++i) - collectCheckers(checkOpts[i], enabledCheckers); - for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator - I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) { - (*I)->RegFunc(checkerMgr); - } -} - -//===----------------------------------------------------------------------===// -// Printing Help. -//===----------------------------------------------------------------------===// - -static void printPackageOption(llvm::raw_ostream &OS) { - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (unsigned i = 0; i != NumPackages; ++i) { - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = strlen(StaticPackageInfo[i].FullName); - if (Length <= 30) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - const unsigned InitialPad = 2; - for (unsigned i = 0; i != NumPackages; ++i) { - const StaticPackageInfoRec &package = StaticPackageInfo[i]; - const std::string &Option = package.FullName; - int Pad = OptionFieldWidth - int(Option.size()); - OS.indent(InitialPad) << Option; - - if (package.GroupIndex != -1 || package.Hidden) { - // Break on long option names. - if (Pad < 0) { - OS << "\n"; - Pad = OptionFieldWidth + InitialPad; - } - OS.indent(Pad + 1) << "["; - if (package.GroupIndex != -1) { - OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName; - if (package.Hidden) - OS << ", "; - } - if (package.Hidden) - OS << "Hidden"; - OS << "]"; - } - - OS << "\n"; - } -} - -typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers; - -static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) { - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (SortedCheckers::iterator - I = checkers.begin(), E = checkers.end(); I != E; ++I) { - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = strlen(I->second->FullName); - if (Length <= 30) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - const unsigned InitialPad = 2; - for (SortedCheckers::iterator - I = checkers.begin(), E = checkers.end(); I != E; ++I) { - const std::string &Option = I->first; - const StaticCheckerInfoRec &checker = *I->second; - int Pad = OptionFieldWidth - int(Option.size()); - OS.indent(InitialPad) << Option; - - // Break on long option names. - if (Pad < 0) { - OS << "\n"; - Pad = OptionFieldWidth + InitialPad; - } - OS.indent(Pad + 1) << checker.HelpText; - - if (checker.GroupIndex != -1 || checker.Hidden) { - OS << " ["; - if (checker.GroupIndex != -1) { - OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName; - if (checker.Hidden) - OS << ", "; - } - if (checker.Hidden) - OS << "Hidden"; - OS << "]"; - } - - OS << "\n"; - } -} - -void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) { - OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n"; - - OS << "\nGROUPS:\n"; - for (unsigned i = 0; i != NumGroups; ++i) - OS.indent(2) << StaticGroupInfo[i].FullName << "\n"; - - OS << "\nPACKAGES:\n"; - printPackageOption(OS); - - OS << "\nCHECKERS:\n"; - - // Sort checkers according to their full name. - SortedCheckers checkers; - for (unsigned i = 0; i != NumCheckers; ++i) - checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i]; - - printCheckerOption(OS, checkers); -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h deleted file mode 100644 index f6c8011..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h +++ /dev/null @@ -1,29 +0,0 @@ -//===--- ClangSACheckerProvider.h - Clang SA Checkers Provider --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the entry point for creating the provider for the checkers defined -// in libclangStaticAnalyzerCheckers. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H -#define LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H - -namespace clang { - -namespace ento { - class CheckerProvider; - -CheckerProvider *createClangSACheckerProvider(); - -} // end ento namespace - -} // end clang namespace - -#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h index 5524b0f..289ce8d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h @@ -19,6 +19,7 @@ namespace clang { namespace ento { class CheckerManager; +class CheckerRegistry; #define GET_CHECKERS #define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index ec2a88a..901af43 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -50,7 +50,7 @@ void ReachableCode::computeReachableBlocks() { if (!cfg.getNumBlockIDs()) return; - llvm::SmallVector<const CFGBlock*, 10> worklist; + SmallVector<const CFGBlock*, 10> worklist; worklist.push_back(&cfg.getEntry()); while (!worklist.empty()) { @@ -68,12 +68,13 @@ void ReachableCode::computeReachableBlocks() { } namespace { -class DeadStoreObs : public LiveVariables::ObserverTy { +class DeadStoreObs : public LiveVariables::Observer { const CFG &cfg; ASTContext &Ctx; BugReporter& BR; + AnalysisContext* AC; ParentMap& Parents; - llvm::SmallPtrSet<VarDecl*, 20> Escaped; + llvm::SmallPtrSet<const VarDecl*, 20> Escaped; llvm::OwningPtr<ReachableCode> reachableCode; const CFGBlock *currentBlock; @@ -81,14 +82,15 @@ class DeadStoreObs : public LiveVariables::ObserverTy { public: DeadStoreObs(const CFG &cfg, ASTContext &ctx, - BugReporter& br, ParentMap& parents, - llvm::SmallPtrSet<VarDecl*, 20> &escaped) - : cfg(cfg), Ctx(ctx), BR(br), Parents(parents), + BugReporter& br, AnalysisContext* ac, ParentMap& parents, + llvm::SmallPtrSet<const VarDecl*, 20> &escaped) + : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents), Escaped(escaped), currentBlock(0) {} virtual ~DeadStoreObs() {} - void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) { + void Report(const VarDecl *V, DeadStoreKind dsk, + PathDiagnosticLocation L, SourceRange R) { if (Escaped.count(V)) return; @@ -102,26 +104,25 @@ public: if (!reachableCode->isReachable(currentBlock)) return; - const std::string &name = V->getNameAsString(); - - const char* BugType = 0; - std::string msg; + llvm::SmallString<64> buf; + llvm::raw_svector_ostream os(buf); + const char *BugType = 0; switch (dsk) { default: - assert(false && "Impossible dead store type."); + llvm_unreachable("Impossible dead store type."); case DeadInit: BugType = "Dead initialization"; - msg = "Value stored to '" + name + - "' during its initialization is never read"; + os << "Value stored to '" << *V + << "' during its initialization is never read"; break; case DeadIncrement: BugType = "Dead increment"; case Standard: if (!BugType) BugType = "Dead assignment"; - msg = "Value stored to '" + name + "' is never read"; + os << "Value stored to '" << *V << "' is never read"; break; case Enclosing: @@ -131,13 +132,12 @@ public: return; } - BR.EmitBasicReport(BugType, "Dead store", msg, L, R); + BR.EmitBasicReport(BugType, "Dead store", os.str(), L, R); } - void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val, + void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, DeadStoreKind dsk, - const LiveVariables::AnalysisDataTy& AD, - const LiveVariables::ValTy& Live) { + const LiveVariables::LivenessValues &Live) { if (!VD->hasLocalStorage()) return; @@ -146,30 +146,32 @@ public: if (VD->getType()->getAs<ReferenceType>()) return; - if (!Live(VD, AD) && - !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) - Report(VD, dsk, Ex->getSourceRange().getBegin(), - Val->getSourceRange()); + if (!Live.isLive(VD) && + !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) { + + PathDiagnosticLocation ExLoc = + PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC); + Report(VD, dsk, ExLoc, Val->getSourceRange()); + } } - void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk, - const LiveVariables::AnalysisDataTy& AD, - const LiveVariables::ValTy& Live) { - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) - CheckVarDecl(VD, DR, Val, dsk, AD, Live); + void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk, + const LiveVariables::LivenessValues& Live) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) + CheckVarDecl(VD, DR, Val, dsk, Live); } - bool isIncrement(VarDecl* VD, BinaryOperator* B) { + bool isIncrement(VarDecl *VD, const BinaryOperator* B) { if (B->isCompoundAssignmentOp()) return true; - Expr* RHS = B->getRHS()->IgnoreParenCasts(); - BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); + const Expr *RHS = B->getRHS()->IgnoreParenCasts(); + const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS); if (!BRHS) return false; - DeclRefExpr *DR; + const DeclRefExpr *DR; if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts()))) if (DR->getDecl() == VD) @@ -182,9 +184,8 @@ public: return false; } - virtual void ObserveStmt(Stmt* S, const CFGBlock *block, - const LiveVariables::AnalysisDataTy& AD, - const LiveVariables::ValTy& Live) { + virtual void observeStmt(const Stmt *S, const CFGBlock *block, + const LiveVariables::LivenessValues &Live) { currentBlock = block; @@ -194,10 +195,10 @@ public: // Only cover dead stores from regular assignments. ++/-- dead stores // have never flagged a real bug. - if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { + if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { if (!B->isAssignmentOp()) return; // Skip non-assignments. - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS())) + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS())) if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. @@ -208,10 +209,10 @@ public: return; } - Expr* RHS = B->getRHS()->IgnoreParenCasts(); + Expr *RHS = B->getRHS()->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. - if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS)) + if (DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) if (VD == dyn_cast<VarDecl>(RhsDR->getDecl())) return; @@ -220,29 +221,29 @@ public: ? Enclosing : (isIncrement(VD,B) ? DeadIncrement : Standard); - CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live); + CheckVarDecl(VD, DR, B->getRHS(), dsk, Live); } } - else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { + else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) { if (!U->isIncrementOp() || U->isPrefix()) return; - Stmt *parent = Parents.getParentIgnoreParenCasts(U); + const Stmt *parent = Parents.getParentIgnoreParenCasts(U); if (!parent || !isa<ReturnStmt>(parent)) return; - Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); + const Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex)) - CheckDeclRef(DR, U, DeadIncrement, AD, Live); + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) + CheckDeclRef(DR, U, DeadIncrement, Live); } - else if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) + else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) // Iterate through the decls. Warn if any initializers are complex // expressions that are not live (never used). - for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); + for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); DI != DE; ++DI) { - VarDecl* V = dyn_cast<VarDecl>(*DI); + VarDecl *V = dyn_cast<VarDecl>(*DI); if (!V) continue; @@ -253,7 +254,7 @@ public: if (V->getType()->getAs<ReferenceType>()) return; - if (Expr* E = V->getInit()) { + if (Expr *E = V->getInit()) { while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E)) E = exprClean->getSubExpr(); @@ -265,7 +266,7 @@ public: // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. - if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) { + if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) { // Special case: check for initializations with constants. // // e.g. : int x = 0; @@ -296,7 +297,9 @@ public: return; } - Report(V, DeadInit, V->getLocation(), E->getSourceRange()); + PathDiagnosticLocation Loc = + PathDiagnosticLocation::create(V, BR.getSourceManager()); + Report(V, DeadInit, Loc, E->getSourceRange()); } } } @@ -318,15 +321,15 @@ public: CFG& getCFG() { return *cfg; } - llvm::SmallPtrSet<VarDecl*, 20> Escaped; + llvm::SmallPtrSet<const VarDecl*, 20> Escaped; void VisitUnaryOperator(UnaryOperator* U) { // Check for '&'. Any VarDecl whose value has its address-taken we // treat as escaped. - Expr* E = U->getSubExpr()->IgnoreParenCasts(); + Expr *E = U->getSubExpr()->IgnoreParenCasts(); if (U->getOpcode() == UO_AddrOf) - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) { + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) + if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { Escaped.insert(VD); return; } @@ -345,13 +348,14 @@ class DeadStoresChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - if (LiveVariables *L = mgr.getLiveVariables(D)) { + if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) { CFG &cfg = *mgr.getCFG(D); + AnalysisContext *AC = mgr.getAnalysisContext(D); ParentMap &pmap = mgr.getParentMap(D); FindEscaped FS(&cfg); FS.getCFG().VisitBlockStmts(FS); - DeadStoreObs A(cfg, BR.getContext(), BR, pmap, FS.Escaped); - L->runOnAllBlocks(cfg, &A); + DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped); + L->runOnAllBlocks(A); } } }; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 486b7f7..d9d5694 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -28,7 +28,7 @@ class LiveVariablesDumper : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { - if (LiveVariables* L = mgr.getLiveVariables(D)) { + if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { L->dumpBlockLiveness(mgr.getSourceManager()); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index baaf8b3..eeda734 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -29,16 +29,17 @@ class DereferenceChecker mutable llvm::OwningPtr<BuiltinBug> BT_undef; public: - void checkLocation(SVal location, bool isLoad, CheckerContext &C) const; + void checkLocation(SVal location, bool isLoad, const Stmt* S, + CheckerContext &C) const; - static void AddDerefSource(llvm::raw_ostream &os, - llvm::SmallVectorImpl<SourceRange> &Ranges, + static void AddDerefSource(raw_ostream &os, + SmallVectorImpl<SourceRange> &Ranges, const Expr *Ex, bool loadedFrom = false); }; } // end anonymous namespace -void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, - llvm::SmallVectorImpl<SourceRange> &Ranges, +void DereferenceChecker::AddDerefSource(raw_ostream &os, + SmallVectorImpl<SourceRange> &Ranges, const Expr *Ex, bool loadedFrom) { Ex = Ex->IgnoreParenLValueCasts(); @@ -65,7 +66,7 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, } } -void DereferenceChecker::checkLocation(SVal l, bool isLoad, +void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, CheckerContext &C) const { // Check for dereference of an undefined value. if (l.isUndef()) { @@ -73,10 +74,10 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, if (!BT_undef) BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); + BugReport *report = + new BugReport(*BT_undef, BT_undef->getDescription(), N); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + bugreporter::GetDerefExpr(N))); C.EmitReport(report); } return; @@ -88,9 +89,8 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, if (!isa<Loc>(location)) return; - const Stmt *S = C.getStmt(); - const GRState *state = C.getState(); - const GRState *notNullState, *nullState; + const ProgramState *state = C.getState(); + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(location); // The explicit NULL case. @@ -107,7 +107,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, BT_null.reset(new BuiltinBug("Dereference of null pointer")); llvm::SmallString<100> buf; - llvm::SmallVector<SourceRange, 2> Ranges; + SmallVector<SourceRange, 2> Ranges; // Walk through lvalue casts to get the original expression // that syntactically caused the load. @@ -157,15 +157,15 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, break; } - EnhancedBugReport *report = - new EnhancedBugReport(*BT_null, + BugReport *report = + new BugReport(*BT_null, buf.empty() ? BT_null->getDescription():buf.str(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + bugreporter::GetDerefExpr(N))); - for (llvm::SmallVectorImpl<SourceRange>::iterator + for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 07fb5aa..75b7cc4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -52,7 +52,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, // Check for divide by zero. ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotZero, *stateZero; + const ProgramState *stateNotZero, *stateZero; llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV); if (stateZero && !stateNotZero) { @@ -60,11 +60,11 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, if (!BT) BT.reset(new BuiltinBug("Division by zero")); - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription(), N); + BugReport *R = + new BugReport(*BT, BT->getDescription(), N); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDenomExpr(N)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + bugreporter::GetDenomExpr(N))); C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index d699dee..531d87e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -44,7 +44,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, if (!T->isPointerType()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal RV = state->getSVal(B->getRHS()); @@ -57,7 +57,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, "Using a fixed address is not portable because that " "address will probably not be valid in all " "environments or platforms.")); - RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index b0c07fc..5c257e5 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -96,10 +96,9 @@ private: // Hash table and related data structures struct BinaryOperatorData { - BinaryOperatorData() : assumption(Possible), analysisContext(0) {} + BinaryOperatorData() : assumption(Possible) {} Assumption assumption; - AnalysisContext *analysisContext; ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a // BinaryOperator }; @@ -118,7 +117,6 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B, BinaryOperatorData &Data = hash[B]; Assumption &A = Data.assumption; AnalysisContext *AC = C.getCurrentAnalysisContext(); - Data.analysisContext = AC; // If we already have visited this node on a path that does not contain an // idempotent operation, return immediately. @@ -143,7 +141,7 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B, || containsNonLocalVarDecl(RHS); } - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal LHSVal = state->getSVal(LHS); SVal RHSVal = state->getSVal(RHS); @@ -351,9 +349,14 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, // Unpack the hash contents const BinaryOperatorData &Data = i->second; const Assumption &A = Data.assumption; - AnalysisContext *AC = Data.analysisContext; const ExplodedNodeSet &ES = Data.explodedNodes; + // If there are no nodes accosted with the expression, nothing to report. + // FIXME: This is possible because the checker does part of processing in + // checkPreStmt and part in checkPostStmt. + if (ES.begin() == ES.end()) + continue; + const BinaryOperator *B = i->first; if (A == Impossible) @@ -363,6 +366,8 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, // warning if (Eng.hasWorkRemaining()) { // If we can trace back + AnalysisContext *AC = (*ES.begin())->getLocationContext() + ->getAnalysisContext(); if (!pathWasCompletelyAnalyzed(AC, AC->getCFGStmtMap()->getBlock(B), Eng.getCoreEngine())) @@ -407,18 +412,18 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, // Add a report for each ExplodedNode for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) { - EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I); + BugReport *report = new BugReport(*BT, os.str(), *I); // Add source ranges and visitor hooks if (LHSRelevant) { const Expr *LHS = i->first->getLHS(); report->addRange(LHS->getSourceRange()); - report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS); + FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS); } if (RHSRelevant) { const Expr *RHS = i->first->getRHS(); report->addRange(i->first->getRHS()->getSourceRange()); - report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS); + FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS); } BR.EmitReport(report); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp index de6da4f..fbc57d3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp @@ -20,7 +20,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" @@ -117,16 +117,28 @@ public: CheckerContext &C) const; private: - const GRState *handleAssign(const GRState *state, const Expr *lexp, - const Expr *rexp, const LocationContext *LC) const; - const GRState *handleAssign(const GRState *state, const MemRegion *MR, - const Expr *rexp, const LocationContext *LC) const; - const GRState *invalidateIterators(const GRState *state, const MemRegion *MR, - const MemberExpr *ME) const; + const ProgramState *handleAssign(const ProgramState *state, + const Expr *lexp, + const Expr *rexp, + const LocationContext *LC) const; + + const ProgramState *handleAssign(const ProgramState *state, + const MemRegion *MR, + const Expr *rexp, + const LocationContext *LC) const; + + const ProgramState *invalidateIterators(const ProgramState *state, + const MemRegion *MR, + const MemberExpr *ME) const; + void checkExpr(CheckerContext &C, const Expr *E) const; + void checkArgs(CheckerContext &C, const CallExpr *CE) const; - const MemRegion *getRegion(const GRState *state, const Expr *E, - const LocationContext *LC) const; + + const MemRegion *getRegion(const ProgramState *state, + const Expr *E, + const LocationContext *LC) const; + const DeclRefExpr *getDeclRefExpr(const Expr *E) const; }; @@ -139,8 +151,8 @@ public: namespace clang { namespace ento { template <> - struct GRStateTrait<IteratorState> - : public GRStatePartialTrait<IteratorState::EntryMap> { + struct ProgramStateTrait<IteratorState> + : public ProgramStatePartialTrait<IteratorState::EntryMap> { static void *GDMIndex() { return IteratorsChecker::getTag(); } }; } @@ -162,7 +174,7 @@ static RefKind getTemplateKind(const NamedDecl *td) { || nameSpace->getName() != "std") return NoKind; - llvm::StringRef name = td->getName(); + StringRef name = td->getName(); return llvm::StringSwitch<RefKind>(name) .Cases("vector", "deque", VectorKind) .Default(NoKind); @@ -215,7 +227,7 @@ static RefKind getTemplateKind(QualType T) { // Iterate through our map and invalidate any iterators that were // initialized fromt the specified instance MemRegion. -const GRState *IteratorsChecker::invalidateIterators(const GRState *state, +const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *state, const MemRegion *MR, const MemberExpr *ME) const { IteratorState::EntryMap Map = state->get<IteratorState>(); if (Map.isEmpty()) @@ -234,7 +246,7 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state, } // Handle assigning to an iterator where we don't have the LValue MemRegion. -const GRState *IteratorsChecker::handleAssign(const GRState *state, +const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state, const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { // Skip the cast if present. if (const MaterializeTemporaryExpr *M @@ -259,7 +271,7 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state, } // handle assigning to an iterator -const GRState *IteratorsChecker::handleAssign(const GRState *state, +const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state, const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { // Assume unknown until we find something definite. state = state->set<IteratorState>(MR, RefState::getUnknown()); @@ -287,7 +299,7 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state, return state; // Finally, see if it is one of the calls that will create // a valid iterator and mark it if so, else mark as Unknown. - llvm::StringRef mName = ME->getMemberDecl()->getName(); + StringRef mName = ME->getMemberDecl()->getName(); if (llvm::StringSwitch<bool>(mName) .Cases("begin", "insert", "erase", true).Default(false)) { @@ -364,7 +376,7 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const { } // Get the MemRegion associated with the expresssion. -const MemRegion *IteratorsChecker::getRegion(const GRState *state, +const MemRegion *IteratorsChecker::getRegion(const ProgramState *state, const Expr *E, const LocationContext *LC) const { const DeclRefExpr *DRE = getDeclRefExpr(E); if (!DRE) @@ -382,7 +394,7 @@ const MemRegion *IteratorsChecker::getRegion(const GRState *state, // use those nodes. We also cannot create multiple nodes at one ProgramPoint // with the same tag. void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const MemRegion *MR = getRegion(state, E, C.getPredecessor()->getLocationContext()); if (!MR) @@ -410,7 +422,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const { "container to its container"; } - EnhancedBugReport *R = new EnhancedBugReport(*BT_Invalid, msg, N); + BugReport *R = new BugReport(*BT_Invalid, msg, N); R->addRange(getDeclRefExpr(E)->getSourceRange()); C.EmitReport(R); } @@ -422,7 +434,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const { const_cast<IteratorsChecker*>(this)->BT_Undefined = new BuiltinBug("Use of iterator that is not defined"); - EnhancedBugReport *R = new EnhancedBugReport(*BT_Undefined, + BugReport *R = new BugReport(*BT_Undefined, BT_Undefined->getDescription(), N); R->addRange(getDeclRefExpr(E)->getSourceRange()); C.EmitReport(R); @@ -455,7 +467,7 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, CheckerContext &C) const { const LocationContext *LC = C.getPredecessor()->getLocationContext(); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); OverloadedOperatorKind Kind = OCE->getOperator(); if (Kind == OO_Equal) { checkExpr(C, OCE->getArg(1)); @@ -491,8 +503,8 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, new BuiltinBug( "Cannot compare iterators from different containers"); - EnhancedBugReport *R = new EnhancedBugReport(*BT_Incompatible, - BT_Incompatible->getDescription(), N); + BugReport *R = new BugReport(*BT_Incompatible, + BT_Incompatible->getDescription(), N); R->addRange(OCE->getSourceRange()); C.EmitReport(R); } @@ -505,14 +517,14 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, // uninitialized ones as Undefined. void IteratorsChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { - const Decl* D = *DS->decl_begin(); - const VarDecl* VD = dyn_cast<VarDecl>(D); + const Decl *D = *DS->decl_begin(); + const VarDecl *VD = dyn_cast<VarDecl>(D); // Only care about iterators. if (getTemplateKind(VD->getType()) != VectorIteratorKind) return; // Get the MemRegion associated with the iterator and mark it as Undefined. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext()); const MemRegion *MR = VarLoc.getAsRegion(); if (!MR) @@ -520,7 +532,7 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS, state = state->set<IteratorState>(MR, RefState::getUndefined()); // if there is an initializer, handle marking Valid if a proper initializer - const Expr* InitEx = VD->getInit(); + const Expr *InitEx = VD->getInit(); if (InitEx) { // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first // it should resolve to an SVal that we can check for validity @@ -544,8 +556,8 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS, namespace { struct CalledReserved {}; } namespace clang { namespace ento { -template<> struct GRStateTrait<CalledReserved> - : public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { +template<> struct ProgramStateTrait<CalledReserved> + : public ProgramStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { static void *GDMIndex() { static int index = 0; return &index; } }; }} @@ -571,8 +583,8 @@ void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE, return; // If we are calling a function that invalidates iterators, mark them // appropriately by finding matching instances. - const GRState *state = C.getState(); - llvm::StringRef mName = ME->getMemberDecl()->getName(); + const ProgramState *state = C.getState(); + StringRef mName = ME->getMemberDecl()->getName(); if (llvm::StringSwitch<bool>(mName) .Cases("insert", "reserve", "push_back", true) .Cases("erase", "pop_back", "clear", "resize", true) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 3d1b5e2..e398fcb 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -32,13 +32,13 @@ static bool IsLLVMStringRef(QualType T) { if (!RT) return false; - return llvm::StringRef(QualType(RT, 0).getAsString()) == - "class llvm::StringRef"; + return StringRef(QualType(RT, 0).getAsString()) == + "class StringRef"; } /// Check whether the declaration is semantically inside the top-level /// namespace named by ns. -static bool InNamespace(const Decl *D, llvm::StringRef NS) { +static bool InNamespace(const Decl *D, StringRef NS) { const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()); if (!ND) return false; @@ -109,7 +109,7 @@ static bool IsSmallVector(QualType T) { } //===----------------------------------------------------------------------===// -// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose +// CHECK: a StringRef should not be bound to a temporary std::string whose // lifetime is shorter than the StringRef's. //===----------------------------------------------------------------------===// @@ -150,7 +150,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { return; // Pattern match for: - // llvm::StringRef x = call() (where call returns std::string) + // StringRef x = call() (where call returns std::string) if (!IsLLVMStringRef(VD->getType())) return; ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init); @@ -175,9 +175,10 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { // Okay, badness! Report an error. const char *desc = "StringRef should not be bound to temporary " "std::string that it outlives"; - + PathDiagnosticLocation VDLoc = + PathDiagnosticLocation::createBegin(VD, BR.getSourceManager()); BR.EmitBasicReport(desc, "LLVM Conventions", desc, - VD->getLocStart(), Init->getSourceRange()); + VDLoc, Init->getSourceRange()); } //===----------------------------------------------------------------------===// @@ -210,7 +211,7 @@ static bool IsPartOfAST(const CXXRecordDecl *R) { namespace { class ASTFieldVisitor { - llvm::SmallVector<FieldDecl*, 10> FieldChain; + SmallVector<FieldDecl*, 10> FieldChain; const CXXRecordDecl *Root; BugReporter &BR; public: @@ -260,7 +261,7 @@ void ASTFieldVisitor::ReportError(QualType T) { if (FieldChain.size() > 1) { os << " via the following chain: "; bool isFirst = true; - for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(), + for (SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(), E=FieldChain.end(); I!=E; ++I) { if (!isFirst) os << '.'; @@ -279,8 +280,10 @@ void ASTFieldVisitor::ReportError(QualType T) { // just report warnings when we see an out-of-line method definition for a // class, as that heuristic doesn't always work (the complete definition of // the class may be in the header file, for example). + PathDiagnosticLocation L = PathDiagnosticLocation::createBegin( + FieldChain.front(), BR.getSourceManager()); BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions", - os.str(), FieldChain.front()->getLocStart()); + os.str(), L); } //===----------------------------------------------------------------------===// @@ -294,7 +297,7 @@ class LLVMConventionsChecker : public Checker< public: void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr, BugReporter &BR) const { - if (R->isDefinition()) + if (R->isCompleteDefinition()) CheckASTMemory(R, BR); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp new file mode 100644 index 0000000..2607db8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -0,0 +1,632 @@ +//==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This checker flags misuses of KeyChainAPI. In particular, the password data +// allocated/returned by SecKeychainItemCopyContent, +// SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has +// to be freed using a call to SecKeychainItemFreeContent. +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" + +using namespace clang; +using namespace ento; + +namespace { +class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>, + check::PreStmt<ReturnStmt>, + check::PostStmt<CallExpr>, + check::EndPath, + check::DeadSymbols> { + mutable llvm::OwningPtr<BugType> BT; + +public: + /// AllocationState is a part of the checker specific state together with the + /// MemRegion corresponding to the allocated data. + struct AllocationState { + /// The index of the allocator function. + unsigned int AllocatorIdx; + SymbolRef Region; + + AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) : + AllocatorIdx(Idx), + Region(R) {} + + bool operator==(const AllocationState &X) const { + return (AllocatorIdx == X.AllocatorIdx && + Region == X.Region); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(AllocatorIdx); + ID.AddPointer(Region); + } + }; + + void checkPreStmt(const CallExpr *S, CheckerContext &C) const; + void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; + void checkPostStmt(const CallExpr *S, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; + void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + +private: + typedef std::pair<SymbolRef, const AllocationState*> AllocationPair; + typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec; + + enum APIKind { + /// Denotes functions tracked by this checker. + ValidAPI = 0, + /// The functions commonly/mistakenly used in place of the given API. + ErrorAPI = 1, + /// The functions which may allocate the data. These are tracked to reduce + /// the false alarm rate. + PossibleAPI = 2 + }; + /// Stores the information about the allocator and deallocator functions - + /// these are the functions the checker is tracking. + struct ADFunctionInfo { + const char* Name; + unsigned int Param; + unsigned int DeallocatorIdx; + APIKind Kind; + }; + static const unsigned InvalidIdx = 100000; + static const unsigned FunctionsToTrackSize = 8; + static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize]; + /// The value, which represents no error return value for allocator functions. + static const unsigned NoErr = 0; + + /// Given the function name, returns the index of the allocator/deallocator + /// function. + static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator); + + inline void initBugType() const { + if (!BT) + BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API")); + } + + void generateDeallocatorMismatchReport(const AllocationPair &AP, + const Expr *ArgExpr, + CheckerContext &C) const; + + BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP, + ExplodedNode *N) const; + + /// Check if RetSym evaluates to an error value in the current state. + bool definitelyReturnedError(SymbolRef RetSym, + const ProgramState *State, + SValBuilder &Builder, + bool noError = false) const; + + /// Check if RetSym evaluates to a NoErr value in the current state. + bool definitelyDidnotReturnError(SymbolRef RetSym, + const ProgramState *State, + SValBuilder &Builder) const { + return definitelyReturnedError(RetSym, State, Builder, true); + } + + /// The bug visitor which allows us to print extra diagnostics along the + /// BugReport path. For example, showing the allocation site of the leaked + /// region. + class SecKeychainBugVisitor : public BugReporterVisitor { + protected: + // The allocated region symbol tracked by the main analysis. + SymbolRef Sym; + + public: + SecKeychainBugVisitor(SymbolRef S) : Sym(S) {} + virtual ~SecKeychainBugVisitor() {} + + void Profile(llvm::FoldingSetNodeID &ID) const { + static int X = 0; + ID.AddPointer(&X); + ID.AddPointer(Sym); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); + }; +}; +} + +/// ProgramState traits to store the currently allocated (and not yet freed) +/// symbols. This is a map from the allocated content symbol to the +/// corresponding AllocationState. +typedef llvm::ImmutableMap<SymbolRef, + MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy; + +namespace { struct AllocatedData {}; } +namespace clang { namespace ento { +template<> struct ProgramStateTrait<AllocatedData> + : public ProgramStatePartialTrait<AllocatedSetTy > { + static void *GDMIndex() { static int index = 0; return &index; } +}; +}} + +static bool isEnclosingFunctionParam(const Expr *E) { + E = E->IgnoreParenCasts(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + const ValueDecl *VD = DRE->getDecl(); + if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD)) + return true; + } + return false; +} + +const MacOSKeychainAPIChecker::ADFunctionInfo + MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = { + {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0 + {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1 + {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2 + {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3 + {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4 + {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5 + {"free", 0, InvalidIdx, ErrorAPI}, // 6 + {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7 +}; + +unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, + bool IsAllocator) { + for (unsigned I = 0; I < FunctionsToTrackSize; ++I) { + ADFunctionInfo FI = FunctionsToTrack[I]; + if (FI.Name != Name) + continue; + // Make sure the function is of the right type (allocator vs deallocator). + if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx)) + return InvalidIdx; + if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx)) + return InvalidIdx; + + return I; + } + // The function is not tracked. + return InvalidIdx; +} + +static SymbolRef getSymbolForRegion(CheckerContext &C, + const MemRegion *R) { + // Implicit casts (ex: void* -> char*) can turn Symbolic region into element + // region, if that is the case, get the underlining region. + R = R->StripCasts(); + if (!isa<SymbolicRegion>(R)) { + return 0; + } + return cast<SymbolicRegion>(R)->getSymbol(); +} + +static bool isBadDeallocationArgument(const MemRegion *Arg) { + if (isa<AllocaRegion>(Arg) || + isa<BlockDataRegion>(Arg) || + isa<TypedRegion>(Arg)) { + return true; + } + return false; +} +/// Given the address expression, retrieve the value it's pointing to. Assume +/// that value is itself an address, and return the corresponding symbol. +static SymbolRef getAsPointeeSymbol(const Expr *Expr, + CheckerContext &C) { + const ProgramState *State = C.getState(); + SVal ArgV = State->getSVal(Expr); + + if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) { + StoreManager& SM = C.getStoreManager(); + const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion(); + if (V) + return getSymbolForRegion(C, V); + } + return 0; +} + +// When checking for error code, we need to consider the following cases: +// 1) noErr / [0] +// 2) someErr / [1, inf] +// 3) unknown +// If noError, returns true iff (1). +// If !noError, returns true iff (2). +bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym, + const ProgramState *State, + SValBuilder &Builder, + bool noError) const { + DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr, + Builder.getSymbolManager().getType(RetSym)); + DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal, + nonloc::SymbolVal(RetSym)); + const ProgramState *ErrState = State->assume(NoErr, noError); + if (ErrState == State) { + return true; + } + + return false; +} + +// Report deallocator mismatch. Remove the region from tracking - reporting a +// missing free error after this one is redundant. +void MacOSKeychainAPIChecker:: + generateDeallocatorMismatchReport(const AllocationPair &AP, + const Expr *ArgExpr, + CheckerContext &C) const { + const ProgramState *State = C.getState(); + State = State->remove<AllocatedData>(AP.first); + ExplodedNode *N = C.generateNode(State); + + if (!N) + return; + initBugType(); + llvm::SmallString<80> sbuf; + llvm::raw_svector_ostream os(sbuf); + unsigned int PDeallocIdx = + FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx; + + os << "Deallocator doesn't match the allocator: '" + << FunctionsToTrack[PDeallocIdx].Name << "' should be used."; + BugReport *Report = new BugReport(*BT, os.str(), N); + Report->addVisitor(new SecKeychainBugVisitor(AP.first)); + Report->addRange(ArgExpr->getSourceRange()); + C.EmitReport(Report); +} + +void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const { + const ProgramState *State = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = State->getSVal(Callee); + unsigned idx = InvalidIdx; + + const FunctionDecl *funDecl = L.getAsFunctionDecl(); + if (!funDecl) + return; + IdentifierInfo *funI = funDecl->getIdentifier(); + if (!funI) + return; + StringRef funName = funI->getName(); + + // If it is a call to an allocator function, it could be a double allocation. + idx = getTrackedFunctionIndex(funName, true); + if (idx != InvalidIdx) { + const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); + if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) + if (const AllocationState *AS = State->get<AllocatedData>(V)) { + if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) { + // Remove the value from the state. The new symbol will be added for + // tracking when the second allocator is processed in checkPostStmt(). + State = State->remove<AllocatedData>(V); + ExplodedNode *N = C.generateNode(State); + if (!N) + return; + initBugType(); + llvm::SmallString<128> sbuf; + llvm::raw_svector_ostream os(sbuf); + unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; + os << "Allocated data should be released before another call to " + << "the allocator: missing a call to '" + << FunctionsToTrack[DIdx].Name + << "'."; + BugReport *Report = new BugReport(*BT, os.str(), N); + Report->addVisitor(new SecKeychainBugVisitor(V)); + Report->addRange(ArgExpr->getSourceRange()); + C.EmitReport(Report); + } + } + return; + } + + // Is it a call to one of deallocator functions? + idx = getTrackedFunctionIndex(funName, false); + if (idx == InvalidIdx) + return; + + // Check the argument to the deallocator. + const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); + SVal ArgSVal = State->getSVal(ArgExpr); + + // Undef is reported by another checker. + if (ArgSVal.isUndef()) + return; + + const MemRegion *Arg = ArgSVal.getAsRegion(); + if (!Arg) + return; + + SymbolRef ArgSM = getSymbolForRegion(C, Arg); + bool RegionArgIsBad = ArgSM ? false : isBadDeallocationArgument(Arg); + // If the argument is coming from the heap, globals, or unknown, do not + // report it. + if (!ArgSM && !RegionArgIsBad) + return; + + // Is the argument to the call being tracked? + const AllocationState *AS = State->get<AllocatedData>(ArgSM); + if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) { + return; + } + // If trying to free data which has not been allocated yet, report as a bug. + // TODO: We might want a more precise diagnostic for double free + // (that would involve tracking all the freed symbols in the checker state). + if (!AS || RegionArgIsBad) { + // It is possible that this is a false positive - the argument might + // have entered as an enclosing function parameter. + if (isEnclosingFunctionParam(ArgExpr)) + return; + + ExplodedNode *N = C.generateNode(State); + if (!N) + return; + initBugType(); + BugReport *Report = new BugReport(*BT, + "Trying to free data which has not been allocated.", N); + Report->addRange(ArgExpr->getSourceRange()); + C.EmitReport(Report); + return; + } + + // Process functions which might deallocate. + if (FunctionsToTrack[idx].Kind == PossibleAPI) { + + if (funName == "CFStringCreateWithBytesNoCopy") { + const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts(); + // NULL ~ default deallocator, so warn. + if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(), + Expr::NPC_ValueDependentIsNotNull)) { + const AllocationPair AP = std::make_pair(ArgSM, AS); + generateDeallocatorMismatchReport(AP, ArgExpr, C); + return; + } + // One of the default allocators, so warn. + if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) { + StringRef DeallocatorName = DE->getFoundDecl()->getName(); + if (DeallocatorName == "kCFAllocatorDefault" || + DeallocatorName == "kCFAllocatorSystemDefault" || + DeallocatorName == "kCFAllocatorMalloc") { + const AllocationPair AP = std::make_pair(ArgSM, AS); + generateDeallocatorMismatchReport(AP, ArgExpr, C); + return; + } + // If kCFAllocatorNull, which does not deallocate, we still have to + // find the deallocator. Otherwise, assume that the user had written a + // custom deallocator which does the right thing. + if (DE->getFoundDecl()->getName() != "kCFAllocatorNull") { + State = State->remove<AllocatedData>(ArgSM); + C.addTransition(State); + return; + } + } + } + return; + } + + // The call is deallocating a value we previously allocated, so remove it + // from the next state. + State = State->remove<AllocatedData>(ArgSM); + + // Check if the proper deallocator is used. + unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; + if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) { + const AllocationPair AP = std::make_pair(ArgSM, AS); + generateDeallocatorMismatchReport(AP, ArgExpr, C); + return; + } + + // If the return status is undefined or is error, report a bad call to free. + if (!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) { + ExplodedNode *N = C.generateNode(State); + if (!N) + return; + initBugType(); + BugReport *Report = new BugReport(*BT, + "Call to free data when error was returned during allocation.", N); + Report->addVisitor(new SecKeychainBugVisitor(ArgSM)); + Report->addRange(ArgExpr->getSourceRange()); + C.EmitReport(Report); + return; + } + + C.addTransition(State); +} + +void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, + CheckerContext &C) const { + const ProgramState *State = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = State->getSVal(Callee); + + const FunctionDecl *funDecl = L.getAsFunctionDecl(); + if (!funDecl) + return; + IdentifierInfo *funI = funDecl->getIdentifier(); + if (!funI) + return; + StringRef funName = funI->getName(); + + // If a value has been allocated, add it to the set for tracking. + unsigned idx = getTrackedFunctionIndex(funName, true); + if (idx == InvalidIdx) + return; + + const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); + // If the argument entered as an enclosing function parameter, skip it to + // avoid false positives. + if (isEnclosingFunctionParam(ArgExpr)) + return; + + if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { + // If the argument points to something that's not a symbolic region, it + // can be: + // - unknown (cannot reason about it) + // - undefined (already reported by other checker) + // - constant (null - should not be tracked, + // other constant will generate a compiler warning) + // - goto (should be reported by other checker) + + // The call return value symbol should stay alive for as long as the + // allocated value symbol, since our diagnostics depend on the value + // returned by the call. Ex: Data should only be freed if noErr was + // returned during allocation.) + SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol(); + C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); + + // Track the allocated value in the checker state. + State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, + RetStatusSymbol)); + assert(State); + C.addTransition(State); + } +} + +void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S, + CheckerContext &C) const { + const Expr *retExpr = S->getRetValue(); + if (!retExpr) + return; + + // Check if the value is escaping through the return. + const ProgramState *state = C.getState(); + const MemRegion *V = state->getSVal(retExpr).getAsRegion(); + if (!V) + return; + state = state->remove<AllocatedData>(getSymbolForRegion(C, V)); + + // Proceed from the new state. + C.addTransition(state); +} + +BugReport *MacOSKeychainAPIChecker:: + generateAllocatedDataNotReleasedReport(const AllocationPair &AP, + ExplodedNode *N) const { + const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx]; + initBugType(); + llvm::SmallString<70> sbuf; + llvm::raw_svector_ostream os(sbuf); + + os << "Allocated data is not released: missing a call to '" + << FunctionsToTrack[FI.DeallocatorIdx].Name << "'."; + BugReport *Report = new BugReport(*BT, os.str(), N); + Report->addVisitor(new SecKeychainBugVisitor(AP.first)); + Report->addRange(SourceRange()); + return Report; +} + +void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, + CheckerContext &C) const { + const ProgramState *State = C.getState(); + AllocatedSetTy ASet = State->get<AllocatedData>(); + if (ASet.isEmpty()) + return; + + bool Changed = false; + AllocationPairVec Errors; + for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { + if (SR.isLive(I->first)) + continue; + + Changed = true; + State = State->remove<AllocatedData>(I->first); + // If the allocated symbol is null or if the allocation call might have + // returned an error, do not report. + if (State->getSymVal(I->first) || + definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) + continue; + Errors.push_back(std::make_pair(I->first, &I->second)); + } + if (!Changed) + return; + + // Generate the new, cleaned up state. + ExplodedNode *N = C.generateNode(State); + if (!N) + return; + + // Generate the error reports. + for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); + I != E; ++I) { + C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N)); + } +} + +// TODO: Remove this after we ensure that checkDeadSymbols are always called. +void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B, + ExprEngine &Eng) const { + const ProgramState *state = B.getState(); + AllocatedSetTy AS = state->get<AllocatedData>(); + if (AS.isEmpty()) + return; + + // Anything which has been allocated but not freed (nor escaped) will be + // found here, so report it. + bool Changed = false; + AllocationPairVec Errors; + for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) { + Changed = true; + state = state->remove<AllocatedData>(I->first); + // If the allocated symbol is null or if error code was returned at + // allocation, do not report. + if (state->getSymVal(I.getKey()) || + definitelyReturnedError(I->second.Region, state, + Eng.getSValBuilder())) { + continue; + } + Errors.push_back(std::make_pair(I->first, &I->second)); + } + + // If no change, do not generate a new state. + if (!Changed) + return; + + ExplodedNode *N = B.generateNode(state); + if (!N) + return; + + // Generate the error reports. + for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); + I != E; ++I) { + Eng.getBugReporter().EmitReport( + generateAllocatedDataNotReleasedReport(*I, N)); + } +} + + +PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode( + const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + const AllocationState *AS = N->getState()->get<AllocatedData>(Sym); + if (!AS) + return 0; + const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym); + if (ASPrev) + return 0; + + // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the + // allocation site. + const CallExpr *CE = cast<CallExpr>(cast<StmtPoint>(N->getLocation()) + .getStmt()); + const FunctionDecl *funDecl = CE->getDirectCallee(); + assert(funDecl && "We do not support indirect function calls as of now."); + StringRef funName = funDecl->getName(); + + // Get the expression of the corresponding argument. + unsigned Idx = getTrackedFunctionIndex(funName, true); + assert(Idx != InvalidIdx && "This should be a call to an allocator."); + const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param); + PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(), + N->getLocationContext()); + return new PathDiagnosticEventPiece(Pos, "Data is allocated here."); +} + +void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) { + mgr.registerChecker<MacOSKeychainAPIChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index f8d076b..88d492e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -20,7 +20,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -56,7 +56,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, // Check if the first argument is stack allocated. If so, issue a warning // because that's likely to be bad news. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; @@ -81,7 +81,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) os << " Perhaps you intended to declare the variable as 'static'?"; - RangedBugReport *report = new RangedBugReport(*BT_dispatchOnce, os.str(), N); + BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); C.EmitReport(report); } @@ -94,7 +94,7 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { // FIXME: This sort of logic is common to several checkers, including // UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Makefile b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Makefile deleted file mode 100644 index 97f4642..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements analyses built on top of source-level CFGs. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangStaticAnalyzerCheckers - -BUILT_SOURCES = Checkers.inc -TABLEGEN_INC_FILES_COMMON = 1 - -include $(CLANG_LEVEL)/Makefile - -$(ObjDir)/Checkers.inc.tmp : Checkers.td $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include/clang/StaticAnalyzer/Checkers/CheckerBase.td $(TBLGEN) $(ObjDir)/.dir - $(Echo) "Building Clang SA Checkers tables with tblgen" - $(Verb) $(TableGen) -gen-clang-sa-checkers -I $(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -o $(call SYSPATH, $@) $< diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 9100215..5631802 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -17,8 +17,8 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -80,35 +80,37 @@ public: void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; - const GRState *evalAssume(const GRState *state, SVal Cond, + const ProgramState *evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const; - void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; - void checkBind(SVal location, SVal val, CheckerContext &C) const; + void checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const; + void checkBind(SVal location, SVal val, const Stmt*S, + CheckerContext &C) const; private: static void MallocMem(CheckerContext &C, const CallExpr *CE); static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att); - static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, - const GRState *state) { + const ProgramState *state) { return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state); } - static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal SizeEx, SVal Init, - const GRState *state); + const ProgramState *state); void FreeMem(CheckerContext &C, const CallExpr *CE) const; void FreeMemAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att) const; - const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state, unsigned Num, bool Hold) const; + const ProgramState *FreeMemAux(CheckerContext &C, const CallExpr *CE, + const ProgramState *state, unsigned Num, bool Hold) const; void ReallocMem(CheckerContext &C, const CallExpr *CE) const; static void CallocMem(CheckerContext &C, const CallExpr *CE); - static bool SummarizeValue(llvm::raw_ostream& os, SVal V); - static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR); + static bool SummarizeValue(raw_ostream &os, SVal V); + static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; }; } // end anonymous namespace @@ -118,15 +120,15 @@ typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy; namespace clang { namespace ento { template <> - struct GRStateTrait<RegionState> - : public GRStatePartialTrait<RegionStateTy> { + struct ProgramStateTrait<RegionState> + : public ProgramStatePartialTrait<RegionStateTy> { static void *GDMIndex() { static int x; return &x; } }; } } bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -193,7 +195,7 @@ bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), + const ProgramState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), C.getState()); C.addTransition(state); } @@ -205,21 +207,21 @@ void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); if (I != E) { - const GRState *state = + const ProgramState *state = MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState()); C.addTransition(state); return; } - const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), + const ProgramState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState()); C.addTransition(state); } -const GRState *MallocChecker::MallocMemAux(CheckerContext &C, +const ProgramState *MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal Size, SVal Init, - const GRState *state) { - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + const ProgramState *state) { + unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); // Set the return value. @@ -247,7 +249,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false); + const ProgramState *state = FreeMemAux(C, CE, C.getState(), 0, false); if (state) C.addTransition(state); @@ -260,15 +262,15 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); I != E; ++I) { - const GRState *state = FreeMemAux(C, CE, C.getState(), *I, + const ProgramState *state = FreeMemAux(C, CE, C.getState(), *I, Att->getOwnKind() == OwnershipAttr::Holds); if (state) C.addTransition(state); } } -const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state, unsigned Num, +const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, + const ProgramState *state, unsigned Num, bool Hold) const { const Expr *ArgExpr = CE->getArg(Num); SVal ArgVal = state->getSVal(ArgExpr); @@ -281,7 +283,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, // FIXME: Technically using 'Assume' here can result in a path // bifurcation. In such cases we need to return two states, not just one. - const GRState *notNullState, *nullState; + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(location); // The explicit NULL case, no operation is performed. @@ -364,7 +366,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, return notNullState->set<RegionState>(Sym, RefState::getReleased(CE)); } -bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) { +bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V)) os << "an integer (" << IntVal->getValue() << ")"; else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V)) @@ -377,13 +379,13 @@ bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) { return true; } -bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os, +bool MallocChecker::SummarizeRegion(raw_ostream &os, const MemRegion *MR) { switch (MR->getKind()) { case MemRegion::FunctionTextRegionKind: { const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); if (FD) - os << "the address of the function '" << FD << "'"; + os << "the address of the function '" << *FD << '\''; else os << "the address of a function"; return true; @@ -484,14 +486,14 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, os << "not memory allocated by malloc()"; } - EnhancedBugReport *R = new EnhancedBugReport(*BT_BadFree, os.str(), N); + BugReport *R = new BugReport(*BT_BadFree, os.str(), N); R->addRange(range); C.EmitReport(R); } } void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *arg0Expr = CE->getArg(0); DefinedOrUnknownSVal arg0Val = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr)); @@ -517,7 +519,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { // If the ptr is NULL and the size is not 0, the call is equivalent to // malloc(size). - const GRState *stateEqual = state->assume(PtrEQ, true); + const ProgramState *stateEqual = state->assume(PtrEQ, true); if (stateEqual && state->assume(SizeZero, false)) { // Hack: set the NULL symbolic region to released to suppress false warning. // In the future we should add more states for allocated regions, e.g., @@ -527,28 +529,25 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { if (Sym) stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE)); - const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), + const ProgramState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), stateEqual); C.addTransition(stateMalloc); } - if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) { + if (const ProgramState *stateNotEqual = state->assume(PtrEQ, false)) { // If the size is 0, free the memory. - if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) - if (const GRState *stateFree = + if (const ProgramState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) + if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false)) { - // Add the state transition to set input pointer argument to be free. - C.addTransition(stateFree); - - // Bind the return value to UndefinedVal because it is now free. - C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + // Bind the return value to NULL because it is now free. + C.addTransition(stateFree->BindExpr(CE, svalBuilder.makeNull(), true)); } - if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) - if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, + if (const ProgramState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) + if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false)) { // FIXME: We should copy the content of the original buffer. - const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), + const ProgramState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), UnknownVal(), stateFree); C.addTransition(stateRealloc); } @@ -556,7 +555,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { } void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); SVal count = state->getSVal(CE->getArg(0)); @@ -574,33 +573,40 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, if (!SymReaper.hasDeadSymbols()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); RegionStateTy RS = state->get<RegionState>(); RegionStateTy::Factory &F = state->get_context<RegionState>(); + bool generateReport = false; + for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { if (SymReaper.isDead(I->first)) { - if (I->second.isAllocated()) { - if (ExplodedNode *N = C.generateNode()) { - if (!BT_Leak) - BT_Leak.reset(new BuiltinBug("Memory leak", - "Allocated memory never released. Potential memory leak.")); - // FIXME: where it is allocated. - BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); - C.EmitReport(R); - } - } + if (I->second.isAllocated()) + generateReport = true; // Remove the dead symbol from the map. RS = F.remove(RS, I->first); + } } - C.generateNode(state->set<RegionState>(RS)); + + ExplodedNode *N = C.generateNode(state->set<RegionState>(RS)); + + // FIXME: This does not handle when we have multiple leaks at a single + // place. + if (N && generateReport) { + if (!BT_Leak) + BT_Leak.reset(new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak.")); + // FIXME: where it is allocated. + BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); + C.EmitReport(R); + } } void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const { - const GRState *state = B.getState(); + const ProgramState *state = B.getState(); RegionStateTy M = state->get<RegionState>(); for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { @@ -623,7 +629,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { if (!retExpr) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SymbolRef Sym = state->getSVal(retExpr).getAsSymbol(); if (!Sym) @@ -640,7 +646,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { C.addTransition(state); } -const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, +const ProgramState *MallocChecker::evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const { // If a symblic region is assumed to NULL, set its state to AllocateFailed. // FIXME: should also check symbols assumed to non-null. @@ -657,7 +663,8 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, } // Check if the location is a freed symbolic region. -void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { +void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const { SymbolRef Sym = l.getLocSymbolInBase(); if (Sym) { const RefState *RS = C.getState()->get<RegionState>(Sym); @@ -675,13 +682,14 @@ void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { } } -void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { +void MallocChecker::checkBind(SVal location, SVal val, + const Stmt *BindS, CheckerContext &C) const { // The PreVisitBind implements the same algorithm as already used by the // Objective C ownership checker: if the pointer escaped from this scope by // assignment, let it go. However, assigning to fields of a stack-storage // structure does not transfer ownership. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location); // Check for null dereferences. @@ -694,7 +702,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { if (Sym) { if (const RefState *RS = state->get<RegionState>(Sym)) { // If ptr is NULL, no operation is performed. - const GRState *notNullState, *nullState; + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(l); // Generate a transition for 'nullState' to record the assumption @@ -724,7 +732,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { // We no longer own this pointer. notNullState = notNullState->set<RegionState>(Sym, - RefState::getRelinquished(C.getStmt())); + RefState::getRelinquished(BindS)); } while (false); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp new file mode 100644 index 0000000..cf5501a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -0,0 +1,268 @@ +// MallocOverflowSecurityChecker.cpp - Check for malloc overflows -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker detects a common memory allocation security flaw. +// Suppose 'unsigned int n' comes from an untrusted source. If the +// code looks like 'malloc (n * 4)', and an attacker can make 'n' be +// say MAX_UINT/4+2, then instead of allocating the correct 'n' 4-byte +// elements, this will actually allocate only two because of overflow. +// Then when the rest of the program attempts to store values past the +// second element, these values will actually overwrite other items in +// the heap, probably allowing the attacker to execute arbitrary code. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "llvm/ADT/SmallVector.h" + +using namespace clang; +using namespace ento; + +namespace { +struct MallocOverflowCheck { + const BinaryOperator *mulop; + const Expr *variable; + + MallocOverflowCheck (const BinaryOperator *m, const Expr *v) + : mulop(m), variable (v) + {} +}; + +class MallocOverflowSecurityChecker : public Checker<check::ASTCodeBody> { +public: + void checkASTCodeBody(const Decl *D, AnalysisManager &mgr, + BugReporter &BR) const; + + void CheckMallocArgument( + llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, + const Expr *TheArgument, ASTContext &Context) const; + + void OutputPossibleOverflows( + llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, + const Decl *D, BugReporter &BR, AnalysisManager &mgr) const; + +}; +} // end anonymous namespace + +void MallocOverflowSecurityChecker::CheckMallocArgument( + llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, + const Expr *TheArgument, + ASTContext &Context) const { + + /* Look for a linear combination with a single variable, and at least + one multiplication. + Reject anything that applies to the variable: an explicit cast, + conditional expression, an operation that could reduce the range + of the result, or anything too complicated :-). */ + const Expr * e = TheArgument; + const BinaryOperator * mulop = NULL; + + for (;;) { + e = e->IgnoreParenImpCasts(); + if (isa<BinaryOperator>(e)) { + const BinaryOperator * binop = dyn_cast<BinaryOperator>(e); + BinaryOperatorKind opc = binop->getOpcode(); + // TODO: ignore multiplications by 1, reject if multiplied by 0. + if (mulop == NULL && opc == BO_Mul) + mulop = binop; + if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl) + return; + + const Expr *lhs = binop->getLHS(); + const Expr *rhs = binop->getRHS(); + if (rhs->isEvaluatable(Context)) + e = lhs; + else if ((opc == BO_Add || opc == BO_Mul) + && lhs->isEvaluatable(Context)) + e = rhs; + else + return; + } + else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e)) + break; + else + return; + } + + if (mulop == NULL) + return; + + // We've found the right structure of malloc argument, now save + // the data so when the body of the function is completely available + // we can check for comparisons. + + // TODO: Could push this into the innermost scope where 'e' is + // defined, rather than the whole function. + PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e)); +} + +namespace { +// A worker class for OutputPossibleOverflows. +class CheckOverflowOps : + public EvaluatedExprVisitor<CheckOverflowOps> { +public: + typedef llvm::SmallVectorImpl<MallocOverflowCheck> theVecType; + +private: + theVecType &toScanFor; + ASTContext &Context; + + bool isIntZeroExpr(const Expr *E) const { + if (!E->getType()->isIntegralOrEnumerationType()) + return false; + llvm::APSInt Result; + if (E->EvaluateAsInt(Result, Context)) + return Result == 0; + return false; + } + + void CheckExpr(const Expr *E_p) { + const Expr *E = E_p->IgnoreParenImpCasts(); + + theVecType::iterator i = toScanFor.end(); + theVecType::iterator e = toScanFor.begin(); + + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { + const Decl * EdreD = DR->getDecl(); + while (i != e) { + --i; + if (const DeclRefExpr *DR_i = dyn_cast<DeclRefExpr>(i->variable)) { + if (DR_i->getDecl() == EdreD) + i = toScanFor.erase(i); + } + } + } + else if (isa<MemberExpr>(E)) { + // No points-to analysis, just look at the member + const Decl * EmeMD = dyn_cast<MemberExpr>(E)->getMemberDecl(); + while (i != e) { + --i; + if (isa<MemberExpr>(i->variable)) { + if (dyn_cast<MemberExpr>(i->variable)->getMemberDecl() == EmeMD) + i = toScanFor.erase (i); + } + } + } + } + + public: + void VisitBinaryOperator(BinaryOperator *E) { + if (E->isComparisonOp()) { + const Expr * lhs = E->getLHS(); + const Expr * rhs = E->getRHS(); + // Ignore comparisons against zero, since they generally don't + // protect against an overflow. + if (!isIntZeroExpr(lhs) && ! isIntZeroExpr(rhs)) { + CheckExpr(lhs); + CheckExpr(rhs); + } + } + EvaluatedExprVisitor<CheckOverflowOps>::VisitBinaryOperator(E); + } + + /* We specifically ignore loop conditions, because they're typically + not error checks. */ + void VisitWhileStmt(WhileStmt *S) { + return this->Visit(S->getBody()); + } + void VisitForStmt(ForStmt *S) { + return this->Visit(S->getBody()); + } + void VisitDoStmt(DoStmt *S) { + return this->Visit(S->getBody()); + } + + CheckOverflowOps(theVecType &v, ASTContext &ctx) + : EvaluatedExprVisitor<CheckOverflowOps>(ctx), + toScanFor(v), Context(ctx) + { } + }; +} + +// OutputPossibleOverflows - We've found a possible overflow earlier, +// now check whether Body might contain a comparison which might be +// preventing the overflow. +// This doesn't do flow analysis, range analysis, or points-to analysis; it's +// just a dumb "is there a comparison" scan. The aim here is to +// detect the most blatent cases of overflow and educate the +// programmer. +void MallocOverflowSecurityChecker::OutputPossibleOverflows( + llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, + const Decl *D, BugReporter &BR, AnalysisManager &mgr) const { + // By far the most common case: nothing to check. + if (PossibleMallocOverflows.empty()) + return; + + // Delete any possible overflows which have a comparison. + CheckOverflowOps c(PossibleMallocOverflows, BR.getContext()); + c.Visit(mgr.getAnalysisContext(D)->getBody()); + + // Output warnings for all overflows that are left. + for (CheckOverflowOps::theVecType::iterator + i = PossibleMallocOverflows.begin(), + e = PossibleMallocOverflows.end(); + i != e; + ++i) { + SourceRange R = i->mulop->getSourceRange(); + BR.EmitBasicReport("MallocOverflowSecurityChecker", + "the computation of the size of the memory allocation may overflow", + PathDiagnosticLocation::createOperatorLoc(i->mulop, + BR.getSourceManager()), + &R, 1); + } +} + +void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, + AnalysisManager &mgr, + BugReporter &BR) const { + + CFG *cfg = mgr.getCFG(D); + if (!cfg) + return; + + // A list of variables referenced in possibly overflowing malloc operands. + llvm::SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows; + + for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { + CFGBlock *block = *it; + for (CFGBlock::iterator bi = block->begin(), be = block->end(); + bi != be; ++bi) { + if (const CFGStmt *CS = bi->getAs<CFGStmt>()) { + if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) { + // Get the callee. + const FunctionDecl *FD = TheCall->getDirectCallee(); + + if (!FD) + return; + + // Get the name of the callee. If it's a builtin, strip off the prefix. + IdentifierInfo *FnInfo = FD->getIdentifier(); + if (!FnInfo) + return; + + if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) { + if (TheCall->getNumArgs() == 1) + CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0), + mgr.getASTContext()); + } + } + } + } + } + + OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr); +} + +void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { + mgr.registerChecker<MallocOverflowSecurityChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index f11db64..7f74a7d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -9,7 +9,7 @@ // // This file defines a NSAutoreleasePoolChecker, a small checker that warns // about subpar uses of NSAutoreleasePool. Note that while the check itself -// (in it's current form) could be written as a flow-insensitive check, in +// (in its current form) could be written as a flow-insensitive check, in // can be potentially enhanced in the future with flow-sensitive information. // It is also a good example of the CheckerVisitor interface. // @@ -18,9 +18,10 @@ #include "ClangSACheckers.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" @@ -53,7 +54,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg, if (!PT) return; - const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); + const ObjCInterfaceDecl *OD = PT->getInterfaceDecl(); if (!OD) return; if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) @@ -66,14 +67,18 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg, return; SourceRange R = msg.getSourceRange(); - + BugReporter &BR = C.getBugReporter(); + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + const SourceManager &SM = BR.getSourceManager(); + const Expr *E = msg.getMsgOrPropExpr(); + PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(E, SM, LC); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " - "and garbage collection", R.getBegin(), &R, 1); + "and garbage collection", L, &R, 1); } void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) { - if (mgr.getLangOptions().getGCMode() != LangOptions::NonGC) + if (mgr.getLangOptions().getGC() != LangOptions::NonGC) mgr.registerChecker<NSAutoreleasePoolChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index a51d8e0..5678998 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -19,7 +19,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" @@ -60,7 +60,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, II = &D->getASTContext().Idents.get("NSError"); bool hasNSError = false; - for (ObjCMethodDecl::param_iterator + for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) { if (IsNSError((*I)->getType(), II)) { hasNSError = true; @@ -72,8 +72,10 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, const char *err = "Method accepting NSError** " "should have a non-void return value to indicate whether or not an " "error occurred"; + PathDiagnosticLocation L = + PathDiagnosticLocation::create(D, BR.getSourceManager()); BR.EmitBasicReport("Bad return type when passing NSError**", - "Coding conventions (Apple)", err, D->getLocation()); + "Coding conventions (Apple)", err, L); } } @@ -118,8 +120,10 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, const char *err = "Function accepting CFErrorRef* " "should have a non-void return value to indicate whether or not an " "error occurred"; + PathDiagnosticLocation L = + PathDiagnosticLocation::create(D, BR.getSourceManager()); BR.EmitBasicReport("Bad return type when passing CFErrorRef*", - "Coding conventions (Apple)", err, D->getLocation()); + "Coding conventions (Apple)", err, L); } } @@ -153,7 +157,8 @@ public: NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0), ShouldCheckNSError(0), ShouldCheckCFError(0) { } - void checkLocation(SVal loc, bool isLoad, CheckerContext &C) const; + void checkLocation(SVal loc, bool isLoad, const Stmt *S, + CheckerContext &C) const; void checkEvent(ImplicitNullDerefEvent event) const; }; } @@ -166,18 +171,18 @@ typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag; namespace clang { namespace ento { template <> - struct GRStateTrait<NSErrorOut> : public GRStatePartialTrait<ErrorOutFlag> { + struct ProgramStateTrait<NSErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> { static void *GDMIndex() { static int index = 0; return &index; } }; template <> - struct GRStateTrait<CFErrorOut> : public GRStatePartialTrait<ErrorOutFlag> { + struct ProgramStateTrait<CFErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> { static void *GDMIndex() { static int index = 0; return &index; } }; } } template <typename T> -static bool hasFlag(SVal val, const GRState *state) { +static bool hasFlag(SVal val, const ProgramState *state) { if (SymbolRef sym = val.getAsSymbol()) if (const unsigned *attachedFlags = state->get<T>(sym)) return *attachedFlags; @@ -185,7 +190,7 @@ static bool hasFlag(SVal val, const GRState *state) { } template <typename T> -static void setFlag(const GRState *state, SVal val, CheckerContext &C) { +static void setFlag(const ProgramState *state, SVal val, CheckerContext &C) { // We tag the symbol that the SVal wraps. if (SymbolRef sym = val.getAsSymbol()) C.addTransition(state->set<T>(sym, true)); @@ -207,6 +212,7 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) { } void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, + const Stmt *S, CheckerContext &C) const { if (!isLoad) return; @@ -214,7 +220,7 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, return; ASTContext &Ctx = C.getASTContext(); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting // SVal so that we can later check it when handling the @@ -247,7 +253,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { return; SVal loc = event.Location; - const GRState *state = event.SinkNode->getState(); + const ProgramState *state = event.SinkNode->getState(); BugReporter &BR = *event.BR; bool isNSError = hasFlag<NSErrorOut>(loc, state); @@ -277,7 +283,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { bug = new NSErrorDerefBug(); else bug = new CFErrorDerefBug(); - EnhancedBugReport *report = new EnhancedBugReport(*bug, os.str(), + BugReport *report = new BugReport(*bug, os.str(), event.SinkNode); BR.EmitReport(report); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index 2d0af9c..81f1924 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -16,23 +16,27 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "llvm/ADT/StringSwitch.h" +#include <cstdarg> using namespace clang; using namespace ento; namespace { -class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr> > { +class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr>, + check::PostObjCMessage > { public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPostObjCMessage(const ObjCMessage &msg, CheckerContext &C) const; }; } void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn(); @@ -50,7 +54,7 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE, // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. BuildSinks - = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) + = llvm::StringSwitch<bool>(StringRef(II->getName())) .Case("exit", true) .Case("panic", true) .Case("error", true) @@ -73,9 +77,70 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE, } if (BuildSinks) - C.generateSink(CE); + C.generateSink(); } +static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) { + va_list argp; + va_start(argp, Sel); + + unsigned Slot = 0; + const char *Arg; + while ((Arg = va_arg(argp, const char *))) { + if (!Sel->getNameForSlot(Slot).equals(Arg)) + break; // still need to va_end! + ++Slot; + } + + va_end(argp); + + // We only succeeded if we made it to the end of the argument list. + return (Arg == NULL); +} + +void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMessage &Msg, + CheckerContext &C) const { + // HACK: This entire check is to handle two messages in the Cocoa frameworks: + // -[NSAssertionHandler + // handleFailureInMethod:object:file:lineNumber:description:] + // -[NSAssertionHandler + // handleFailureInFunction:file:lineNumber:description:] + // Eventually these should be annotated with __attribute__((noreturn)). + // Because ObjC messages use dynamic dispatch, it is not generally safe to + // assume certain methods can't return. In cases where it is definitely valid, + // see if you can mark the methods noreturn or analyzer_noreturn instead of + // adding more explicit checks to this method. + + if (!Msg.isInstanceMessage()) + return; + + const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface(); + if (!Receiver) + return; + if (!Receiver->getIdentifier()->isStr("NSAssertionHandler")) + return; + + Selector Sel = Msg.getSelector(); + switch (Sel.getNumArgs()) { + default: + return; + case 4: + if (!isMultiArgSelector(&Sel, "handleFailureInFunction", "file", + "lineNumber", "description", NULL)) + return; + break; + case 5: + if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file", + "lineNumber", "description", NULL)) + return; + break; + } + + // If we got here, it's one of the messages we care about. + C.generateSink(); +} + + void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { mgr.registerChecker<NoReturnFunctionChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp index 7262bc3..f426265 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp @@ -22,22 +22,32 @@ using namespace ento; namespace { -class OSAtomicChecker : public Checker<eval::Call> { +class OSAtomicChecker : public Checker<eval::InlineCall> { public: - bool evalCall(const CallExpr *CE, CheckerContext &C) const; + bool inlineCall(const CallExpr *CE, ExprEngine &Eng, + ExplodedNode *Pred, ExplodedNodeSet &Dst) const; private: - static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE); + bool evalOSAtomicCompareAndSwap(const CallExpr *CE, + ExprEngine &Eng, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) const; + + ExplodedNode *generateNode(const ProgramState *State, + ExplodedNode *Pred, const CallExpr *Statement, + StmtNodeBuilder &B, ExplodedNodeSet &Dst) const; }; - } -bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); +bool OSAtomicChecker::inlineCall(const CallExpr *CE, + ExprEngine &Eng, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) const { + const ProgramState *state = Pred->getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); - const FunctionDecl* FD = L.getAsFunctionDecl(); + const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) return false; @@ -45,24 +55,38 @@ bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (!II) return false; - llvm::StringRef FName(II->getName()); + StringRef FName(II->getName()); // Check for compare and swap. if (FName.startswith("OSAtomicCompareAndSwap") || FName.startswith("objc_atomicCompareAndSwap")) - return evalOSAtomicCompareAndSwap(C, CE); + return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst); // FIXME: Other atomics. return false; } -bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, - const CallExpr *CE) { +ExplodedNode *OSAtomicChecker::generateNode(const ProgramState *State, + ExplodedNode *Pred, + const CallExpr *Statement, + StmtNodeBuilder &B, + ExplodedNodeSet &Dst) const { + ExplodedNode *N = B.generateNode(Statement, State, Pred, this); + if (N) + Dst.Add(N); + return N; +} + +bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE, + ExprEngine &Eng, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) const { // Not enough arguments to match OSAtomicCompareAndSwap? if (CE->getNumArgs() != 3) return false; - ASTContext &Ctx = C.getASTContext(); + StmtNodeBuilder &Builder = Eng.getBuilder(); + ASTContext &Ctx = Eng.getContext(); const Expr *oldValueExpr = CE->getArg(0); QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); @@ -87,15 +111,11 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, if (theValueTypePointee != newValueType) return false; - static unsigned magic_load = 0; - static unsigned magic_store = 0; - - const void *OSAtomicLoadTag = &magic_load; - const void *OSAtomicStoreTag = &magic_store; - + static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load"); + static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store"); + // Load 'theValue'. - ExprEngine &Engine = C.getEngine(); - const GRState *state = C.getState(); + const ProgramState *state = Pred->getState(); ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); // Here we should use the value type of the region as the load type, because @@ -106,19 +126,19 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, // LoadTy specifying can be omitted. But we put it here to emphasize the // semantics. QualType LoadTy; - if (const TypedRegion *TR = - dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + if (const TypedValueRegion *TR = + dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { LoadTy = TR->getValueType(); } - Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(), - state, location, OSAtomicLoadTag, LoadTy); + Eng.evalLoad(Tmp, theValueExpr, Pred, + state, location, &OSAtomicLoadTag, LoadTy); if (Tmp.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. - C.getNodeBuilder().BuildSinks = true; + Builder.BuildSinks = true; return true; } @@ -126,7 +146,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, I != E; ++I) { ExplodedNode *N = *I; - const GRState *stateLoad = N->getState(); + const ProgramState *stateLoad = N->getState(); // Use direct bindings from the environment since we are forcing a load // from a location that the Environment would typically not be used @@ -145,12 +165,13 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, DefinedOrUnknownSVal oldValueVal = cast<DefinedOrUnknownSVal>(oldValueVal_untested); - SValBuilder &svalBuilder = Engine.getSValBuilder(); + SValBuilder &svalBuilder = Eng.getSValBuilder(); // Perform the comparison. - DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal); + DefinedOrUnknownSVal Cmp = + svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal); - const GRState *stateEqual = stateLoad->assume(Cmp, true); + const ProgramState *stateEqual = stateLoad->assume(Cmp, true); // Were they equal? if (stateEqual) { @@ -159,20 +180,20 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, SVal val = stateEqual->getSVal(newValueExpr); // Handle implicit value casts. - if (const TypedRegion *R = - dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + if (const TypedValueRegion *R = + dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType()); } - Engine.evalStore(TmpStore, NULL, theValueExpr, N, - stateEqual, location, val, OSAtomicStoreTag); + Eng.evalStore(TmpStore, NULL, theValueExpr, N, + stateEqual, location, val, &OSAtomicStoreTag); if (TmpStore.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. - C.getNodeBuilder().BuildSinks = true; + Builder.BuildSinks = true; return true; } @@ -180,24 +201,24 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), E2 = TmpStore.end(); I2 != E2; ++I2) { ExplodedNode *predNew = *I2; - const GRState *stateNew = predNew->getState(); + const ProgramState *stateNew = predNew->getState(); // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) - Res = Engine.getSValBuilder().makeTruthVal(true, T); - C.generateNode(stateNew->BindExpr(CE, Res), predNew); + Res = Eng.getSValBuilder().makeTruthVal(true, T); + generateNode(stateNew->BindExpr(CE, Res), predNew, CE, Builder, Dst); } } // Were they not equal? - if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) { + if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) { // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) - Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType()); - C.generateNode(stateNotEqual->BindExpr(CE, Res), N); + Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType()); + generateNode(stateNotEqual->BindExpr(CE, Res), N, CE, Builder, Dst); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index a118049..3e4e07b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -38,7 +38,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const { const Expr *Ex = S->getSynchExpr(); - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal V = state->getSVal(Ex); // Uninitialized value used for the mutex? @@ -47,9 +47,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, if (!BT_undef) BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex " "for @synchronized")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + BugReport *report = + new BugReport(*BT_undef, BT_undef->getDescription(), N); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); C.EmitReport(report); } return; @@ -59,7 +59,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, return; // Check for null mutexes. - const GRState *notNullState, *nullState; + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V)); if (nullState) { @@ -70,10 +70,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, if (!BT_null) BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() " "(no synchronization will occur)")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_null, BT_null->getDescription(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - Ex); + BugReport *report = + new BugReport(*BT_null, BT_null->getDescription(), N); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); C.EmitReport(report); return; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 4c05867..2fb9944 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -50,7 +50,8 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/AST/ParentMap.h" @@ -76,7 +77,8 @@ public: void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - void checkLocation(SVal location, bool isLoad, CheckerContext &C) const; + void checkLocation(SVal location, bool isLoad, const Stmt *S, + CheckerContext &C) const; }; } // end anonymous namespace @@ -109,11 +111,11 @@ namespace { struct PreCallSelfFlags {}; } namespace clang { namespace ento { template<> - struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> { - static void* GDMIndex() { static int index = 0; return &index; } + struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> { + static void *GDMIndex() { static int index = 0; return &index; } }; template <> - struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> { + struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> { static void *GDMIndex() { static int index = 0; return &index; } }; @@ -122,13 +124,13 @@ namespace ento { /// object before the call so we can assign them to the new object that 'self' /// points to after the call. template <> - struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> { + struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> { static void *GDMIndex() { static int index = 0; return &index; } }; } } -static SelfFlagEnum getSelfFlags(SVal val, const GRState *state) { +static SelfFlagEnum getSelfFlags(SVal val, const ProgramState *state) { if (SymbolRef sym = val.getAsSymbol()) if (const unsigned *attachedFlags = state->get<SelfFlag>(sym)) return (SelfFlagEnum)*attachedFlags; @@ -139,7 +141,7 @@ static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) { return getSelfFlags(val, C.getState()); } -static void addSelfFlag(const GRState *state, SVal val, +static void addSelfFlag(const ProgramState *state, SVal val, SelfFlagEnum flag, CheckerContext &C) { // We tag the symbol that the SVal wraps. if (SymbolRef sym = val.getAsSymbol()) @@ -179,8 +181,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, if (!N) return; - EnhancedBugReport *report = - new EnhancedBugReport(*new InitSelfBug(), errorStr, N); + BugReport *report = + new BugReport(*new InitSelfBug(), errorStr, N); C.EmitReport(report); } @@ -197,7 +199,7 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg, if (isInitMessage(msg)) { // Tag the return value as the result of an initializer. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); // FIXME this really should be context sensitive, where we record // the current stack frame (for IPA). Also, we need to clean this @@ -257,7 +259,7 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S, void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { SVal argV = state->getSVal(*I); @@ -275,7 +277,7 @@ void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE, void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { SVal argV = state->getSVal(*I); @@ -294,10 +296,11 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE, } void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad, + const Stmt *S, CheckerContext &C) const { // Tag the result of a load from 'self' so that we can easily know that the // value is the object that 'self' points to. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (isSelfVar(location, C)) addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C); } @@ -315,9 +318,9 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { // self = [super init] applies only to NSObject subclasses. // For instance, NSProxy doesn't implement -init. - ASTContext& Ctx = MD->getASTContext(); + ASTContext &Ctx = MD->getASTContext(); IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); - ObjCInterfaceDecl* ID = MD->getClassInterface()->getSuperClass(); + ObjCInterfaceDecl *ID = MD->getClassInterface()->getSuperClass(); for ( ; ID ; ID = ID->getSuperClass()) { IdentifierInfo *II = ID->getIdentifier(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index d78e5ce..bbc262f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -29,7 +29,7 @@ using namespace ento; enum IVarState { Unused, Used }; typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap; -static void Scan(IvarUsageMap& M, const Stmt* S) { +static void Scan(IvarUsageMap& M, const Stmt *S) { if (!S) return; @@ -51,11 +51,11 @@ static void Scan(IvarUsageMap& M, const Stmt* S) { Scan(M, *I); } -static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { +static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl *D) { if (!D) return; - const ObjCIvarDecl* ID = D->getPropertyIvarDecl(); + const ObjCIvarDecl *ID = D->getPropertyIvarDecl(); if (!ID) return; @@ -65,7 +65,7 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { I->second = Used; } -static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { +static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) { // Scan the methods for accesses. for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), E = D->instmeth_end(); I!=E; ++I) @@ -102,14 +102,14 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { - const ObjCInterfaceDecl* ID = D->getClassInterface(); + const ObjCInterfaceDecl *ID = D->getClassInterface(); IvarUsageMap M; // Iterate over the ivars. for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { - const ObjCIvarDecl* ID = *I; + const ObjCIvarDecl *ID = *I; // Ignore ivars that... // (a) aren't private @@ -155,12 +155,14 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << "Instance variable '" << I->first << "' in class '" << ID + os << "Instance variable '" << *I->first << "' in class '" << *ID << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; + PathDiagnosticLocation L = + PathDiagnosticLocation::create(I->first, BR.getSourceManager()); BR.EmitBasicReport("Unused instance variable", "Optimization", - os.str(), I->first->getLocation()); + os.str(), L); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index 7c21acc..202522b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -36,7 +36,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B, if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal LV = state->getSVal(B->getLHS()); SVal RV = state->getSVal(B->getRHS()); @@ -56,7 +56,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B, "Pointer arithmetic done on non-array variables " "means reliance on memory layout, which is " "dangerous.")); - RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index 16ede20..924c7f2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -39,7 +39,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (B->getOpcode() != BO_Sub) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal LV = state->getSVal(B->getLHS()); SVal RV = state->getSVal(B->getRHS()); @@ -64,7 +64,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, BT.reset(new BuiltinBug("Pointer subtraction", "Subtraction of two pointers that do not point to " "the same memory chunk may cause incorrect result.")); - RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 74199bb..c02b5b1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -1,4 +1,4 @@ -//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===// +//===--- PthreadLockChecker.cpp - Check for locking problems ---*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually -// this shouldn't be registered with ExprEngineInternalChecks. +// This defines PthreadLockChecker, a simple lock -> unlock checker. +// Also handles XNU locks, which behave similarly enough to share code. // //===----------------------------------------------------------------------===// @@ -16,25 +16,29 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" -#include "llvm/ADT/ImmutableSet.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "llvm/ADT/ImmutableList.h" using namespace clang; using namespace ento; namespace { -class PthreadLockChecker - : public Checker< check::PostStmt<CallExpr> > { +class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > { + mutable llvm::OwningPtr<BugType> BT_doublelock; + mutable llvm::OwningPtr<BugType> BT_lor; + enum LockingSemantics { + NotApplicable = 0, + PthreadSemantics, + XNUSemantics + }; public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - void AcquireLock(CheckerContext &C, const CallExpr *CE, - SVal lock, bool isTryLock) const; + void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, + bool isTryLock, enum LockingSemantics semantics) const; - void ReleaseLock(CheckerContext &C, const CallExpr *CE, - SVal lock) const; - + void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const; }; } // end anonymous namespace @@ -42,80 +46,117 @@ public: namespace { class LockSet {}; } namespace clang { namespace ento { -template <> struct GRStateTrait<LockSet> : - public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { - static void* GDMIndex() { static int x = 0; return &x; } +template <> struct ProgramStateTrait<LockSet> : + public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > { + static void *GDMIndex() { static int x = 0; return &x; } }; -} // end GR namespace +} // end of ento (ProgramState) namespace } // end clang namespace void PthreadLockChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); - const FunctionTextRegion *R = - dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); - - if (!R) + const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl(); + + if (!FD) return; - - IdentifierInfo *II = R->getDecl()->getIdentifier(); + + // Get the name of the callee. + IdentifierInfo *II = FD->getIdentifier(); if (!II) // if no identifier, not a simple C function return; - llvm::StringRef FName = II->getName(); - - if (FName == "pthread_mutex_lock") { - if (CE->getNumArgs() != 1) - return; - AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false); - } - else if (FName == "pthread_mutex_trylock") { - if (CE->getNumArgs() != 1) - return; - AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true); - } - else if (FName == "pthread_mutex_unlock") { - if (CE->getNumArgs() != 1) - return; + StringRef FName = II->getName(); + + if (CE->getNumArgs() != 1) + return; + + if (FName == "pthread_mutex_lock" || + FName == "pthread_rwlock_rdlock" || + FName == "pthread_rwlock_wrlock") + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, PthreadSemantics); + else if (FName == "lck_mtx_lock" || + FName == "lck_rw_lock_exclusive" || + FName == "lck_rw_lock_shared") + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, XNUSemantics); + else if (FName == "pthread_mutex_trylock" || + FName == "pthread_rwlock_tryrdlock" || + FName == "pthread_rwlock_tryrwlock") + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, PthreadSemantics); + else if (FName == "lck_mtx_try_lock" || + FName == "lck_rw_try_lock_exclusive" || + FName == "lck_rw_try_lock_shared") + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, XNUSemantics); + else if (FName == "pthread_mutex_unlock" || + FName == "pthread_rwlock_unlock" || + FName == "lck_mtx_unlock" || + FName == "lck_rw_done") ReleaseLock(C, CE, state->getSVal(CE->getArg(0))); - } } void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, - SVal lock, bool isTryLock) const { + SVal lock, bool isTryLock, + enum LockingSemantics semantics) const { const MemRegion *lockR = lock.getAsRegion(); if (!lockR) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal X = state->getSVal(CE); if (X.isUnknownOrUndef()) return; DefinedSVal retVal = cast<DefinedSVal>(X); - const GRState *lockSucc = state; - + + if (state->contains<LockSet>(lockR)) { + if (!BT_doublelock) + BT_doublelock.reset(new BugType("Double locking", "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *report = new BugReport(*BT_doublelock, + "This lock has already " + "been acquired", N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); + return; + } + + const ProgramState *lockSucc = state; if (isTryLock) { - // Bifurcate the state, and allow a mode where the lock acquisition fails. - const GRState *lockFail; - llvm::tie(lockFail, lockSucc) = state->assume(retVal); + // Bifurcate the state, and allow a mode where the lock acquisition fails. + const ProgramState *lockFail; + switch (semantics) { + case PthreadSemantics: + llvm::tie(lockFail, lockSucc) = state->assume(retVal); + break; + case XNUSemantics: + llvm::tie(lockSucc, lockFail) = state->assume(retVal); + break; + default: + llvm_unreachable("Unknown tryLock locking semantics"); + break; + } assert(lockFail && lockSucc); - C.addTransition(C.generateNode(CE, lockFail)); - } - else { - // Assume that the return value was 0. + C.addTransition(lockFail); + + } else if (semantics == PthreadSemantics) { + // Assume that the return value was 0. lockSucc = state->assume(retVal, false); assert(lockSucc); + + } else { + // XNU locking semantics return void on non-try locks + assert((semantics == XNUSemantics) && "Unknown locking semantics"); + lockSucc = state; } - // Record that the lock was acquired. + // Record that the lock was acquired. lockSucc = lockSucc->add<LockSet>(lockR); - - C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) : - C.getPredecessor()); + C.addTransition(lockSucc); } void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, @@ -125,19 +166,37 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, if (!lockR) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); + llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>(); - // Record that the lock was released. - // FIXME: Handle unlocking locks that were never acquired. This may - // require IPA for wrappers. - const GRState *unlockState = state->remove<LockSet>(lockR); - - if (state == unlockState) + // FIXME: Better analysis requires IPA for wrappers. + // FIXME: check for double unlocks + if (LS.isEmpty()) return; - C.addTransition(C.generateNode(CE, unlockState)); + const MemRegion *firstLockR = LS.getHead(); + if (firstLockR != lockR) { + if (!BT_lor) + BT_lor.reset(new BugType("Lock order reversal", "Lock checker")); + ExplodedNode *N = C.generateSink(); + if (!N) + return; + BugReport *report = new BugReport(*BT_lor, + "This was not the most " + "recently acquired lock. " + "Possible lock order " + "reversal", N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); + return; + } + + // Record that the lock was released. + state = state->set<LockSet>(LS.getTail()); + C.addTransition(state); } + void ento::registerPthreadLockChecker(CheckerManager &mgr) { mgr.registerChecker<PthreadLockChecker>(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index bf53029..93e0fe5 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1,4 +1,4 @@ -// CFRefCount.cpp - Transfer functions for tracking simple values -*- C++ -*--// +//==-- RetainCountChecker.cpp - Checks for leaks and other issues -*- C++ -*--// // // The LLVM Compiler Infrastructure // @@ -7,111 +7,56 @@ // //===----------------------------------------------------------------------===// // -// This file defines the methods for CFRefCount, which implements -// a reference count checker for Core Foundation (Mac OS X). +// This file defines the methods for RetainCountChecker, which implements +// a reference count checker for Core Foundation and Cocoa on (Mac OS X). // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "ClangSACheckers.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include <stdarg.h> +#include <cstdarg> using namespace clang; using namespace ento; -using llvm::StringRef; using llvm::StrInStrNoCase; namespace { -class InstanceReceiver { - ObjCMessage Msg; - const LocationContext *LC; -public: - InstanceReceiver() : LC(0) { } - InstanceReceiver(const ObjCMessage &msg, - const LocationContext *lc = 0) : Msg(msg), LC(lc) {} - - bool isValid() const { - return Msg.isValid() && Msg.isInstanceMessage(); - } - operator bool() const { - return isValid(); - } - - SVal getSValAsScalarOrLoc(const GRState *state) { - assert(isValid()); - // We have an expression for the receiver? Fetch the value - // of that expression. - if (const Expr *Ex = Msg.getInstanceReceiver()) - return state->getSValAsScalarOrLoc(Ex); - - // Otherwise we are sending a message to super. In this case the - // object reference is the same as 'self'. - if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) - return state->getSVal(state->getRegion(SelfDecl, LC)); - - return UnknownVal(); - } - - SourceRange getSourceRange() const { - assert(isValid()); - if (const Expr *Ex = Msg.getInstanceReceiver()) - return Ex->getSourceRange(); - - // Otherwise we are sending a message to super. - SourceLocation L = Msg.getSuperLoc(); - assert(L.isValid()); - return SourceRange(L, L); - } -}; -} - -static const ObjCMethodDecl* -ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { - const ObjCInterfaceDecl *ID = MD->getClassInterface(); - - return MD->isInstanceMethod() - ? ID->lookupInstanceMethod(MD->getSelector()) - : ID->lookupClassMethod(MD->getSelector()); -} - -namespace { +/// Wrapper around different kinds of node builder, so that helper functions +/// can have a common interface. class GenericNodeBuilderRefCount { - StmtNodeBuilder *SNB; - const Stmt *S; - const void *tag; + CheckerContext *C; + const ProgramPointTag *tag; EndOfFunctionNodeBuilder *ENB; public: - GenericNodeBuilderRefCount(StmtNodeBuilder &snb, const Stmt *s, - const void *t) - : SNB(&snb), S(s), tag(t), ENB(0) {} + GenericNodeBuilderRefCount(CheckerContext &c, + const ProgramPointTag *t) + : C(&c), tag(t), ENB(0) {} GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb) - : SNB(0), S(0), tag(0), ENB(&enb) {} + : C(0), tag(0), ENB(&enb) {} - ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) { - if (SNB) - return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag), - state, Pred); + ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred) { + if (C) + return C->generateNode(state, Pred, tag, false); assert(ENB); return ENB->generateNode(state, Pred); @@ -125,9 +70,9 @@ public: /// ArgEffect is used to summarize a function/method call's effect on a /// particular argument. -enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing, +enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg, DecRefBridgedTransfered, - DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape, + IncRefMsg, IncRef, MakeCollectable, MayEscape, NewAutoreleasePool, SelfOwn, StopTracking }; namespace llvm { @@ -148,9 +93,8 @@ namespace { /// respect to its return value. class RetEffect { public: - enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, + enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol, - ReceiverAlias, OwnedWhenTrackedReceiver }; enum ObjKind { CF, ObjC, AnyObj }; @@ -158,36 +102,27 @@ public: private: Kind K; ObjKind O; - unsigned index; - RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {} - RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {} + RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} public: Kind getKind() const { return K; } ObjKind getObjKind() const { return O; } - unsigned getIndex() const { - assert(getKind() == Alias); - return index; - } - bool isOwned() const { return K == OwnedSymbol || K == OwnedAllocatedSymbol || K == OwnedWhenTrackedReceiver; } + bool operator==(const RetEffect &Other) const { + return K == Other.K && O == Other.O; + } + static RetEffect MakeOwnedWhenTrackedReceiver() { return RetEffect(OwnedWhenTrackedReceiver, ObjC); } - static RetEffect MakeAlias(unsigned Idx) { - return RetEffect(Alias, Idx); - } - static RetEffect MakeReceiverAlias() { - return RetEffect(ReceiverAlias); - } static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); } @@ -314,15 +249,15 @@ public: ID.Add(T); } - void print(llvm::raw_ostream& Out) const; + void print(raw_ostream &Out) const; }; -void RefVal::print(llvm::raw_ostream& Out) const { +void RefVal::print(raw_ostream &Out) const { if (!T.isNull()) - Out << "Tracked Type:" << T.getAsString() << '\n'; + Out << "Tracked " << T.getAsString() << '/'; switch (getKind()) { - default: assert(false); + default: llvm_unreachable("Invalid RefVal kind"); case Owned: { Out << "Owned"; unsigned cnt = getCount(); @@ -406,18 +341,19 @@ typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; namespace clang { namespace ento { - template<> - struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> { - static void* GDMIndex() { - static int RefBIndex = 0; - return &RefBIndex; - } - }; +template<> +struct ProgramStateTrait<RefBindings> + : public ProgramStatePartialTrait<RefBindings> { + static void *GDMIndex() { + static int RefBIndex = 0; + return &RefBIndex; + } +}; } } //===----------------------------------------------------------------------===// -// Summaries +// Function/Method behavior summaries. //===----------------------------------------------------------------------===// namespace { @@ -436,19 +372,13 @@ class RetainSummary { ArgEffect Receiver; /// Ret - The effect on the return value. Used to indicate if the - /// function/method call returns a new tracked symbol, returns an - /// alias of one of the arguments in the call, and so on. + /// function/method call returns a new tracked symbol. RetEffect Ret; - /// EndPath - Indicates that execution of this method/function should - /// terminate the simulation of a path. - bool EndPath; - public: RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, - ArgEffect ReceiverEff, bool endpath = false) - : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R), - EndPath(endpath) {} + ArgEffect ReceiverEff) + : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R) {} /// getArg - Return the argument effect on the argument specified by /// idx (starting from 0). @@ -474,10 +404,6 @@ public: /// setRetEffect - Set the effect of the return value of the call. void setRetEffect(RetEffect E) { Ret = E; } - /// isEndPath - Returns true if executing the given method/function should - /// terminate the path. - bool isEndPath() const { return EndPath; } - /// Sets the effect on the receiver of the message. void setReceiverEffect(ArgEffect e) { Receiver = e; } @@ -485,6 +411,14 @@ public: /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } + + /// Test if two retain summaries are identical. Note that merely equivalent + /// summaries are not necessarily identical (for example, if an explicit + /// argument effect matches the default effect). + bool operator==(const RetainSummary &Other) const { + return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect && + Receiver == Other.Receiver && Ret == Other.Ret; + } }; } // end anonymous namespace @@ -500,10 +434,10 @@ public: ObjCSummaryKey(IdentifierInfo* ii, Selector s) : II(ii), S(s) {} - ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s) + ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s) : II(d ? d->getIdentifier() : 0), S(s) {} - ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s) + ObjCSummaryKey(const ObjCInterfaceDecl *d, IdentifierInfo *ii, Selector s) : II(d ? d->getIdentifier() : ii), S(s) {} ObjCSummaryKey(Selector s) @@ -547,19 +481,19 @@ struct isPodLike<ObjCSummaryKey> { static const bool value = true; }; namespace { class ObjCSummaryCache { - typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy; + typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy; MapTy M; public: ObjCSummaryCache() {} - RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, + const RetainSummary * find(const ObjCInterfaceDecl *D, IdentifierInfo *ClsName, Selector S) { // Lookup the method using the decl for the class @interface. If we // have no decl, lookup using the class name. return D ? find(D, S) : find(ClsName, S); } - RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) { + const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) { // Do a lookup with the (D,S) pair. If we find a match return // the iterator. ObjCSummaryKey K(D, S); @@ -574,7 +508,7 @@ public: // generate initial summaries without having to worry about NSObject // being declared. // FIXME: We may change this at some point. - for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) { + for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) { if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) break; @@ -584,12 +518,12 @@ public: // Cache the summary with original key to make the next lookup faster // and return the iterator. - RetainSummary *Summ = I->second; + const RetainSummary *Summ = I->second; M[K] = Summ; return Summ; } - RetainSummary* find(IdentifierInfo* II, Selector S) { + const RetainSummary * find(IdentifierInfo* II, Selector S) { // FIXME: Class method lookup. Right now we dont' have a good way // of going between IdentifierInfo* and the class hierarchy. MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); @@ -600,11 +534,11 @@ public: return I == M.end() ? NULL : I->second; } - RetainSummary*& operator[](ObjCSummaryKey K) { + const RetainSummary *& operator[](ObjCSummaryKey K) { return M[K]; } - RetainSummary*& operator[](Selector S) { + const RetainSummary *& operator[](Selector S) { return M[ ObjCSummaryKey(S) ]; } }; @@ -621,7 +555,7 @@ class RetainSummaryManager { // Typedefs. //==-----------------------------------------------------------------==// - typedef llvm::DenseMap<const FunctionDecl*, RetainSummary*> + typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *> FuncSummariesTy; typedef ObjCSummaryCache ObjCMethodSummariesTy; @@ -631,11 +565,7 @@ class RetainSummaryManager { //==-----------------------------------------------------------------==// /// Ctx - The ASTContext object for the analyzed ASTs. - ASTContext& Ctx; - - /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier - /// "CFDictionaryCreate". - IdentifierInfo* CFDictionaryCreateII; + ASTContext &Ctx; /// GCEnabled - Records whether or not the analyzed code runs in GC mode. const bool GCEnabled; @@ -672,7 +602,7 @@ class RetainSummaryManager { RetEffect ObjCInitRetE; RetainSummary DefaultSummary; - RetainSummary* StopSummary; + const RetainSummary *StopSummary; //==-----------------------------------------------------------------==// // Methods. @@ -687,30 +617,28 @@ class RetainSummaryManager { public: RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } - RetainSummary *getDefaultSummary() { - RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); - return new (Summ) RetainSummary(DefaultSummary); + const RetainSummary *getDefaultSummary() { + return &DefaultSummary; } + + const RetainSummary * getUnarySummary(const FunctionType* FT, + UnaryFuncKind func); - RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func); - - RetainSummary* getCFSummaryCreateRule(const FunctionDecl* FD); - RetainSummary* getCFSummaryGetRule(const FunctionDecl* FD); - RetainSummary* getCFCreateGetRuleSummary(const FunctionDecl* FD, - StringRef FName); + const RetainSummary * getCFSummaryCreateRule(const FunctionDecl *FD); + const RetainSummary * getCFSummaryGetRule(const FunctionDecl *FD); + const RetainSummary * getCFCreateGetRuleSummary(const FunctionDecl *FD); - RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, - ArgEffect ReceiverEff = DoNothing, - ArgEffect DefaultEff = MayEscape, - bool isEndPath = false); + const RetainSummary * getPersistentSummary(ArgEffects AE, RetEffect RetEff, + ArgEffect ReceiverEff = DoNothing, + ArgEffect DefaultEff = MayEscape); - RetainSummary* getPersistentSummary(RetEffect RE, - ArgEffect ReceiverEff = DoNothing, - ArgEffect DefaultEff = MayEscape) { + const RetainSummary * getPersistentSummary(RetEffect RE, + ArgEffect ReceiverEff = DoNothing, + ArgEffect DefaultEff = MayEscape) { return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff); } - RetainSummary *getPersistentStopSummary() { + const RetainSummary *getPersistentStopSummary() { if (StopSummary) return StopSummary; @@ -720,35 +648,35 @@ public: return StopSummary; } - RetainSummary *getInitMethodSummary(QualType RetTy); + const RetainSummary *getInitMethodSummary(QualType RetTy); void InitializeClassMethodSummaries(); void InitializeMethodSummaries(); private: - void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) { + void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) { ObjCClassMethodSummaries[S] = Summ; } - void addNSObjectMethSummary(Selector S, RetainSummary *Summ) { + void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) { ObjCMethodSummaries[S] = Summ; } void addClassMethSummary(const char* Cls, const char* nullaryName, - RetainSummary *Summ) { + const RetainSummary *Summ) { IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); Selector S = GetNullarySelector(nullaryName, Ctx); ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } void addInstMethSummary(const char* Cls, const char* nullaryName, - RetainSummary *Summ) { + const RetainSummary *Summ) { IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); Selector S = GetNullarySelector(nullaryName, Ctx); ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } Selector generateSelector(va_list argp) { - llvm::SmallVector<IdentifierInfo*, 10> II; + SmallVector<IdentifierInfo*, 10> II; while (const char* s = va_arg(argp, const char*)) II.push_back(&Ctx.Idents.get(s)); @@ -757,47 +685,36 @@ private: } void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, - RetainSummary* Summ, va_list argp) { + const RetainSummary * Summ, va_list argp) { Selector S = generateSelector(argp); Summaries[ObjCSummaryKey(ClsII, S)] = Summ; } - void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) { + void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); va_end(argp); } - void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) { + void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp); va_end(argp); } - void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) { + void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp); va_end(argp); } - void addPanicSummary(const char* Cls, ...) { - RetainSummary* Summ = getPersistentSummary(AF.getEmptyMap(), - RetEffect::MakeNoRet(), - DoNothing, DoNothing, true); - va_list argp; - va_start (argp, Cls); - addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); - va_end(argp); - } - public: - RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC) + RetainSummaryManager(ASTContext &ctx, bool gcenabled, bool usesARC) : Ctx(ctx), - CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")), GCEnabled(gcenabled), ARCEnabled(usesARC), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), @@ -819,31 +736,31 @@ public: InitializeMethodSummaries(); } - ~RetainSummaryManager(); - - RetainSummary* getSummary(const FunctionDecl* FD); + const RetainSummary * getSummary(const FunctionDecl *FD); - RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg, - const GRState *state, - const LocationContext *LC); + const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg, + const ProgramState *state, + const LocationContext *LC); - RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg, - const ObjCInterfaceDecl* ID) { + const RetainSummary * getInstanceMethodSummary(const ObjCMessage &msg, + const ObjCInterfaceDecl *ID) { return getInstanceMethodSummary(msg.getSelector(), 0, ID, msg.getMethodDecl(), msg.getType(Ctx)); } - RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, - const ObjCInterfaceDecl* ID, - const ObjCMethodDecl *MD, - QualType RetTy); + const RetainSummary * getInstanceMethodSummary(Selector S, + IdentifierInfo *ClsName, + const ObjCInterfaceDecl *ID, + const ObjCMethodDecl *MD, + QualType RetTy); - RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName, - const ObjCInterfaceDecl *ID, - const ObjCMethodDecl *MD, - QualType RetTy); + const RetainSummary *getClassMethodSummary(Selector S, + IdentifierInfo *ClsName, + const ObjCInterfaceDecl *ID, + const ObjCMethodDecl *MD, + QualType RetTy); - RetainSummary *getClassMethodSummary(const ObjCMessage &msg) { + const RetainSummary *getClassMethodSummary(const ObjCMessage &msg) { const ObjCInterfaceDecl *Class = 0; if (!msg.isInstanceMessage()) Class = msg.getReceiverInterface(); @@ -856,30 +773,26 @@ public: /// getMethodSummary - This version of getMethodSummary is used to query /// the summary for the current method being analyzed. - RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { + const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) { // FIXME: Eventually this should be unneeded. const ObjCInterfaceDecl *ID = MD->getClassInterface(); Selector S = MD->getSelector(); IdentifierInfo *ClsName = ID->getIdentifier(); QualType ResultTy = MD->getResultType(); - // Resolve the method decl last. - if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD)) - MD = InterfaceMD; - if (MD->isInstanceMethod()) return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy); else return getClassMethodSummary(S, ClsName, ID, MD, ResultTy); } - RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD, - Selector S, QualType RetTy); + const RetainSummary * getCommonMethodSummary(const ObjCMethodDecl *MD, + Selector S, QualType RetTy); - void updateSummaryFromAnnotations(RetainSummary &Summ, + void updateSummaryFromAnnotations(const RetainSummary *&Summ, const ObjCMethodDecl *MD); - void updateSummaryFromAnnotations(RetainSummary &Summ, + void updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD); bool isGCEnabled() const { return GCEnabled; } @@ -888,35 +801,69 @@ public: bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; } - RetainSummary *copySummary(RetainSummary *OldSumm) { - RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); + const RetainSummary *copySummary(const RetainSummary *OldSumm) { + RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); new (Summ) RetainSummary(*OldSumm); return Summ; } }; +// Used to avoid allocating long-term (BPAlloc'd) memory for default retain +// summaries. If a function or method looks like it has a default summary, but +// it has annotations, the annotations are added to the stack-based template +// and then copied into managed memory. +class RetainSummaryTemplate { + RetainSummaryManager &Manager; + const RetainSummary *&RealSummary; + const RetainSummary *BaseSummary; + RetainSummary ScratchSummary; + bool Accessed; +public: + RetainSummaryTemplate(const RetainSummary *&real, const RetainSummary &base, + RetainSummaryManager &manager) + : Manager(manager), + RealSummary(real), + BaseSummary(&base), + ScratchSummary(base), + Accessed(false) {} + + ~RetainSummaryTemplate() { + if (Accessed) + RealSummary = Manager.copySummary(&ScratchSummary); + else if (!RealSummary) + RealSummary = BaseSummary; + } + + RetainSummary &operator*() { + Accessed = true; + return ScratchSummary; + } + + RetainSummary *operator->() { + Accessed = true; + return &ScratchSummary; + } +}; + } // end anonymous namespace //===----------------------------------------------------------------------===// // Implementation of checker data structures. //===----------------------------------------------------------------------===// -RetainSummaryManager::~RetainSummaryManager() {} - ArgEffects RetainSummaryManager::getArgEffects() { ArgEffects AE = ScratchArgs; ScratchArgs = AF.getEmptyMap(); return AE; } -RetainSummary* +const RetainSummary * RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff, - ArgEffect DefaultEff, - bool isEndPath) { + ArgEffect DefaultEff) { // Create the summary and return it. - RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>(); - new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath); + RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>(); + new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff); return Summ; } @@ -924,22 +871,28 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, // Summary creation for functions (largely uses of Core Foundation). //===----------------------------------------------------------------------===// -static bool isRetain(const FunctionDecl* FD, StringRef FName) { +static bool isRetain(const FunctionDecl *FD, StringRef FName) { return FName.endswith("Retain"); } -static bool isRelease(const FunctionDecl* FD, StringRef FName) { +static bool isRelease(const FunctionDecl *FD, StringRef FName) { return FName.endswith("Release"); } -RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { +static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) { + // FIXME: Remove FunctionDecl parameter. + // FIXME: Is it really okay if MakeCollectable isn't a suffix? + return FName.find("MakeCollectable") != StringRef::npos; +} + +const RetainSummary * RetainSummaryManager::getSummary(const FunctionDecl *FD) { // Look up a summary in our cache of FunctionDecls -> Summaries. FuncSummariesTy::iterator I = FuncSummaries.find(FD); if (I != FuncSummaries.end()) return I->second; // No summary? Generate one. - RetainSummary *S = 0; + const RetainSummary *S = 0; do { // We generate "stop" summaries for implicitly defined functions. @@ -1054,10 +1007,10 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { if (cocoa::isRefType(RetTy, "CF", FName)) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); - else if (FName.find("MakeCollectable") != StringRef::npos) + else if (isMakeCollectable(FD, FName)) S = getUnarySummary(FT, cfmakecollectable); else - S = getCFCreateGetRuleSummary(FD, FName); + S = getCFCreateGetRuleSummary(FD); break; } @@ -1067,7 +1020,7 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); else - S = getCFCreateGetRuleSummary(FD, FName); + S = getCFCreateGetRuleSummary(FD); break; } @@ -1076,7 +1029,7 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { if (cocoa::isRefType(RetTy, "DADisk") || cocoa::isRefType(RetTy, "DADissenter") || cocoa::isRefType(RetTy, "DASessionRef")) { - S = getCFCreateGetRuleSummary(FD, FName); + S = getCFCreateGetRuleSummary(FD); break; } @@ -1121,27 +1074,22 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { } while (0); - if (!S) - S = getDefaultSummary(); - // Annotations override defaults. - assert(S); - updateSummaryFromAnnotations(*S, FD); + updateSummaryFromAnnotations(S, FD); FuncSummaries[FD] = S; return S; } -RetainSummary* -RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD, - StringRef FName) { - if (coreFoundation::followsCreateRule(FName)) +const RetainSummary * +RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) { + if (coreFoundation::followsCreateRule(FD)) return getCFSummaryCreateRule(FD); return getCFSummaryGetRule(FD); } -RetainSummary* +const RetainSummary * RetainSummaryManager::getUnarySummary(const FunctionType* FT, UnaryFuncKind func) { @@ -1153,44 +1101,27 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, assert (ScratchArgs.isEmpty()); + ArgEffect Effect; switch (func) { - case cfretain: { - ScratchArgs = AF.add(ScratchArgs, 0, IncRef); - return getPersistentSummary(RetEffect::MakeAlias(0), - DoNothing, DoNothing); - } - - case cfrelease: { - ScratchArgs = AF.add(ScratchArgs, 0, DecRef); - return getPersistentSummary(RetEffect::MakeNoRet(), - DoNothing, DoNothing); - } - - case cfmakecollectable: { - ScratchArgs = AF.add(ScratchArgs, 0, MakeCollectable); - return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); - } - - default: - assert (false && "Not a supported unary function."); - return getDefaultSummary(); + case cfretain: Effect = IncRef; break; + case cfrelease: Effect = DecRef; break; + case cfmakecollectable: Effect = MakeCollectable; break; + default: llvm_unreachable("Not a supported unary function."); } + + ScratchArgs = AF.add(ScratchArgs, 0, Effect); + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } -RetainSummary* -RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl* FD) { +const RetainSummary * +RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { assert (ScratchArgs.isEmpty()); - if (FD->getIdentifier() == CFDictionaryCreateII) { - ScratchArgs = AF.add(ScratchArgs, 1, DoNothingByRef); - ScratchArgs = AF.add(ScratchArgs, 2, DoNothingByRef); - } - return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); } -RetainSummary* -RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) { +const RetainSummary * +RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { assert (ScratchArgs.isEmpty()); return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), DoNothing, DoNothing); @@ -1200,7 +1131,7 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) { // Summary creation for Selectors. //===----------------------------------------------------------------------===// -RetainSummary* +const RetainSummary * RetainSummaryManager::getInitMethodSummary(QualType RetTy) { assert(ScratchArgs.isEmpty()); // 'init' methods conceptually return a newly allocated object and claim @@ -1213,22 +1144,24 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) { } void -RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD) { if (!FD) return; + RetainSummaryTemplate Template(Summ, DefaultSummary, *this); + // Effects on the parameters. unsigned parm_idx = 0; for (FunctionDecl::param_const_iterator pi = FD->param_begin(), pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; if (pd->getAttr<NSConsumedAttr>()) { - if (!GCEnabled) - Summ.addArg(AF, parm_idx, DecRef); - } - else if(pd->getAttr<CFConsumedAttr>()) { - Summ.addArg(AF, parm_idx, DecRef); + if (!GCEnabled) { + Template->addArg(AF, parm_idx, DecRef); + } + } else if (pd->getAttr<CFConsumedAttr>()) { + Template->addArg(AF, parm_idx, DecRef); } } @@ -1237,83 +1170,84 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, // Determine if there is a special return effect for this method. if (cocoa::isCocoaObjectRef(RetTy)) { if (FD->getAttr<NSReturnsRetainedAttr>()) { - Summ.setRetEffect(ObjCAllocRetE); + Template->setRetEffect(ObjCAllocRetE); } else if (FD->getAttr<CFReturnsRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } else if (FD->getAttr<NSReturnsNotRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); + Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); } else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); } - } - else if (RetTy->getAs<PointerType>()) { + } else if (RetTy->getAs<PointerType>()) { if (FD->getAttr<CFReturnsRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); } } } void -RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, - const ObjCMethodDecl *MD) { +RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, + const ObjCMethodDecl *MD) { if (!MD) return; + RetainSummaryTemplate Template(Summ, DefaultSummary, *this); + bool isTrackedLoc = false; // Effects on the receiver. if (MD->getAttr<NSConsumesSelfAttr>()) { if (!GCEnabled) - Summ.setReceiverEffect(DecRefMsg); + Template->setReceiverEffect(DecRefMsg); } // Effects on the parameters. unsigned parm_idx = 0; - for (ObjCMethodDecl::param_iterator pi=MD->param_begin(), pe=MD->param_end(); + for (ObjCMethodDecl::param_const_iterator + pi=MD->param_begin(), pe=MD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; if (pd->getAttr<NSConsumedAttr>()) { if (!GCEnabled) - Summ.addArg(AF, parm_idx, DecRef); + Template->addArg(AF, parm_idx, DecRef); } else if(pd->getAttr<CFConsumedAttr>()) { - Summ.addArg(AF, parm_idx, DecRef); + Template->addArg(AF, parm_idx, DecRef); } } // Determine if there is a special return effect for this method. if (cocoa::isCocoaObjectRef(MD->getResultType())) { if (MD->getAttr<NSReturnsRetainedAttr>()) { - Summ.setRetEffect(ObjCAllocRetE); + Template->setRetEffect(ObjCAllocRetE); return; } if (MD->getAttr<NSReturnsNotRetainedAttr>()) { - Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); + Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); return; } isTrackedLoc = true; - } - - if (!isTrackedLoc) + } else { isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL; + } if (isTrackedLoc) { if (MD->getAttr<CFReturnsRetainedAttr>()) - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); else if (MD->getAttr<CFReturnsNotRetainedAttr>()) - Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); } } -RetainSummary* -RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, +const RetainSummary * +RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD, Selector S, QualType RetTy) { if (MD) { @@ -1322,9 +1256,9 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, // Delegates are a frequent form of false positives with the retain // count checker. unsigned i = 0; - for (ObjCMethodDecl::param_iterator I = MD->param_begin(), + for (ObjCMethodDecl::param_const_iterator I = MD->param_begin(), E = MD->param_end(); I != E; ++I, ++i) - if (ParmVarDecl *PD = *I) { + if (const ParmVarDecl *PD = *I) { QualType Ty = Ctx.getCanonicalType(PD->getType()); if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy) ScratchArgs = AF.add(ScratchArgs, i, StopTracking); @@ -1370,15 +1304,15 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape); } -RetainSummary* +const RetainSummary * RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg, - const GRState *state, + const ProgramState *state, const LocationContext *LC) { // We need the type-information of the tracked receiver object // Retrieve it from the state. const Expr *Receiver = msg.getInstanceReceiver(); - const ObjCInterfaceDecl* ID = 0; + const ObjCInterfaceDecl *ID = 0; // FIXME: Is this really working as expected? There are cases where // we just use the 'ID' from the message expression. @@ -1410,19 +1344,18 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg, // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. - RetainSummary *Summ = getInstanceMethodSummary(msg, ID); - return Summ ? Summ : getDefaultSummary(); + return getInstanceMethodSummary(msg, ID); } -RetainSummary* +const RetainSummary * RetainSummaryManager::getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, - const ObjCInterfaceDecl* ID, + const ObjCInterfaceDecl *ID, const ObjCMethodDecl *MD, QualType RetTy) { // Look up a summary in our summary cache. - RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S); + const RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S); if (!Summ) { assert(ScratchArgs.isEmpty()); @@ -1434,7 +1367,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, Summ = getCommonMethodSummary(MD, S, RetTy); // Annotations override defaults. - updateSummaryFromAnnotations(*Summ, MD); + updateSummaryFromAnnotations(Summ, MD); // Memoize the summary. ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; @@ -1443,19 +1376,21 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, return Summ; } -RetainSummary* +const RetainSummary * RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, const ObjCInterfaceDecl *ID, const ObjCMethodDecl *MD, QualType RetTy) { assert(ClsName && "Class name must be specified."); - RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); + const RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); if (!Summ) { Summ = getCommonMethodSummary(MD, S, RetTy); + // Annotations override defaults. - updateSummaryFromAnnotations(*Summ, MD); + updateSummaryFromAnnotations(Summ, MD); + // Memoize the summary. ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; } @@ -1465,8 +1400,6 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, void RetainSummaryManager::InitializeClassMethodSummaries() { assert(ScratchArgs.isEmpty()); - RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE); - // Create the [NSAssertionHandler currentHander] summary. addClassMethSummary("NSAssertionHandler", "currentHandler", getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); @@ -1482,7 +1415,8 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { // used for delegates that can release the object. When we have better // inter-procedural analysis we can potentially do something better. This // workaround is to remove false positives. - Summ = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking); + const RetainSummary *Summ = + getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking); IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject"); addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject", "afterDelay", NULL); @@ -1506,7 +1440,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Create the "init" selector. It just acts as a pass-through for the // receiver. - RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); + const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); // awakeAfterUsingCoder: behaves basically like an 'init' method. It @@ -1515,35 +1449,34 @@ void RetainSummaryManager::InitializeMethodSummaries() { InitSumm); // The next methods are allocators. - RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); - RetainSummary *CFAllocSumm = + const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); + const RetainSummary *CFAllocSumm = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); // Create the "retain" selector. - RetEffect E = RetEffect::MakeReceiverAlias(); - RetainSummary *Summ = getPersistentSummary(E, IncRefMsg); + RetEffect NoRet = RetEffect::MakeNoRet(); + const RetainSummary *Summ = getPersistentSummary(NoRet, IncRefMsg); addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); // Create the "release" selector. - Summ = getPersistentSummary(E, DecRefMsg); + Summ = getPersistentSummary(NoRet, DecRefMsg); addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); // Create the "drain" selector. - Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef); + Summ = getPersistentSummary(NoRet, isGCEnabled() ? DoNothing : DecRef); addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ); // Create the -dealloc summary. - Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc); + Summ = getPersistentSummary(NoRet, Dealloc); addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); // Create the "autorelease" selector. - Summ = getPersistentSummary(E, Autorelease); + Summ = getPersistentSummary(NoRet, Autorelease); addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); // Specially handle NSAutoreleasePool. addInstMethSummary("NSAutoreleasePool", "init", - getPersistentSummary(RetEffect::MakeReceiverAlias(), - NewAutoreleasePool)); + getPersistentSummary(NoRet, NewAutoreleasePool)); // For NSWindow, allocated objects are (initially) self-owned. // FIXME: For now we opt for false negatives with NSWindow, as these objects @@ -1551,7 +1484,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Thus, we need to track an NSWindow's display status. // This is tracked in <rdar://problem/6062711>. // See also http://llvm.org/bugs/show_bug.cgi?id=3714. - RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), + const RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), StopTracking, StopTracking); @@ -1583,13 +1516,6 @@ void RetainSummaryManager::InitializeMethodSummaries() { // exit a method. addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); - // Create NSAssertionHandler summaries. - addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file", - "lineNumber", "description", NULL); - - addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object", - "file", "lineNumber", "description", NULL); - // Create summaries QCRenderer/QCView -createSnapShotImageOfType: addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType", NULL); @@ -1623,26 +1549,27 @@ namespace { class AutoreleaseStack {}; } namespace clang { namespace ento { -template<> struct GRStateTrait<AutoreleaseStack> - : public GRStatePartialTrait<ARStack> { - static inline void* GDMIndex() { return &AutoRBIndex; } +template<> struct ProgramStateTrait<AutoreleaseStack> + : public ProgramStatePartialTrait<ARStack> { + static inline void *GDMIndex() { return &AutoRBIndex; } }; -template<> struct GRStateTrait<AutoreleasePoolContents> - : public GRStatePartialTrait<ARPoolContents> { - static inline void* GDMIndex() { return &AutoRCIndex; } +template<> struct ProgramStateTrait<AutoreleasePoolContents> + : public ProgramStatePartialTrait<ARPoolContents> { + static inline void *GDMIndex() { return &AutoRCIndex; } }; } // end GR namespace } // end clang namespace -static SymbolRef GetCurrentAutoreleasePool(const GRState* state) { +static SymbolRef GetCurrentAutoreleasePool(const ProgramState *state) { ARStack stack = state->get<AutoreleaseStack>(); return stack.isEmpty() ? SymbolRef() : stack.getHead(); } -static const GRState * SendAutorelease(const GRState *state, - ARCounts::Factory &F, SymbolRef sym) { - +static const ProgramState * +SendAutorelease(const ProgramState *state, + ARCounts::Factory &F, + SymbolRef sym) { SymbolRef pool = GetCurrentAutoreleasePool(state); const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool); ARCounts newCnts(0); @@ -1658,196 +1585,11 @@ static const GRState * SendAutorelease(const GRState *state, } //===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// - -namespace { - -class CFRefCount : public TransferFuncs { -public: - class BindingsPrinter : public GRState::Printer { - public: - virtual void Print(llvm::raw_ostream& Out, const GRState* state, - const char* nl, const char* sep); - }; - - typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*> - SummaryLogTy; - - RetainSummaryManager Summaries; - SummaryLogTy SummaryLog; - const LangOptions& LOpts; - ARCounts::Factory ARCountFactory; - - BugType *useAfterRelease, *releaseNotOwned; - BugType *deallocGC, *deallocNotOwned; - BugType *leakWithinFunction, *leakAtReturn; - BugType *overAutorelease; - BugType *returnNotOwnedForOwned; - BugReporter *BR; - - const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E, - RefVal::Kind& hasErr); - - void ProcessNonLeakError(ExplodedNodeSet& Dst, - StmtNodeBuilder& Builder, - const Expr* NodeExpr, SourceRange ErrorRange, - ExplodedNode* Pred, - const GRState* St, - RefVal::Kind hasErr, SymbolRef Sym); - - const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, - llvm::SmallVectorImpl<SymbolRef> &Leaked); - - ExplodedNode* ProcessLeaks(const GRState * state, - llvm::SmallVectorImpl<SymbolRef> &Leaked, - GenericNodeBuilderRefCount &Builder, - ExprEngine &Eng, - ExplodedNode *Pred = 0); - -public: - CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) - : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount), - LOpts(lopts), useAfterRelease(0), releaseNotOwned(0), - deallocGC(0), deallocNotOwned(0), - leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), - returnNotOwnedForOwned(0), BR(0) {} - - virtual ~CFRefCount() {} - - void RegisterChecks(ExprEngine &Eng); - - virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) { - Printers.push_back(new BindingsPrinter()); - } - - bool isGCEnabled() const { return Summaries.isGCEnabled(); } - bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); } - - const LangOptions& getLangOptions() const { return LOpts; } - - const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const { - SummaryLogTy::const_iterator I = SummaryLog.find(N); - return I == SummaryLog.end() ? 0 : I->second; - } - - // Calls. - - void evalSummary(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const Expr* Ex, - const CallOrObjCMessage &callOrMsg, - InstanceReceiver Receiver, - const RetainSummary& Summ, - const MemRegion *Callee, - ExplodedNode* Pred, const GRState *state); - - virtual void evalCall(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const CallExpr* CE, SVal L, - ExplodedNode* Pred); - - - virtual void evalObjCMessage(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - ObjCMessage msg, - ExplodedNode* Pred, - const GRState *state); - // Stores. - virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val); - - // End-of-path. - - virtual void evalEndPath(ExprEngine& Engine, - EndOfFunctionNodeBuilder& Builder); - - virtual void evalDeadSymbols(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - ExplodedNode* Pred, - const GRState* state, - SymbolReaper& SymReaper); - - std::pair<ExplodedNode*, const GRState *> - HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilderRefCount Bd, - ExplodedNode* Pred, ExprEngine &Eng, - SymbolRef Sym, RefVal V, bool &stop); - // Return statements. - - virtual void evalReturn(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - const ReturnStmt* S, - ExplodedNode* Pred); - - void evalReturnWithRetEffect(ExplodedNodeSet& Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - const ReturnStmt* S, - ExplodedNode* Pred, - RetEffect RE, RefVal X, - SymbolRef Sym, const GRState *state); - - - // Assumptions. - - virtual const GRState *evalAssume(const GRState* state, SVal condition, - bool assumption); -}; - -} // end anonymous namespace - -static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, - const GRState *state) { - Out << ' '; - if (Sym) - Out << Sym->getSymbolID(); - else - Out << "<pool>"; - Out << ":{"; - - // Get the contents of the pool. - if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym)) - for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J) - Out << '(' << J.getKey() << ',' << J.getData() << ')'; - - Out << '}'; -} - -void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, - const GRState* state, - const char* nl, const char* sep) { - - RefBindings B = state->get<RefBindings>(); - - if (!B.isEmpty()) - Out << sep << nl; - - for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { - Out << (*I).first << " : "; - (*I).second.print(Out); - Out << nl; - } - - // Print the autorelease stack. - Out << sep << nl << "AR pool stack:"; - ARStack stack = state->get<AutoreleaseStack>(); - - PrintPool(Out, SymbolRef(), state); // Print the caller's pool. - for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I) - PrintPool(Out, *I, state); - - Out << nl; -} - -//===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// - namespace { + typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *> + SummaryLogTy; //===-------------===// // Bug Descriptions. // @@ -1855,35 +1597,30 @@ namespace { class CFRefBug : public BugType { protected: - CFRefCount& TF; - - CFRefBug(CFRefCount* tf, llvm::StringRef name) - : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} + CFRefBug(StringRef name) + : BugType(name, "Memory (Core Foundation/Objective-C)") {} public: - CFRefCount& getTF() { return TF; } - // FIXME: Eventually remove. - virtual const char* getDescription() const = 0; + virtual const char *getDescription() const = 0; virtual bool isLeak() const { return false; } }; class UseAfterRelease : public CFRefBug { public: - UseAfterRelease(CFRefCount* tf) - : CFRefBug(tf, "Use-after-release") {} + UseAfterRelease() : CFRefBug("Use-after-release") {} - const char* getDescription() const { + const char *getDescription() const { return "Reference-counted object is used after it is released"; } }; class BadRelease : public CFRefBug { public: - BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} + BadRelease() : CFRefBug("Bad release") {} - const char* getDescription() const { + const char *getDescription() const { return "Incorrect decrement of the reference count of an object that is " "not owned at this point by the caller"; } @@ -1891,8 +1628,8 @@ namespace { class DeallocGC : public CFRefBug { public: - DeallocGC(CFRefCount *tf) - : CFRefBug(tf, "-dealloc called while using garbage collection") {} + DeallocGC() + : CFRefBug("-dealloc called while using garbage collection") {} const char *getDescription() const { return "-dealloc called while using garbage collection"; @@ -1901,8 +1638,8 @@ namespace { class DeallocNotOwned : public CFRefBug { public: - DeallocNotOwned(CFRefCount *tf) - : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} + DeallocNotOwned() + : CFRefBug("-dealloc sent to non-exclusively owned object") {} const char *getDescription() const { return "-dealloc sent to object that may be referenced elsewhere"; @@ -1911,8 +1648,8 @@ namespace { class OverAutorelease : public CFRefBug { public: - OverAutorelease(CFRefCount *tf) : - CFRefBug(tf, "Object sent -autorelease too many times") {} + OverAutorelease() + : CFRefBug("Object sent -autorelease too many times") {} const char *getDescription() const { return "Object sent -autorelease too many times"; @@ -1921,8 +1658,8 @@ namespace { class ReturnedNotOwnedForOwned : public CFRefBug { public: - ReturnedNotOwnedForOwned(CFRefCount *tf) : - CFRefBug(tf, "Method should return an owned object") {} + ReturnedNotOwnedForOwned() + : CFRefBug("Method should return an owned object") {} const char *getDescription() const { return "Object with a +0 retain count returned to caller where a +1 " @@ -1933,141 +1670,170 @@ namespace { class Leak : public CFRefBug { const bool isReturn; protected: - Leak(CFRefCount* tf, llvm::StringRef name, bool isRet) - : CFRefBug(tf, name), isReturn(isRet) {} + Leak(StringRef name, bool isRet) + : CFRefBug(name), isReturn(isRet) { + // Leaks should not be reported if they are post-dominated by a sink. + setSuppressOnSink(true); + } public: - const char* getDescription() const { return ""; } + const char *getDescription() const { return ""; } bool isLeak() const { return true; } }; class LeakAtReturn : public Leak { public: - LeakAtReturn(CFRefCount* tf, llvm::StringRef name) - : Leak(tf, name, true) {} + LeakAtReturn(StringRef name) + : Leak(name, true) {} }; class LeakWithinFunction : public Leak { public: - LeakWithinFunction(CFRefCount* tf, llvm::StringRef name) - : Leak(tf, name, false) {} + LeakWithinFunction(StringRef name) + : Leak(name, false) {} }; //===---------===// // Bug Reports. // //===---------===// - class CFRefReport : public RangedBugReport { + class CFRefReportVisitor : public BugReporterVisitor { protected: SymbolRef Sym; - const CFRefCount &TF; + const SummaryLogTy &SummaryLog; + bool GCEnabled; + public: - CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym) - : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} + CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log) + : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {} - CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, llvm::StringRef endText) - : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} - - virtual ~CFRefReport() {} - - CFRefBug& getBugType() const { - return (CFRefBug&) RangedBugReport::getBugType(); + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + static int x = 0; + ID.AddPointer(&x); + ID.AddPointer(Sym); } - virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const { - if (!getBugType().isLeak()) - return RangedBugReport::getRanges(); - else - return std::make_pair(ranges_iterator(), ranges_iterator()); - } + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); - SymbolRef getSymbol() const { return Sym; } + virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR); + }; - PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* N); + class CFRefLeakReportVisitor : public CFRefReportVisitor { + public: + CFRefLeakReportVisitor(SymbolRef sym, bool GCEnabled, + const SummaryLogTy &log) + : CFRefReportVisitor(sym, GCEnabled, log) {} - std::pair<const char**,const char**> getExtraDescriptiveText(); + PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR); + }; + + class CFRefReport : public BugReport { + void addGCModeDescription(const LangOptions &LOpts, bool GCEnabled); - PathDiagnosticPiece* VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, - BugReporterContext& BRC); + public: + CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, + const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, + bool registerVisitor = true) + : BugReport(D, D.getDescription(), n) { + if (registerVisitor) + addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log)); + addGCModeDescription(LOpts, GCEnabled); + } + + CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, + const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, + StringRef endText) + : BugReport(D, D.getDescription(), endText, n) { + addVisitor(new CFRefReportVisitor(sym, GCEnabled, Log)); + addGCModeDescription(LOpts, GCEnabled); + } + + virtual std::pair<ranges_iterator, ranges_iterator> getRanges() { + const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType()); + if (!BugTy.isLeak()) + return BugReport::getRanges(); + else + return std::make_pair(ranges_iterator(), ranges_iterator()); + } }; class CFRefLeakReport : public CFRefReport { - SourceLocation AllocSite; const MemRegion* AllocBinding; - public: - CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, - ExprEngine& Eng); - PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* N); + public: + CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, + const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, + ExprEngine &Eng); - SourceLocation getLocation() const { return AllocSite; } + PathDiagnosticLocation getLocation(const SourceManager &SM) const { + assert(Location.isValid()); + return Location; + } }; } // end anonymous namespace - - -static const char* Msgs[] = { - // GC only - "Code is compiled to only use garbage collection", - // No GC. - "Code is compiled to use reference counts", - // Hybrid, with GC. - "Code is compiled to use either garbage collection (GC) or reference counts" - " (non-GC). The bug occurs with GC enabled", - // Hybrid, without GC - "Code is compiled to use either garbage collection (GC) or reference counts" - " (non-GC). The bug occurs in non-GC mode" -}; - -std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() { - CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF(); - - switch (TF.getLangOptions().getGCMode()) { - default: - assert(false); - - case LangOptions::GCOnly: - assert (TF.isGCEnabled()); - return std::make_pair(&Msgs[0], &Msgs[0]+1); - - case LangOptions::NonGC: - assert (!TF.isGCEnabled()); - return std::make_pair(&Msgs[1], &Msgs[1]+1); - - case LangOptions::HybridGC: - if (TF.isGCEnabled()) - return std::make_pair(&Msgs[2], &Msgs[2]+1); - else - return std::make_pair(&Msgs[3], &Msgs[3]+1); +void CFRefReport::addGCModeDescription(const LangOptions &LOpts, + bool GCEnabled) { + const char *GCModeDescription = 0; + + switch (LOpts.getGC()) { + case LangOptions::GCOnly: + assert(GCEnabled); + GCModeDescription = "Code is compiled to only use garbage collection"; + break; + + case LangOptions::NonGC: + assert(!GCEnabled); + GCModeDescription = "Code is compiled to use reference counts"; + break; + + case LangOptions::HybridGC: + if (GCEnabled) { + GCModeDescription = "Code is compiled to use either garbage collection " + "(GC) or reference counts (non-GC). The bug occurs " + "with GC enabled"; + break; + } else { + GCModeDescription = "Code is compiled to use either garbage collection " + "(GC) or reference counts (non-GC). The bug occurs " + "in non-GC mode"; + break; + } } + + assert(GCModeDescription && "invalid/unknown GC mode"); + addExtraText(GCModeDescription); } -static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V, +// FIXME: This should be a method on SmallVector. +static inline bool contains(const SmallVectorImpl<ArgEffect>& V, ArgEffect X) { - for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end(); + for (SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end(); I!=E; ++I) if (*I == X) return true; return false; } -PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, - BugReporterContext& BRC) { +PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { - if (!isa<PostStmt>(N->getLocation())) + if (!isa<StmtPoint>(N->getLocation())) return NULL; // Check if the type state has changed. - const GRState *PrevSt = PrevN->getState(); - const GRState *CurrSt = N->getState(); + const ProgramState *PrevSt = PrevN->getState(); + const ProgramState *CurrSt = N->getState(); const RefVal* CurrT = CurrSt->get<RefBindings>(Sym); if (!CurrT) return NULL; @@ -2083,13 +1849,13 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, // This is the allocation site since the previous node had no bindings // for this symbol. if (!PrevT) { - const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt(); if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); - if (const FunctionDecl* FD = X.getAsFunctionDecl()) - os << "Call to function '" << FD << '\''; + if (const FunctionDecl *FD = X.getAsFunctionDecl()) + os << "Call to function '" << *FD << '\''; else os << "function call"; } @@ -2110,7 +1876,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, if (CurrV.isOwned()) { os << "+1 retain count"; - if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) { + if (GCEnabled) { assert(CurrV.getObjKind() == RetEffect::CF); os << ". " "Core Foundation objects are not automatically garbage collected."; @@ -2121,19 +1887,20 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, os << "+0 retain count"; } - PathDiagnosticLocation Pos(S, BRC.getSourceManager()); + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), + N->getLocationContext()); return new PathDiagnosticEventPiece(Pos, os.str()); } // Gather up the effects that were performed on the object at this // program point - llvm::SmallVector<ArgEffect, 2> AEffects; + SmallVector<ArgEffect, 2> AEffects; - if (const RetainSummary *Summ = - TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) { + const ExplodedNode *OrigNode = BRC.getNodeResolver().getOriginalNode(N); + if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) { // We only have summaries attached to nodes after evaluating CallExpr and // ObjCMessageExprs. - const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt(); if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { // Iterate through the parameter expressions and see if the symbol @@ -2166,7 +1933,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, RefVal PrevV = *PrevT; // Specially handle -dealloc. - if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) { + if (!GCEnabled && contains(AEffects, Dealloc)) { // Determine if the object's reference count was pushed to zero. assert(!(PrevV == CurrV) && "The typestate *must* have changed."); // We may not have transitioned to 'release' if we hit an error. @@ -2181,16 +1948,15 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, // Specially handle CFMakeCollectable and friends. if (contains(AEffects, MakeCollectable)) { // Get the name of the function. - const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); + const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt(); SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee()); - const FunctionDecl* FD = X.getAsFunctionDecl(); - const std::string& FName = FD->getNameAsString(); + const FunctionDecl *FD = X.getAsFunctionDecl(); - if (TF.isGCEnabled()) { + if (GCEnabled) { // Determine if the object's reference count was pushed to zero. assert(!(PrevV == CurrV) && "The typestate *must* have changed."); - os << "In GC mode a call to '" << FName + os << "In GC mode a call to '" << *FD << "' decrements an object's retain count and registers the " "object with the garbage collector. "; @@ -2205,7 +1971,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, << '.'; } else - os << "When GC is not enabled a call to '" << FName + os << "When GC is not enabled a call to '" << *FD << "' has no effect on its argument."; // Nothing more to say. @@ -2237,7 +2003,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, os << " The object now has a +" << Count << " retain count."; if (PrevV.getKind() == RefVal::Released) { - assert(TF.isGCEnabled() && CurrV.getCount() > 0); + assert(GCEnabled && CurrV.getCount() > 0); os << " The object is not eligible for garbage collection until the " "retain count reaches 0 again."; } @@ -2262,11 +2028,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } // Emit any remaining diagnostics for the argument effects (if any). - for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(), + for (SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(), E=AEffects.end(); I != E; ++I) { // A bunch of things have alternate behavior under GC. - if (TF.isGCEnabled()) + if (GCEnabled) switch (*I) { default: break; case Autorelease: @@ -2285,15 +2051,16 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, if (os.str().empty()) return 0; // We have nothing to say! - const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt(); - PathDiagnosticLocation Pos(S, BRC.getSourceManager()); - PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str()); + const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt(); + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), + N->getLocationContext()); + PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Pos, os.str()); // Add the range by scanning the children of the statement for any bindings // to Sym. for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) - if (const Expr* Exp = dyn_cast_or_null<Expr>(*I)) + if (const Expr *Exp = dyn_cast_or_null<Expr>(*I)) if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) { P->addRange(Exp->getSourceRange()); break; @@ -2335,16 +2102,16 @@ namespace { } static std::pair<const ExplodedNode*,const MemRegion*> -GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, +GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, SymbolRef Sym) { // Find both first node that referred to the tracked symbol and the // memory location that value was store to. - const ExplodedNode* Last = N; + const ExplodedNode *Last = N; const MemRegion* FirstBinding = 0; while (N) { - const GRState* St = N->getState(); + const ProgramState *St = N->getState(); RefBindings B = St->get<RefBindings>(); if (!B.lookup(Sym)) @@ -2362,17 +2129,19 @@ GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, } PathDiagnosticPiece* -CFRefReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndN) { +CFRefReportVisitor::getEndPath(BugReporterContext &BRC, + const ExplodedNode *EndN, + BugReport &BR) { // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. BRC.addNotableSymbol(Sym); - return RangedBugReport::getEndPath(BRC, EndN); + return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); } PathDiagnosticPiece* -CFRefLeakReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndN){ +CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, + const ExplodedNode *EndN, + BugReport &BR) { // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. @@ -2381,41 +2150,19 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object // is stored to. - const ExplodedNode* AllocNode = 0; + const ExplodedNode *AllocNode = 0; const MemRegion* FirstBinding = 0; llvm::tie(AllocNode, FirstBinding) = GetAllocationSite(BRC.getStateManager(), EndN, Sym); - SourceManager& SMgr = BRC.getSourceManager(); + SourceManager& SM = BRC.getSourceManager(); // Compute an actual location for the leak. Sometimes a leak doesn't // occur at an actual statement (e.g., transition between blocks; end // of function) so we need to walk the graph and compute a real location. - const ExplodedNode* LeakN = EndN; - PathDiagnosticLocation L; - - while (LeakN) { - ProgramPoint P = LeakN->getLocation(); - - if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { - L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr); - break; - } - else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { - if (const Stmt* Term = BE->getSrc()->getTerminator()) { - L = PathDiagnosticLocation(Term->getLocStart(), SMgr); - break; - } - } - - LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin()); - } - - if (!L.isValid()) { - const Decl &D = EndN->getCodeDecl(); - L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr); - } + const ExplodedNode *LeakN = EndN; + PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM); std::string sbuf; llvm::raw_string_ostream os(sbuf); @@ -2454,7 +2201,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, } } else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { - ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); + ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); os << " and returned from method '" << MD.getSelector().getAsString() << "' is potentially leaked when using garbage collection. Callers " "of this method do not expect a returned object with a +1 retain " @@ -2468,10 +2215,11 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, return new PathDiagnosticEventPiece(L, os.str()); } -CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, - SymbolRef sym, ExprEngine& Eng) -: CFRefReport(D, tf, n, sym) { +CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, + bool GCEnabled, const SummaryLogTy &Log, + ExplodedNode *n, SymbolRef sym, + ExprEngine &Eng) +: CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were @@ -2481,41 +2229,418 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, // Note that this is *not* the trimmed graph; we are guaranteed, however, // that all ancestor nodes that represent the allocation site have the // same SourceLocation. - const ExplodedNode* AllocNode = 0; + const ExplodedNode *AllocNode = 0; + + const SourceManager& SMgr = Eng.getContext().getSourceManager(); llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding. - GetAllocationSite(Eng.getStateManager(), getErrorNode(), getSymbol()); + GetAllocationSite(Eng.getStateManager(), getErrorNode(), sym); // Get the SourceLocation for the allocation site. ProgramPoint P = AllocNode->getLocation(); - AllocSite = cast<PostStmt>(P).getStmt()->getLocStart(); - + const Stmt *AllocStmt = cast<PostStmt>(P).getStmt(); + Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, + n->getLocationContext()); // Fill in the description of the bug. Description.clear(); llvm::raw_string_ostream os(Description); - SourceManager& SMgr = Eng.getContext().getSourceManager(); - unsigned AllocLine = SMgr.getInstantiationLineNumber(AllocSite); + unsigned AllocLine = SMgr.getExpansionLineNumber(AllocStmt->getLocStart()); os << "Potential leak "; - if (tf.isGCEnabled()) { + if (GCEnabled) os << "(when using garbage collection) "; - } os << "of an object allocated on line " << AllocLine; // FIXME: AllocBinding doesn't get populated for RegionStore yet. if (AllocBinding) os << " and stored into '" << AllocBinding->getString() << '\''; + + addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log)); } //===----------------------------------------------------------------------===// // Main checker logic. //===----------------------------------------------------------------------===// +namespace { +class RetainCountChecker + : public Checker< check::Bind, + check::DeadSymbols, + check::EndAnalysis, + check::EndPath, + check::PostStmt<BlockExpr>, + check::PostStmt<CastExpr>, + check::PostStmt<CallExpr>, + check::PostStmt<CXXConstructExpr>, + check::PostObjCMessage, + check::PreStmt<ReturnStmt>, + check::RegionChanges, + eval::Assume, + eval::Call > { + mutable llvm::OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned; + mutable llvm::OwningPtr<CFRefBug> deallocGC, deallocNotOwned; + mutable llvm::OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned; + mutable llvm::OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn; + mutable llvm::OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC; + + typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap; + + // This map is only used to ensure proper deletion of any allocated tags. + mutable SymbolTagMap DeadSymbolTags; + + mutable llvm::OwningPtr<RetainSummaryManager> Summaries; + mutable llvm::OwningPtr<RetainSummaryManager> SummariesGC; + + mutable ARCounts::Factory ARCountFactory; + + mutable SummaryLogTy SummaryLog; + mutable bool ShouldResetSummaryLog; + +public: + RetainCountChecker() : ShouldResetSummaryLog(false) {} + + virtual ~RetainCountChecker() { + DeleteContainerSeconds(DeadSymbolTags); + } + + void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng) const { + // FIXME: This is a hack to make sure the summary log gets cleared between + // analyses of different code bodies. + // + // Why is this necessary? Because a checker's lifetime is tied to a + // translation unit, but an ExplodedGraph's lifetime is just a code body. + // Once in a blue moon, a new ExplodedNode will have the same address as an + // old one with an associated summary, and the bug report visitor gets very + // confused. (To make things worse, the summary lifetime is currently also + // tied to a code body, so we get a crash instead of incorrect results.) + // + // Why is this a bad solution? Because if the lifetime of the ExplodedGraph + // changes, things will start going wrong again. Really the lifetime of this + // log needs to be tied to either the specific nodes in it or the entire + // ExplodedGraph, not to a specific part of the code being analyzed. + // + // (Also, having stateful local data means that the same checker can't be + // used from multiple threads, but a lot of checkers have incorrect + // assumptions about that anyway. So that wasn't a priority at the time of + // this fix.) + // + // This happens at the end of analysis, but bug reports are emitted /after/ + // this point. So we can't just clear the summary log now. Instead, we mark + // that the next time we access the summary log, it should be cleared. + + // If we never reset the summary log during /this/ code body analysis, + // there were no new summaries. There might still have been summaries from + // the /last/ analysis, so clear them out to make sure the bug report + // visitors don't get confused. + if (ShouldResetSummaryLog) + SummaryLog.clear(); + + ShouldResetSummaryLog = !SummaryLog.empty(); + } + + CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts, + bool GCEnabled) const { + if (GCEnabled) { + if (!leakWithinFunctionGC) + leakWithinFunctionGC.reset(new LeakWithinFunction("Leak of object when " + "using garbage " + "collection")); + return leakWithinFunctionGC.get(); + } else { + if (!leakWithinFunction) { + if (LOpts.getGC() == LangOptions::HybridGC) { + leakWithinFunction.reset(new LeakWithinFunction("Leak of object when " + "not using garbage " + "collection (GC) in " + "dual GC/non-GC " + "code")); + } else { + leakWithinFunction.reset(new LeakWithinFunction("Leak")); + } + } + return leakWithinFunction.get(); + } + } + + CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const { + if (GCEnabled) { + if (!leakAtReturnGC) + leakAtReturnGC.reset(new LeakAtReturn("Leak of returned object when " + "using garbage collection")); + return leakAtReturnGC.get(); + } else { + if (!leakAtReturn) { + if (LOpts.getGC() == LangOptions::HybridGC) { + leakAtReturn.reset(new LeakAtReturn("Leak of returned object when " + "not using garbage collection " + "(GC) in dual GC/non-GC code")); + } else { + leakAtReturn.reset(new LeakAtReturn("Leak of returned object")); + } + } + return leakAtReturn.get(); + } + } + + RetainSummaryManager &getSummaryManager(ASTContext &Ctx, + bool GCEnabled) const { + // FIXME: We don't support ARC being turned on and off during one analysis. + // (nor, for that matter, do we support changing ASTContexts) + bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount; + if (GCEnabled) { + if (!SummariesGC) + SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled)); + else + assert(SummariesGC->isARCEnabled() == ARCEnabled); + return *SummariesGC; + } else { + if (!Summaries) + Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled)); + else + assert(Summaries->isARCEnabled() == ARCEnabled); + return *Summaries; + } + } + + RetainSummaryManager &getSummaryManager(CheckerContext &C) const { + return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled()); + } + + void printState(raw_ostream &Out, const ProgramState *State, + const char *NL, const char *Sep) const; + + void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; + void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; + void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; + + void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const; + void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const; + void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call, + CheckerContext &C) const; + + bool evalCall(const CallExpr *CE, CheckerContext &C) const; + + const ProgramState *evalAssume(const ProgramState *state, SVal Cond, + bool Assumption) const; + + const ProgramState * + checkRegionChanges(const ProgramState *state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions) const; + + bool wantsRegionChangeUpdate(const ProgramState *state) const { + return true; + } + + void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; + void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, + ExplodedNode *Pred, RetEffect RE, RefVal X, + SymbolRef Sym, const ProgramState *state) const; + + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const; + + const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym, + RefVal V, ArgEffect E, RefVal::Kind &hasErr, + CheckerContext &C) const; + + void processNonLeakError(const ProgramState *St, SourceRange ErrorRange, + RefVal::Kind ErrorKind, SymbolRef Sym, + CheckerContext &C) const; + + const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const; + + const ProgramState *handleSymbolDeath(const ProgramState *state, + SymbolRef sid, RefVal V, + SmallVectorImpl<SymbolRef> &Leaked) const; + + std::pair<ExplodedNode *, const ProgramState *> + handleAutoreleaseCounts(const ProgramState *state, + GenericNodeBuilderRefCount Bd, ExplodedNode *Pred, + ExprEngine &Eng, SymbolRef Sym, RefVal V) const; + + ExplodedNode *processLeaks(const ProgramState *state, + SmallVectorImpl<SymbolRef> &Leaked, + GenericNodeBuilderRefCount &Builder, + ExprEngine &Eng, + ExplodedNode *Pred = 0) const; +}; +} // end anonymous namespace + +namespace { +class StopTrackingCallback : public SymbolVisitor { + const ProgramState *state; +public: + StopTrackingCallback(const ProgramState *st) : state(st) {} + const ProgramState *getState() const { return state; } + + bool VisitSymbol(SymbolRef sym) { + state = state->remove<RefBindings>(sym); + return true; + } +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Handle statements that may have an effect on refcounts. +//===----------------------------------------------------------------------===// + +void RetainCountChecker::checkPostStmt(const BlockExpr *BE, + CheckerContext &C) const { + + // Scan the BlockDecRefExprs for any object the retain count checker + // may be tracking. + if (!BE->getBlockDecl()->hasCaptures()) + return; + + const ProgramState *state = C.getState(); + const BlockDataRegion *R = + cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); + + BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), + E = R->referenced_vars_end(); + + if (I == E) + return; + + // FIXME: For now we invalidate the tracking of all symbols passed to blocks + // via captured variables, even though captured variables result in a copy + // and in implicit increment/decrement of a retain count. + SmallVector<const MemRegion*, 10> Regions; + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); + + for ( ; I != E; ++I) { + const VarRegion *VR = *I; + if (VR->getSuperRegion() == R) { + VR = MemMgr.getVarRegion(VR->getDecl(), LC); + } + Regions.push_back(VR); + } + + state = + state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), + Regions.data() + Regions.size()).getState(); + C.addTransition(state); +} + +void RetainCountChecker::checkPostStmt(const CastExpr *CE, + CheckerContext &C) const { + const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); + if (!BE) + return; + + ArgEffect AE = IncRef; + + switch (BE->getBridgeKind()) { + case clang::OBC_Bridge: + // Do nothing. + return; + case clang::OBC_BridgeRetained: + AE = IncRef; + break; + case clang::OBC_BridgeTransfer: + AE = DecRefBridgedTransfered; + break; + } + + const ProgramState *state = C.getState(); + SymbolRef Sym = state->getSVal(CE).getAsLocSymbol(); + if (!Sym) + return; + const RefVal* T = state->get<RefBindings>(Sym); + if (!T) + return; + + RefVal::Kind hasErr = (RefVal::Kind) 0; + state = updateSymbol(state, Sym, *T, AE, hasErr, C); + + if (hasErr) { + // FIXME: If we get an error during a bridge cast, should we report it? + // Should we assert that there is no error? + return; + } + + C.generateNode(state); +} + +void RetainCountChecker::checkPostStmt(const CallExpr *CE, + CheckerContext &C) const { + // Get the callee. + const ProgramState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + RetainSummaryManager &Summaries = getSummaryManager(C); + const RetainSummary *Summ = 0; + + // FIXME: Better support for blocks. For now we stop tracking anything + // that is passed to blocks. + // FIXME: Need to handle variables that are "captured" by the block. + if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { + Summ = Summaries.getPersistentStopSummary(); + } else if (const FunctionDecl *FD = L.getAsFunctionDecl()) { + Summ = Summaries.getSummary(FD); + } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { + if (const CXXMethodDecl *MD = me->getMethodDecl()) + Summ = Summaries.getSummary(MD); + } + + if (!Summ) + Summ = Summaries.getDefaultSummary(); + + checkSummary(*Summ, CallOrObjCMessage(CE, state), C); +} + +void RetainCountChecker::checkPostStmt(const CXXConstructExpr *CE, + CheckerContext &C) const { + const CXXConstructorDecl *Ctor = CE->getConstructor(); + if (!Ctor) + return; + + RetainSummaryManager &Summaries = getSummaryManager(C); + const RetainSummary *Summ = Summaries.getSummary(Ctor); + + // If we didn't get a summary, this constructor doesn't affect retain counts. + if (!Summ) + return; + + const ProgramState *state = C.getState(); + checkSummary(*Summ, CallOrObjCMessage(CE, state), C); +} + +void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg, + CheckerContext &C) const { + const ProgramState *state = C.getState(); + ExplodedNode *Pred = C.getPredecessor(); + + RetainSummaryManager &Summaries = getSummaryManager(C); + + const RetainSummary *Summ; + if (Msg.isInstanceMessage()) { + const LocationContext *LC = Pred->getLocationContext(); + Summ = Summaries.getInstanceMethodSummary(Msg, state, LC); + } else { + Summ = Summaries.getClassMethodSummary(Msg); + } + + // If we didn't get a summary, this message doesn't affect retain counts. + if (!Summ) + return; + + checkSummary(*Summ, CallOrObjCMessage(Msg, state), C); +} + /// GetReturnType - Used to get the return type of a message expression or /// function call with the intention of affixing that type to a tracked symbol. /// While the the return type can be queried directly from RetEx, when /// invoking class methods we augment to the return type to be that of /// a pointer to the class (as opposed it just being id). -static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { +// FIXME: We may be able to do this with related result types instead. +// This function is probably overestimating. +static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { QualType RetTy = RetE->getType(); // If RetE is not a message expression just return its type. // If RetE is a message expression, return its types if it is something @@ -2536,167 +2661,43 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { return RetTy; } - -// HACK: Symbols that have ref-count state that are referenced directly -// (not as structure or array elements, or via bindings) by an argument -// should not have their ref-count state stripped after we have -// done an invalidation pass. -// -// FIXME: This is a global to currently share between CFRefCount and -// RetainReleaseChecker. Eventually all functionality in CFRefCount should -// be migrated to RetainReleaseChecker, and we can make this a non-global. -llvm::DenseSet<SymbolRef> WhitelistedSymbols; -namespace { -struct ResetWhiteList { - ResetWhiteList() {} - ~ResetWhiteList() { WhitelistedSymbols.clear(); } -}; -} - -void CFRefCount::evalSummary(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const Expr* Ex, - const CallOrObjCMessage &callOrMsg, - InstanceReceiver Receiver, - const RetainSummary& Summ, - const MemRegion *Callee, - ExplodedNode* Pred, const GRState *state) { +void RetainCountChecker::checkSummary(const RetainSummary &Summ, + const CallOrObjCMessage &CallOrMsg, + CheckerContext &C) const { + const ProgramState *state = C.getState(); // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; SourceRange ErrorRange; SymbolRef ErrorSym = 0; - llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate; - - // Use RAII to make sure the whitelist is properly cleared. - ResetWhiteList resetWhiteList; + for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { + SVal V = CallOrMsg.getArgSVal(idx); - // Invalidate all instance variables of the receiver of a message. - // FIXME: We should be able to do better with inter-procedural analysis. - if (Receiver) { - SVal V = Receiver.getSValAsScalarOrLoc(state); if (SymbolRef Sym = V.getAsLocSymbol()) { - if (state->get<RefBindings>(Sym)) - WhitelistedSymbols.insert(Sym); - } - if (const MemRegion *region = V.getAsRegion()) - RegionsToInvalidate.push_back(region); - } - - // Invalidate all instance variables for the callee of a C++ method call. - // FIXME: We should be able to do better with inter-procedural analysis. - // FIXME: we can probably do better for const versus non-const methods. - if (callOrMsg.isCXXCall()) { - if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion()) - RegionsToInvalidate.push_back(callee); - } - - for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) { - SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx); - SymbolRef Sym = V.getAsLocSymbol(); - - if (Sym) - if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) { - WhitelistedSymbols.insert(Sym); - state = Update(state, Sym, *T, Summ.getArg(idx), hasErr); + if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) { + state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C); if (hasErr) { - ErrorRange = callOrMsg.getArgSourceRange(idx); + ErrorRange = CallOrMsg.getArgSourceRange(idx); ErrorSym = Sym; break; } } - - tryAgain: - if (isa<Loc>(V)) { - if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) { - if (Summ.getArg(idx) == DoNothingByRef) - continue; - - // Invalidate the value of the variable passed by reference. - const MemRegion *R = MR->getRegion(); - - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // approriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralOrEnumerationType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || - isa<ObjCIvarRegion>(superReg)) - R = cast<TypedRegion>(superReg); - } - // FIXME: What about layers of ElementRegions? - } - - // Mark this region for invalidation. We batch invalidate regions - // below for efficiency. - RegionsToInvalidate.push_back(R); - continue; - } - else { - // Nuke all other arguments passed by reference. - // FIXME: is this necessary or correct? This handles the non-Region - // cases. Is it ever valid to store to these? - state = state->unbindLoc(cast<Loc>(V)); - } } - else if (isa<nonloc::LocAsInteger>(V)) { - // If we are passing a location wrapped as an integer, unwrap it and - // invalidate the values referred by the location. - V = cast<nonloc::LocAsInteger>(V).getLoc(); - goto tryAgain; - } - } - - // Block calls result in all captured values passed-via-reference to be - // invalidated. - if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) { - RegionsToInvalidate.push_back(BR); } - // Invalidate regions we designed for invalidation use the batch invalidation - // API. - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned Count = Builder.getCurrentBlockCount(); - StoreManager::InvalidatedSymbols IS; - - // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate - // global variables. - // NOTE: RetainReleaseChecker handles the actual invalidation of symbols. - state = - state->invalidateRegions(RegionsToInvalidate.data(), - RegionsToInvalidate.data() + - RegionsToInvalidate.size(), - Ex, Count, &IS, - /* invalidateGlobals = */ - Eng.doesInvalidateGlobals(callOrMsg)); - // Evaluate the effect on the message receiver. - if (!ErrorRange.isValid() && Receiver) { - SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol(); - if (Sym) { - if (const RefVal* T = state->get<RefBindings>(Sym)) { - state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr); + bool ReceiverIsTracked = false; + if (!hasErr && CallOrMsg.isObjCMessage()) { + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC); + if (SymbolRef Sym = Receiver.getAsLocSymbol()) { + if (const RefVal *T = state->get<RefBindings>(Sym)) { + ReceiverIsTracked = true; + state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), + hasErr, C); if (hasErr) { - ErrorRange = Receiver.getSourceRange(); + ErrorRange = CallOrMsg.getReceiverSourceRange(); ErrorSym = Sym; } } @@ -2705,8 +2706,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, // Process any errors. if (hasErr) { - ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state, - hasErr, ErrorSym); + processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C); return; } @@ -2714,75 +2714,34 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, RetEffect RE = Summ.getRetEffect(); if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { - bool found = false; - if (Receiver) { - SVal V = Receiver.getSValAsScalarOrLoc(state); - if (SymbolRef Sym = V.getAsLocSymbol()) - if (state->get<RefBindings>(Sym)) { - found = true; - RE = Summaries.getObjAllocRetEffect(); - } - } // FIXME: Otherwise, this is a send-to-super instance message. - if (!found) + if (ReceiverIsTracked) + RE = getSummaryManager(C).getObjAllocRetEffect(); + else RE = RetEffect::MakeNoRet(); } switch (RE.getKind()) { default: - assert (false && "Unhandled RetEffect."); break; - - case RetEffect::NoRet: { - // Make up a symbol for the return value (not reference counted). - // FIXME: Most of this logic is not specific to the retain/release - // checker. - - // FIXME: We eventually should handle structs and other compound types - // that are returned by value. - - // Use the result type from callOrMsg as it automatically adjusts - // for methods/functions that return references. - QualType resultTy = callOrMsg.getResultType(Eng.getContext()); - if (Loc::isLocType(resultTy) || - (resultTy->isIntegerType() && resultTy->isScalarType())) { - unsigned Count = Builder.getCurrentBlockCount(); - SValBuilder &svalBuilder = Eng.getSValBuilder(); - SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count); - state = state->BindExpr(Ex, X, false); - } - - break; - } - - case RetEffect::Alias: { - unsigned idx = RE.getIndex(); - assert (idx < callOrMsg.getNumArgs()); - SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx); - state = state->BindExpr(Ex, V, false); - break; - } + llvm_unreachable("Unhandled RetEffect."); break; - case RetEffect::ReceiverAlias: { - assert(Receiver); - SVal V = Receiver.getSValAsScalarOrLoc(state); - state = state->BindExpr(Ex, V, false); + case RetEffect::NoRet: + // No work necessary. break; - } case RetEffect::OwnedAllocatedSymbol: case RetEffect::OwnedSymbol: { - unsigned Count = Builder.getCurrentBlockCount(); - SValBuilder &svalBuilder = Eng.getSValBuilder(); - SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count); + SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol(); + if (!Sym) + break; // Use the result type from callOrMsg as it automatically adjusts - // for methods/functions that return references. - QualType resultTy = callOrMsg.getResultType(Eng.getContext()); + // for methods/functions that return references. + QualType ResultTy = CallOrMsg.getResultType(C.getASTContext()); state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(), - resultTy)); - state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false); + ResultTy)); // FIXME: Add a flag to the checker where allocations are assumed to - // *not fail. + // *not* fail. (The code below is out-of-date, though.) #if 0 if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) { bool isFeasible; @@ -2797,151 +2756,324 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, case RetEffect::GCNotOwnedSymbol: case RetEffect::ARCNotOwnedSymbol: case RetEffect::NotOwnedSymbol: { - unsigned Count = Builder.getCurrentBlockCount(); - SValBuilder &svalBuilder = Eng.getSValBuilder(); - SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, svalBuilder.getContext()); + const Expr *Ex = CallOrMsg.getOriginExpr(); + SymbolRef Sym = state->getSVal(Ex).getAsSymbol(); + if (!Sym) + break; + + // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *. + QualType ResultTy = GetReturnType(Ex, C.getASTContext()); state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(), - RetT)); - state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false); + ResultTy)); break; } } - // Generate a sink node if we are at the end of a path. - ExplodedNode *NewNode = - Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state) - : Builder.MakeNode(Dst, Ex, Pred, state); + // This check is actually necessary; otherwise the statement builder thinks + // we've hit a previously-found path. + // Normally addTransition takes care of this, but we want the node pointer. + ExplodedNode *NewNode; + if (state == C.getState()) { + NewNode = C.getPredecessor(); + } else { + NewNode = C.generateNode(state); + } - // Annotate the edge with summary we used. - if (NewNode) SummaryLog[NewNode] = &Summ; + // Annotate the node with summary we used. + if (NewNode) { + // FIXME: This is ugly. See checkEndAnalysis for why it's necessary. + if (ShouldResetSummaryLog) { + SummaryLog.clear(); + ShouldResetSummaryLog = false; + } + SummaryLog[NewNode] = &Summ; + } } -void CFRefCount::evalCall(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const CallExpr* CE, SVal L, - ExplodedNode* Pred) { - - RetainSummary *Summ = 0; +const ProgramState * +RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym, + RefVal V, ArgEffect E, RefVal::Kind &hasErr, + CheckerContext &C) const { + // In GC mode [... release] and [... retain] do nothing. + // In ARC mode they shouldn't exist at all, but we just ignore them. + bool IgnoreRetainMsg = C.isObjCGCEnabled(); + if (!IgnoreRetainMsg) + IgnoreRetainMsg = (bool)C.getASTContext().getLangOptions().ObjCAutoRefCount; - // FIXME: Better support for blocks. For now we stop tracking anything - // that is passed to blocks. - // FIXME: Need to handle variables that are "captured" by the block. - if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { - Summ = Summaries.getPersistentStopSummary(); - } - else if (const FunctionDecl* FD = L.getAsFunctionDecl()) { - Summ = Summaries.getSummary(FD); + switch (E) { + default: break; + case IncRefMsg: E = IgnoreRetainMsg ? DoNothing : IncRef; break; + case DecRefMsg: E = IgnoreRetainMsg ? DoNothing : DecRef; break; + case MakeCollectable: E = C.isObjCGCEnabled() ? DecRef : DoNothing; break; + case NewAutoreleasePool: E = C.isObjCGCEnabled() ? DoNothing : + NewAutoreleasePool; break; } - else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { - if (const CXXMethodDecl *MD = me->getMethodDecl()) - Summ = Summaries.getSummary(MD); - else - Summ = Summaries.getDefaultSummary(); + + // Handle all use-after-releases. + if (!C.isObjCGCEnabled() && V.getKind() == RefVal::Released) { + V = V ^ RefVal::ErrorUseAfterRelease; + hasErr = V.getKind(); + return state->set<RefBindings>(sym, V); } - else - Summ = Summaries.getDefaultSummary(); - assert(Summ); - evalSummary(Dst, Eng, Builder, CE, - CallOrObjCMessage(CE, Builder.GetState(Pred)), - InstanceReceiver(), *Summ,L.getAsRegion(), - Pred, Builder.GetState(Pred)); -} + switch (E) { + case DecRefMsg: + case IncRefMsg: + case MakeCollectable: + llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted"); + return state; -void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - ObjCMessage msg, - ExplodedNode* Pred, - const GRState *state) { - RetainSummary *Summ = - msg.isInstanceMessage() - ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext()) - : Summaries.getClassMethodSummary(msg); - - assert(Summ && "RetainSummary is null"); - evalSummary(Dst, Eng, Builder, msg.getOriginExpr(), - CallOrObjCMessage(msg, Builder.GetState(Pred)), - InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL, - Pred, state); -} + case Dealloc: + // Any use of -dealloc in GC is *bad*. + if (C.isObjCGCEnabled()) { + V = V ^ RefVal::ErrorDeallocGC; + hasErr = V.getKind(); + break; + } -namespace { -class StopTrackingCallback : public SymbolVisitor { - const GRState *state; -public: - StopTrackingCallback(const GRState *st) : state(st) {} - const GRState *getState() const { return state; } + switch (V.getKind()) { + default: + llvm_unreachable("Invalid RefVal state for an explicit dealloc."); + break; + case RefVal::Owned: + // The object immediately transitions to the released state. + V = V ^ RefVal::Released; + V.clearCounts(); + return state->set<RefBindings>(sym, V); + case RefVal::NotOwned: + V = V ^ RefVal::ErrorDeallocNotOwned; + hasErr = V.getKind(); + break; + } + break; - bool VisitSymbol(SymbolRef sym) { - state = state->remove<RefBindings>(sym); - return true; - } -}; -} // end anonymous namespace + case NewAutoreleasePool: + assert(!C.isObjCGCEnabled()); + return state->add<AutoreleaseStack>(sym); + case MayEscape: + if (V.getKind() == RefVal::Owned) { + V = V ^ RefVal::NotOwned; + break; + } -void CFRefCount::evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) { - // Are we storing to something that causes the value to "escape"? - bool escapes = false; + // Fall-through. - // A value escapes in three possible cases (this may change): - // - // (1) we are binding to something that is not a memory region. - // (2) we are binding to a memregion that does not have stack storage - // (3) we are binding to a memregion with stack storage that the store - // does not understand. - const GRState *state = B.getState(); + case DoNothing: + return state; - if (!isa<loc::MemRegionVal>(location)) - escapes = true; - else { - const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion(); - escapes = !R->hasStackStorage(); + case Autorelease: + if (C.isObjCGCEnabled()) + return state; - if (!escapes) { - // To test (3), generate a new state with the binding removed. If it is - // the same state, then it escapes (since the store cannot represent - // the binding). - escapes = (state == (state->bindLoc(cast<Loc>(location), UnknownVal()))); - } + // Update the autorelease counts. + state = SendAutorelease(state, ARCountFactory, sym); + V = V.autorelease(); + break; + + case StopTracking: + return state->remove<RefBindings>(sym); + + case IncRef: + switch (V.getKind()) { + default: + llvm_unreachable("Invalid RefVal state for a retain."); + break; + case RefVal::Owned: + case RefVal::NotOwned: + V = V + 1; + break; + case RefVal::Released: + // Non-GC cases are handled above. + assert(C.isObjCGCEnabled()); + V = (V ^ RefVal::Owned) + 1; + break; + } + break; + + case SelfOwn: + V = V ^ RefVal::NotOwned; + // Fall-through. + case DecRef: + case DecRefBridgedTransfered: + switch (V.getKind()) { + default: + // case 'RefVal::Released' handled above. + llvm_unreachable("Invalid RefVal state for a release."); + break; + + case RefVal::Owned: + assert(V.getCount() > 0); + if (V.getCount() == 1) + V = V ^ (E == DecRefBridgedTransfered ? + RefVal::NotOwned : RefVal::Released); + V = V - 1; + break; + + case RefVal::NotOwned: + if (V.getCount() > 0) + V = V - 1; + else { + V = V ^ RefVal::ErrorReleaseNotOwned; + hasErr = V.getKind(); + } + break; + + case RefVal::Released: + // Non-GC cases are handled above. + assert(C.isObjCGCEnabled()); + V = V ^ RefVal::ErrorUseAfterRelease; + hasErr = V.getKind(); + break; + } + break; } + return state->set<RefBindings>(sym, V); +} - // If our store can represent the binding and we aren't storing to something - // that doesn't have local storage then just return and have the simulation - // state continue as is. - if (!escapes) +void RetainCountChecker::processNonLeakError(const ProgramState *St, + SourceRange ErrorRange, + RefVal::Kind ErrorKind, + SymbolRef Sym, + CheckerContext &C) const { + ExplodedNode *N = C.generateSink(St); + if (!N) + return; + + CFRefBug *BT; + switch (ErrorKind) { + default: + llvm_unreachable("Unhandled error."); return; + case RefVal::ErrorUseAfterRelease: + if (!useAfterRelease) + useAfterRelease.reset(new UseAfterRelease()); + BT = &*useAfterRelease; + break; + case RefVal::ErrorReleaseNotOwned: + if (!releaseNotOwned) + releaseNotOwned.reset(new BadRelease()); + BT = &*releaseNotOwned; + break; + case RefVal::ErrorDeallocGC: + if (!deallocGC) + deallocGC.reset(new DeallocGC()); + BT = &*deallocGC; + break; + case RefVal::ErrorDeallocNotOwned: + if (!deallocNotOwned) + deallocNotOwned.reset(new DeallocNotOwned()); + BT = &*deallocNotOwned; + break; + } - // Otherwise, find all symbols referenced by 'val' that we are tracking - // and stop tracking them. - B.MakeNode(state->scanReachableSymbols<StopTrackingCallback>(val).getState()); + assert(BT); + CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOptions(), + C.isObjCGCEnabled(), SummaryLog, + N, Sym); + report->addRange(ErrorRange); + C.EmitReport(report); } - // Return statements. +//===----------------------------------------------------------------------===// +// Handle the return values of retain-count-related functions. +//===----------------------------------------------------------------------===// + +bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { + // Get the callee. We're only interested in simple C functions. + const ProgramState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); -void CFRefCount::evalReturn(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - const ReturnStmt* S, - ExplodedNode* Pred) { + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + IdentifierInfo *II = FD->getIdentifier(); + if (!II) + return false; + + // For now, we're only handling the functions that return aliases of their + // arguments: CFRetain and CFMakeCollectable (and their families). + // Eventually we should add other functions we can model entirely, + // such as CFRelease, which don't invalidate their arguments or globals. + if (CE->getNumArgs() != 1) + return false; + + // Get the name of the function. + StringRef FName = II->getName(); + FName = FName.substr(FName.find_first_not_of('_')); + + // See if it's one of the specific functions we know how to eval. + bool canEval = false; + + QualType ResultTy = FD->getResultType(); + if (ResultTy->isObjCIdType()) { + // Handle: id NSMakeCollectable(CFTypeRef) + canEval = II->isStr("NSMakeCollectable"); + } else if (ResultTy->isPointerType()) { + // Handle: (CF|CG)Retain + // CFMakeCollectable + // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist). + if (cocoa::isRefType(ResultTy, "CF", FName) || + cocoa::isRefType(ResultTy, "CG", FName)) { + canEval = isRetain(FD, FName) || isMakeCollectable(FD, FName); + } + } + + if (!canEval) + return false; + + // Bind the return value. + SVal RetVal = state->getSVal(CE->getArg(0)); + if (RetVal.isUnknown()) { + // If the receiver is unknown, conjure a return value. + SValBuilder &SVB = C.getSValBuilder(); + unsigned Count = C.getCurrentBlockCount(); + SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); + } + state = state->BindExpr(CE, RetVal, false); + + // FIXME: This should not be necessary, but otherwise the argument seems to be + // considered alive during the next statement. + if (const MemRegion *ArgRegion = RetVal.getAsRegion()) { + // Save the refcount status of the argument. + SymbolRef Sym = RetVal.getAsLocSymbol(); + RefBindings::data_type *Binding = 0; + if (Sym) + Binding = state->get<RefBindings>(Sym); + + // Invalidate the argument region. + unsigned Count = C.getCurrentBlockCount(); + state = state->invalidateRegions(ArgRegion, CE, Count); + + // Restore the refcount status of the argument. + if (Binding) + state = state->set<RefBindings>(Sym, *Binding); + } + + C.addTransition(state); + return true; +} + +//===----------------------------------------------------------------------===// +// Handle return statements. +//===----------------------------------------------------------------------===// - const Expr* RetE = S->getRetValue(); +void RetainCountChecker::checkPreStmt(const ReturnStmt *S, + CheckerContext &C) const { + const Expr *RetE = S->getRetValue(); if (!RetE) return; - const GRState *state = Builder.GetState(Pred); + const ProgramState *state = C.getState(); SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol(); - if (!Sym) return; // Get the reference count binding (if any). - const RefVal* T = state->get<RefBindings>(Sym); - + const RefVal *T = state->get<RefBindings>(Sym); if (!T) return; @@ -2951,7 +3083,7 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst, switch (X.getKind()) { case RefVal::Owned: { unsigned cnt = X.getCount(); - assert (cnt > 0); + assert(cnt > 0); X.setCount(cnt - 1); X = X ^ RefVal::ReturnedOwned; break; @@ -2975,21 +3107,25 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst, // Update the binding. state = state->set<RefBindings>(Sym, X); - Pred = Builder.MakeNode(Dst, S, Pred, state); + ExplodedNode *Pred = C.generateNode(state); + + // At this point we have updated the state properly. + // Everything after this is merely checking to see if the return value has + // been over- or under-retained. // Did we cache out? if (!Pred) return; // Update the autorelease counts. - static unsigned autoreleasetag = 0; - GenericNodeBuilderRefCount Bd(Builder, S, &autoreleasetag); - bool stop = false; - llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym, - X, stop); + static SimpleProgramPointTag + AutoreleaseTag("RetainCountChecker : Autorelease"); + GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag); + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, + C.getEngine(), Sym, X); // Did we cache out? - if (!Pred || stop) + if (!Pred) return; // Get the updated binding. @@ -2998,36 +3134,37 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst, X = *T; // Consult the summary of the enclosing method. - Decl const *CD = &Pred->getCodeDecl(); + RetainSummaryManager &Summaries = getSummaryManager(C); + const Decl *CD = &Pred->getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) { - const RetainSummary &Summ = *Summaries.getMethodSummary(MD); - return evalReturnWithRetEffect(Dst, Eng, Builder, S, - Pred, Summ.getRetEffect(), X, - Sym, state); + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) { + // Unlike regular functions, /all/ ObjC methods are assumed to always + // follow Cocoa retain-count conventions, not just those with special + // names or attributes. + const RetainSummary *Summ = Summaries.getMethodSummary(MD); + RetEffect RE = Summ ? Summ->getRetEffect() : RetEffect::MakeNoRet(); + checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { if (!isa<CXXMethodDecl>(FD)) if (const RetainSummary *Summ = Summaries.getSummary(FD)) - return evalReturnWithRetEffect(Dst, Eng, Builder, S, - Pred, Summ->getRetEffect(), X, - Sym, state); + checkReturnWithRetEffect(S, C, Pred, Summ->getRetEffect(), X, + Sym, state); } } -void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst, - ExprEngine &Eng, - StmtNodeBuilder &Builder, - const ReturnStmt *S, - ExplodedNode *Pred, - RetEffect RE, RefVal X, - SymbolRef Sym, const GRState *state) { +void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, + CheckerContext &C, + ExplodedNode *Pred, + RetEffect RE, RefVal X, + SymbolRef Sym, + const ProgramState *state) const { // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { if (RE.getKind() != RetEffect::NoRet) { bool hasError = false; - if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { + if (C.isObjCGCEnabled() && RE.getObjKind() == RetEffect::ObjC) { // Things are more complicated with garbage collection. If the // returned object is suppose to be an Objective-C object, we have // a leak (as the caller expects a GC'ed object) because no @@ -3045,46 +3182,88 @@ void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst, if (hasError) { // Generate an error node. - static int ReturnOwnLeakTag = 0; state = state->set<RefBindings>(Sym, X); - ExplodedNode *N = - Builder.generateNode(PostStmt(S, Pred->getLocationContext(), - &ReturnOwnLeakTag), state, Pred); + + static SimpleProgramPointTag + ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak"); + ExplodedNode *N = C.generateNode(state, Pred, &ReturnOwnLeakTag); if (N) { + const LangOptions &LOpts = C.getASTContext().getLangOptions(); + bool GCEnabled = C.isObjCGCEnabled(); CFRefReport *report = - new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this, - N, Sym, Eng); - BR->EmitReport(report); + new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled), + LOpts, GCEnabled, SummaryLog, + N, Sym, C.getEngine()); + C.EmitReport(report); } } } - return; - } - - if (X.isReturnedNotOwned()) { + } else if (X.isReturnedNotOwned()) { if (RE.isOwned()) { // Trying to return a not owned object to a caller expecting an // owned object. - - static int ReturnNotOwnedForOwnedTag = 0; state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned); - if (ExplodedNode *N = - Builder.generateNode(PostStmt(S, Pred->getLocationContext(), - &ReturnNotOwnedForOwnedTag), - state, Pred)) { - CFRefReport *report = - new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned), - *this, N, Sym); - BR->EmitReport(report); + + static SimpleProgramPointTag + ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned"); + ExplodedNode *N = C.generateNode(state, Pred, &ReturnNotOwnedTag); + if (N) { + if (!returnNotOwnedForOwned) + returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned()); + + CFRefReport *report = + new CFRefReport(*returnNotOwnedForOwned, + C.getASTContext().getLangOptions(), + C.isObjCGCEnabled(), SummaryLog, N, Sym); + C.EmitReport(report); } } } } -// Assumptions. +//===----------------------------------------------------------------------===// +// Check various ways a symbol can be invalidated. +//===----------------------------------------------------------------------===// + +void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, + CheckerContext &C) const { + // Are we storing to something that causes the value to "escape"? + bool escapes = true; + + // A value escapes in three possible cases (this may change): + // + // (1) we are binding to something that is not a memory region. + // (2) we are binding to a memregion that does not have stack storage + // (3) we are binding to a memregion with stack storage that the store + // does not understand. + const ProgramState *state = C.getState(); + + if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) { + escapes = !regionLoc->getRegion()->hasStackStorage(); + + if (!escapes) { + // To test (3), generate a new state with the binding added. If it is + // the same state, then it escapes (since the store cannot represent + // the binding). + escapes = (state == (state->bindLoc(*regionLoc, val))); + } + } + + // If our store can represent the binding and we aren't storing to something + // that doesn't have local storage then just return and have the simulation + // state continue as is. + if (!escapes) + return; + + // Otherwise, find all symbols referenced by 'val' that we are tracking + // and stop tracking them. + state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); + C.addTransition(state); +} -const GRState* CFRefCount::evalAssume(const GRState *state, - SVal Cond, bool Assumption) { +const ProgramState *RetainCountChecker::evalAssume(const ProgramState *state, + SVal Cond, + bool Assumption) const { // FIXME: We may add to the interface of evalAssume the list of symbols // whose assumptions have changed. For now we just iterate through the @@ -3098,9 +3277,9 @@ const GRState* CFRefCount::evalAssume(const GRState *state, return state; bool changed = false; - RefBindings::Factory& RefBFactory = state->get_context<RefBindings>(); + RefBindings::Factory &RefBFactory = state->get_context<RefBindings>(); - for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { // Check if the symbol is null (or equal to any constant). // If this is the case, stop tracking the symbol. if (state->getSymVal(I.getKey())) { @@ -3115,161 +3294,48 @@ const GRState* CFRefCount::evalAssume(const GRState *state, return state; } -const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, - RefVal V, ArgEffect E, - RefVal::Kind& hasErr) { - - // In GC mode [... release] and [... retain] do nothing. - switch (E) { - default: break; - case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break; - case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break; - case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break; - case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : - NewAutoreleasePool; break; - } +const ProgramState * +RetainCountChecker::checkRegionChanges(const ProgramState *state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions) const { + if (!invalidated) + return state; - // Handle all use-after-releases. - if (!isGCEnabled() && V.getKind() == RefVal::Released) { - V = V ^ RefVal::ErrorUseAfterRelease; - hasErr = V.getKind(); - return state->set<RefBindings>(sym, V); + llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; + for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), + E = ExplicitRegions.end(); I != E; ++I) { + if (const SymbolicRegion *SR = (*I)->StripCasts()->getAs<SymbolicRegion>()) + WhitelistedSymbols.insert(SR->getSymbol()); } - switch (E) { - case DecRefMsg: - case IncRefMsg: - case MakeCollectable: - assert(false && - "DecRefMsg/IncRefMsg/MakeCollectable already transformed"); - return state; - - case Dealloc: - // Any use of -dealloc in GC is *bad*. - if (isGCEnabled()) { - V = V ^ RefVal::ErrorDeallocGC; - hasErr = V.getKind(); - break; - } - - switch (V.getKind()) { - default: - assert(false && "Invalid case."); - case RefVal::Owned: - // The object immediately transitions to the released state. - V = V ^ RefVal::Released; - V.clearCounts(); - return state->set<RefBindings>(sym, V); - case RefVal::NotOwned: - V = V ^ RefVal::ErrorDeallocNotOwned; - hasErr = V.getKind(); - break; - } - break; - - case NewAutoreleasePool: - assert(!isGCEnabled()); - return state->add<AutoreleaseStack>(sym); - - case MayEscape: - if (V.getKind() == RefVal::Owned) { - V = V ^ RefVal::NotOwned; - break; - } - - // Fall-through. - - case DoNothingByRef: - case DoNothing: - return state; - - case Autorelease: - if (isGCEnabled()) - return state; - - // Update the autorelease counts. - state = SendAutorelease(state, ARCountFactory, sym); - V = V.autorelease(); - break; - - case StopTracking: - return state->remove<RefBindings>(sym); - - case IncRef: - switch (V.getKind()) { - default: - assert(false); - - case RefVal::Owned: - case RefVal::NotOwned: - V = V + 1; - break; - case RefVal::Released: - // Non-GC cases are handled above. - assert(isGCEnabled()); - V = (V ^ RefVal::Owned) + 1; - break; - } - break; - - case SelfOwn: - V = V ^ RefVal::NotOwned; - // Fall-through. - case DecRef: - case DecRefBridgedTransfered: - switch (V.getKind()) { - default: - // case 'RefVal::Released' handled above. - assert (false); - - case RefVal::Owned: - assert(V.getCount() > 0); - if (V.getCount() == 1) - V = V ^ (E == DecRefBridgedTransfered ? - RefVal::NotOwned : RefVal::Released); - V = V - 1; - break; - - case RefVal::NotOwned: - if (V.getCount() > 0) - V = V - 1; - else { - V = V ^ RefVal::ErrorReleaseNotOwned; - hasErr = V.getKind(); - } - break; - - case RefVal::Released: - // Non-GC cases are handled above. - assert(isGCEnabled()); - V = V ^ RefVal::ErrorUseAfterRelease; - hasErr = V.getKind(); - break; - } - break; + for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), + E = invalidated->end(); I!=E; ++I) { + SymbolRef sym = *I; + if (WhitelistedSymbols.count(sym)) + continue; + // Remove any existing reference-count binding. + state = state->remove<RefBindings>(sym); } - return state->set<RefBindings>(sym, V); + return state; } //===----------------------------------------------------------------------===// // Handle dead symbols and end-of-path. //===----------------------------------------------------------------------===// -std::pair<ExplodedNode*, const GRState *> -CFRefCount::HandleAutoreleaseCounts(const GRState * state, - GenericNodeBuilderRefCount Bd, - ExplodedNode* Pred, - ExprEngine &Eng, - SymbolRef Sym, RefVal V, bool &stop) { - +std::pair<ExplodedNode *, const ProgramState *> +RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state, + GenericNodeBuilderRefCount Bd, + ExplodedNode *Pred, ExprEngine &Eng, + SymbolRef Sym, RefVal V) const { unsigned ACnt = V.getAutoreleaseCount(); - stop = false; // No autorelease counts? Nothing to be done. if (!ACnt) return std::make_pair(Pred, state); - assert(!isGCEnabled() && "Autorelease counts in GC mode?"); + assert(!Eng.isObjCGCEnabled() && "Autorelease counts in GC mode?"); unsigned Cnt = V.getCount(); // FIXME: Handle sending 'autorelease' to already released object. @@ -3284,48 +3350,54 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, V = V ^ RefVal::ReturnedNotOwned; else V = V ^ RefVal::NotOwned; - } - else { + } else { V.setCount(Cnt - ACnt); V.setAutoreleaseCount(0); } state = state->set<RefBindings>(Sym, V); ExplodedNode *N = Bd.MakeNode(state, Pred); - stop = (N == 0); + if (N == 0) + state = 0; return std::make_pair(N, state); } // Woah! More autorelease counts then retain counts left. // Emit hard error. - stop = true; V = V ^ RefVal::ErrorOverAutorelease; state = state->set<RefBindings>(Sym, V); if (ExplodedNode *N = Bd.MakeNode(state, Pred)) { N->markAsSink(); - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + llvm::SmallString<128> sbuf; + llvm::raw_svector_ostream os(sbuf); os << "Object over-autoreleased: object was sent -autorelease "; if (V.getAutoreleaseCount() > 1) os << V.getAutoreleaseCount() << " times "; os << "but the object has a +" << V.getCount() << " retain count"; + if (!overAutorelease) + overAutorelease.reset(new OverAutorelease()); + + const LangOptions &LOpts = Eng.getContext().getLangOptions(); CFRefReport *report = - new CFRefReport(*static_cast<CFRefBug*>(overAutorelease), - *this, N, Sym, os.str()); - BR->EmitReport(report); + new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false, + SummaryLog, N, Sym, os.str()); + Eng.getBugReporter().EmitReport(report); } - return std::make_pair((ExplodedNode*)0, state); + return std::make_pair((ExplodedNode *)0, (const ProgramState *)0); } -const GRState * -CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, - llvm::SmallVectorImpl<SymbolRef> &Leaked) { - - bool hasLeak = V.isOwned() || - ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); +const ProgramState * +RetainCountChecker::handleSymbolDeath(const ProgramState *state, + SymbolRef sid, RefVal V, + SmallVectorImpl<SymbolRef> &Leaked) const { + bool hasLeak = false; + if (V.isOwned()) + hasLeak = true; + else if (V.isNotOwned() || V.isReturnedOwned()) + hasLeak = (V.getCount() > 0); if (!hasLeak) return state->remove<RefBindings>(sid); @@ -3334,13 +3406,11 @@ CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak); } -ExplodedNode* -CFRefCount::ProcessLeaks(const GRState * state, - llvm::SmallVectorImpl<SymbolRef> &Leaked, - GenericNodeBuilderRefCount &Builder, - ExprEngine& Eng, - ExplodedNode *Pred) { - +ExplodedNode * +RetainCountChecker::processLeaks(const ProgramState *state, + SmallVectorImpl<SymbolRef> &Leaked, + GenericNodeBuilderRefCount &Builder, + ExprEngine &Eng, ExplodedNode *Pred) const { if (Leaked.empty()) return Pred; @@ -3348,85 +3418,94 @@ CFRefCount::ProcessLeaks(const GRState * state, ExplodedNode *N = Builder.MakeNode(state, Pred); if (N) { - for (llvm::SmallVectorImpl<SymbolRef>::iterator + for (SmallVectorImpl<SymbolRef>::iterator I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction - : leakAtReturn); + const LangOptions &LOpts = Eng.getContext().getLangOptions(); + bool GCEnabled = Eng.isObjCGCEnabled(); + CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled) + : getLeakAtReturnBug(LOpts, GCEnabled); assert(BT && "BugType not initialized."); - CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng); - BR->EmitReport(report); + + CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled, + SummaryLog, N, *I, Eng); + Eng.getBugReporter().EmitReport(report); } } return N; } -void CFRefCount::evalEndPath(ExprEngine& Eng, - EndOfFunctionNodeBuilder& Builder) { - - const GRState *state = Builder.getState(); +void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder, + ExprEngine &Eng) const { + const ProgramState *state = Builder.getState(); GenericNodeBuilderRefCount Bd(Builder); RefBindings B = state->get<RefBindings>(); - ExplodedNode *Pred = 0; + ExplodedNode *Pred = Builder.getPredecessor(); for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - bool stop = false; - llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, - (*I).first, - (*I).second, stop); - - if (stop) + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng, + I->first, I->second); + if (!state) return; } B = state->get<RefBindings>(); - llvm::SmallVector<SymbolRef, 10> Leaked; + SmallVector<SymbolRef, 10> Leaked; for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) - state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked); + state = handleSymbolDeath(state, I->first, I->second, Leaked); - ProcessLeaks(state, Leaked, Bd, Eng, Pred); + processLeaks(state, Leaked, Bd, Eng, Pred); +} + +const ProgramPointTag * +RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const { + const SimpleProgramPointTag *&tag = DeadSymbolTags[sym]; + if (!tag) { + llvm::SmallString<64> buf; + llvm::raw_svector_ostream out(buf); + out << "RetainCountChecker : Dead Symbol : " << sym->getSymbolID(); + tag = new SimpleProgramPointTag(out.str()); + } + return tag; } -void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - ExplodedNode* Pred, - const GRState* state, - SymbolReaper& SymReaper) { - const Stmt *S = Builder.getStmt(); +void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + ExprEngine &Eng = C.getEngine(); + ExplodedNode *Pred = C.getPredecessor(); + + const ProgramState *state = C.getState(); RefBindings B = state->get<RefBindings>(); // Update counts from autorelease pools for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { SymbolRef Sym = *I; - if (const RefVal* T = B.lookup(Sym)){ + if (const RefVal *T = B.lookup(Sym)){ // Use the symbol as the tag. // FIXME: This might not be as unique as we would like. - GenericNodeBuilderRefCount Bd(Builder, S, Sym); - bool stop = false; - llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, - Sym, *T, stop); - if (stop) + GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym)); + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng, + Sym, *T); + if (!state) return; } } B = state->get<RefBindings>(); - llvm::SmallVector<SymbolRef, 10> Leaked; + SmallVector<SymbolRef, 10> Leaked; for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { - if (const RefVal* T = B.lookup(*I)) - state = HandleSymbolDeath(state, *I, *T, Leaked); + if (const RefVal *T = B.lookup(*I)) + state = handleSymbolDeath(state, *I, *T, Leaked); } - static unsigned LeakPPTag = 0; { - GenericNodeBuilderRefCount Bd(Builder, S, &LeakPPTag); - Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred); + GenericNodeBuilderRefCount Bd(C, this); + Pred = processLeaks(state, Leaked, Bd, Eng, Pred); } // Did we cache out? @@ -3434,256 +3513,76 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst, return; // Now generate a new node that nukes the old bindings. - RefBindings::Factory& F = state->get_context<RefBindings>(); + RefBindings::Factory &F = state->get_context<RefBindings>(); for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I!=E; ++I) B = F.remove(B, *I); + E = SymReaper.dead_end(); I != E; ++I) + B = F.remove(B, *I); state = state->set<RefBindings>(B); - Builder.MakeNode(Dst, S, Pred, state); -} - -void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, - StmtNodeBuilder& Builder, - const Expr* NodeExpr, - SourceRange ErrorRange, - ExplodedNode* Pred, - const GRState* St, - RefVal::Kind hasErr, SymbolRef Sym) { - Builder.BuildSinks = true; - ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St); - - if (!N) - return; - - CFRefBug *BT = 0; - - switch (hasErr) { - default: - assert(false && "Unhandled error."); - return; - case RefVal::ErrorUseAfterRelease: - BT = static_cast<CFRefBug*>(useAfterRelease); - break; - case RefVal::ErrorReleaseNotOwned: - BT = static_cast<CFRefBug*>(releaseNotOwned); - break; - case RefVal::ErrorDeallocGC: - BT = static_cast<CFRefBug*>(deallocGC); - break; - case RefVal::ErrorDeallocNotOwned: - BT = static_cast<CFRefBug*>(deallocNotOwned); - break; - } - - CFRefReport *report = new CFRefReport(*BT, *this, N, Sym); - report->addRange(ErrorRange); - BR->EmitReport(report); + C.generateNode(state, Pred); } //===----------------------------------------------------------------------===// -// Pieces of the retain/release checker implemented using a CheckerVisitor. -// More pieces of the retain/release checker will be migrated to this interface -// (ideally, all of it some day). +// Debug printing of refcount bindings and autorelease pools. //===----------------------------------------------------------------------===// -namespace { -class RetainReleaseChecker - : public Checker< check::PostStmt<BlockExpr>, - check::PostStmt<CastExpr>, - check::RegionChanges > { -public: - bool wantsRegionUpdate; - - RetainReleaseChecker() : wantsRegionUpdate(true) {} - - - void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; - - void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; - - const GRState *checkRegionChanges(const GRState *state, - const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *begin, - const MemRegion * const *end) const; - - bool wantsRegionChangeUpdate(const GRState *state) const { - return wantsRegionUpdate; - } -}; -} // end anonymous namespace +static void PrintPool(raw_ostream &Out, SymbolRef Sym, + const ProgramState *State) { + Out << ' '; + if (Sym) + Out << Sym->getSymbolID(); + else + Out << "<pool>"; + Out << ":{"; -const GRState * -RetainReleaseChecker::checkRegionChanges(const GRState *state, - const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *begin, - const MemRegion * const *end) const { - if (!invalidated) - return state; + // Get the contents of the pool. + if (const ARCounts *Cnts = State->get<AutoreleasePoolContents>(Sym)) + for (ARCounts::iterator I = Cnts->begin(), E = Cnts->end(); I != E; ++I) + Out << '(' << I.getKey() << ',' << I.getData() << ')'; - for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), - E = invalidated->end(); I!=E; ++I) { - SymbolRef sym = *I; - if (WhitelistedSymbols.count(sym)) - continue; - // Remove any existing reference-count binding. - state = state->remove<RefBindings>(sym); - } - return state; + Out << '}'; } -void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE, - CheckerContext &C) const { - - // Scan the BlockDecRefExprs for any object the retain/release checker - // may be tracking. - if (!BE->getBlockDecl()->hasCaptures()) - return; +static bool UsesAutorelease(const ProgramState *state) { + // A state uses autorelease if it allocated an autorelease pool or if it has + // objects in the caller's autorelease pool. + return !state->get<AutoreleaseStack>().isEmpty() || + state->get<AutoreleasePoolContents>(SymbolRef()); +} - const GRState *state = C.getState(); - const BlockDataRegion *R = - cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); +void RetainCountChecker::printState(raw_ostream &Out, const ProgramState *State, + const char *NL, const char *Sep) const { - BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), - E = R->referenced_vars_end(); + RefBindings B = State->get<RefBindings>(); - if (I == E) - return; - - // FIXME: For now we invalidate the tracking of all symbols passed to blocks - // via captured variables, even though captured variables result in a copy - // and in implicit increment/decrement of a retain count. - llvm::SmallVector<const MemRegion*, 10> Regions; - const LocationContext *LC = C.getPredecessor()->getLocationContext(); - MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); + if (!B.isEmpty()) + Out << Sep << NL; - for ( ; I != E; ++I) { - const VarRegion *VR = *I; - if (VR->getSuperRegion() == R) { - VR = MemMgr.getVarRegion(VR->getDecl(), LC); - } - Regions.push_back(VR); + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { + Out << I->first << " : "; + I->second.print(Out); + Out << NL; } - state = - state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), - Regions.data() + Regions.size()).getState(); - C.addTransition(state); -} + // Print the autorelease stack. + if (UsesAutorelease(State)) { + Out << Sep << NL << "AR pool stack:"; + ARStack Stack = State->get<AutoreleaseStack>(); -void RetainReleaseChecker::checkPostStmt(const CastExpr *CE, - CheckerContext &C) const { - const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); - if (!BE) - return; - - ArgEffect AE = IncRef; - - switch (BE->getBridgeKind()) { - case clang::OBC_Bridge: - // Do nothing. - return; - case clang::OBC_BridgeRetained: - AE = IncRef; - break; - case clang::OBC_BridgeTransfer: - AE = DecRefBridgedTransfered; - break; - } - - const GRState *state = C.getState(); - SymbolRef Sym = state->getSVal(CE).getAsLocSymbol(); - if (!Sym) - return; - const RefVal* T = state->get<RefBindings>(Sym); - if (!T) - return; + PrintPool(Out, SymbolRef(), State); // Print the caller's pool. + for (ARStack::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) + PrintPool(Out, *I, State); - // This is gross. Once the checker and CFRefCount are unified, - // this will go away. - CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF()); - RefVal::Kind hasErr = (RefVal::Kind) 0; - state = cf.Update(state, Sym, *T, AE, hasErr); - - if (hasErr) { - - return; + Out << NL; } - - C.generateNode(state); } //===----------------------------------------------------------------------===// -// Transfer function creation for external clients. +// Checker registration. //===----------------------------------------------------------------------===// -void CFRefCount::RegisterChecks(ExprEngine& Eng) { - BugReporter &BR = Eng.getBugReporter(); - - useAfterRelease = new UseAfterRelease(this); - BR.Register(useAfterRelease); - - releaseNotOwned = new BadRelease(this); - BR.Register(releaseNotOwned); - - deallocGC = new DeallocGC(this); - BR.Register(deallocGC); - - deallocNotOwned = new DeallocNotOwned(this); - BR.Register(deallocNotOwned); - - overAutorelease = new OverAutorelease(this); - BR.Register(overAutorelease); - - returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); - BR.Register(returnNotOwnedForOwned); - - // First register "return" leaks. - const char* name = 0; - - if (isGCEnabled()) - name = "Leak of returned object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of returned object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak of returned object"; - } - - // Leaks should not be reported if they are post-dominated by a sink. - leakAtReturn = new LeakAtReturn(this, name); - leakAtReturn->setSuppressOnSink(true); - BR.Register(leakAtReturn); - - // Second, register leaks within a function/method. - if (isGCEnabled()) - name = "Leak of object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak"; - } - - // Leaks should not be reported if they are post-dominated by sinks. - leakWithinFunction = new LeakWithinFunction(this, name); - leakWithinFunction->setSuppressOnSink(true); - BR.Register(leakWithinFunction); - - // Save the reference to the BugReporter. - this->BR = &BR; - - // Register the RetainReleaseChecker with the ExprEngine object. - // Functionality in CFRefCount will be migrated to RetainReleaseChecker - // over time. - // FIXME: HACK! Remove TransferFuncs and turn all of CFRefCount into fully - // using the checker mechanism. - Eng.getCheckerManager().registerChecker<RetainReleaseChecker>(); +void ento::registerRetainCountChecker(CheckerManager &Mgr) { + Mgr.registerChecker<RetainCountChecker>(); } -TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts) { - return new CFRefCount(Ctx, GCEnabled, lopts); -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index 1729b25..e761bff 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -33,7 +33,7 @@ public: void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *RetE = RS->getRetValue(); if (!RetE) @@ -58,8 +58,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); - const GRState *StInBound = state->assumeInBound(Idx, NumElements, true); - const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false); + const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true); + const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); @@ -78,8 +78,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, // reference is outside the range. // Generate a report for this bug. - RangedBugReport *report = - new RangedBugReport(*BT, BT->getDescription(), N); + BugReport *report = + new BugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); C.EmitReport(report); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 7c215b7..e8c8d90 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -50,11 +50,11 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, BT.reset(new BuiltinBug("Garbage return value", "Undefined or garbage value returned to caller")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT, BT->getDescription(), N); + BugReport *report = + new BugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE)); C.EmitReport(report); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 73ce359..91c4b96 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -17,7 +17,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -35,12 +35,12 @@ public: private: void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const; - static SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R, + static SourceRange GenName(raw_ostream &os, const MemRegion *R, SourceManager &SM); }; } -SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os, +SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os, const MemRegion *R, SourceManager &SM) { // Get the base region, stripping away fields and elements. @@ -50,34 +50,39 @@ SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os, // Check if the region is a compound literal. if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { - const CompoundLiteralExpr* CL = CR->getLiteralExpr(); + const CompoundLiteralExpr *CL = CR->getLiteralExpr(); os << "stack memory associated with a compound literal " "declared on line " - << SM.getInstantiationLineNumber(CL->getLocStart()) + << SM.getExpansionLineNumber(CL->getLocStart()) << " returned to caller"; range = CL->getSourceRange(); } else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { - const Expr* ARE = AR->getExpr(); + const Expr *ARE = AR->getExpr(); SourceLocation L = ARE->getLocStart(); range = ARE->getSourceRange(); os << "stack memory allocated by call to alloca() on line " - << SM.getInstantiationLineNumber(L); + << SM.getExpansionLineNumber(L); } else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { const BlockDecl *BD = BR->getCodeRegion()->getDecl(); SourceLocation L = BD->getLocStart(); range = BD->getSourceRange(); os << "stack-allocated block declared on line " - << SM.getInstantiationLineNumber(L); + << SM.getExpansionLineNumber(L); } else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { os << "stack memory associated with local variable '" << VR->getString() << '\''; range = VR->getDecl()->getSourceRange(); } + else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) { + os << "stack memory associated with temporary object of type '" + << TOR->getValueType().getAsString() << '\''; + range = TOR->getExpr()->getSourceRange(); + } else { - assert(false && "Invalid region in ReturnStackAddressChecker."); + llvm_unreachable("Invalid region in ReturnStackAddressChecker."); } return range; @@ -99,7 +104,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion * llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, R, C.getSourceManager()); os << " returned to caller"; - RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N); + BugReport *report = new BugReport(*BT_returnstack, os.str(), N); report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); @@ -134,7 +139,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const { - const GRState *state = B.getState(); + const ProgramState *state = B.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. @@ -143,7 +148,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng; const StackFrameContext *CurSFC; public: - llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; + SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; CallBack(ExprEngine &Eng, const LocationContext *LCtx) : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {} @@ -202,9 +207,9 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, Eng.getContext().getSourceManager()); os << " is still referred to by the global variable '"; const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); - os << VR->getDecl()->getNameAsString() + os << *VR->getDecl() << "' upon returning to the caller. This will be a dangling reference"; - RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N); + BugReport *report = new BugReport(*BT_stackleak, os.str(), N); if (range.isValid()) report->addRange(range); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 711c672..1d14e9e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -16,8 +16,8 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" @@ -96,9 +96,9 @@ private: void OpenFileAux(CheckerContext &C, const CallExpr *CE) const; - const GRState *CheckNullStream(SVal SV, const GRState *state, + const ProgramState *CheckNullStream(SVal SV, const ProgramState *state, CheckerContext &C) const; - const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state, + const ProgramState *CheckDoubleClose(const CallExpr *CE, const ProgramState *state, CheckerContext &C) const; }; @@ -107,15 +107,15 @@ private: namespace clang { namespace ento { template <> - struct GRStateTrait<StreamState> - : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > { + struct ProgramStateTrait<StreamState> + : public ProgramStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > { static void *GDMIndex() { static int x; return &x; } }; } } bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); const FunctionDecl *FD = L.getAsFunctionDecl(); @@ -221,8 +221,8 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const { } void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + const ProgramState *state = C.getState(); + unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); DefinedSVal RetVal = cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count)); @@ -231,7 +231,7 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { ConstraintManager &CM = C.getConstraintManager(); // Bifurcate the state into two: one with a valid FILE* pointer, the other // with a NULL. - const GRState *stateNotNull, *stateNull; + const ProgramState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal); if (SymbolRef Sym = RetVal.getAsSymbol()) { @@ -247,25 +247,25 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { } void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = CheckDoubleClose(CE, C.getState(), C); + const ProgramState *state = CheckDoubleClose(CE, C.getState(), C); if (state) C.addTransition(state); } void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C)) return; } void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C)) return; } void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C))) return; // Check the legality of the 'whence' argument of 'fseek'. @@ -291,61 +291,61 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { } void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) return; } -const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state, +const ProgramState *StreamChecker::CheckNullStream(SVal SV, const ProgramState *state, CheckerContext &C) const { const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV); if (!DV) return 0; ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotNull, *stateNull; + const ProgramState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (!stateNotNull && stateNull) { @@ -361,8 +361,8 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state, return stateNotNull; } -const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE, - const GRState *state, +const ProgramState *StreamChecker::CheckDoubleClose(const CallExpr *CE, + const ProgramState *state, CheckerContext &C) const { SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol(); if (!Sym) @@ -399,7 +399,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { SymbolRef Sym = *I; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const StreamState *SS = state->get<StreamState>(Sym); if (!SS) return; @@ -420,7 +420,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const { - const GRState *state = B.getState(); + const ProgramState *state = B.getState(); typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap; SymMap M = state->get<StreamState>(); @@ -445,7 +445,7 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { if (!RetE) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SymbolRef Sym = state->getSVal(RetE).getAsSymbol(); if (!Sym) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 1fb1815..b860b34 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -27,26 +27,25 @@ class UndefBranchChecker : public Checker<check::BranchCondition> { mutable llvm::OwningPtr<BuiltinBug> BT; struct FindUndefExpr { - GRStateManager& VM; - const GRState* St; + const ProgramState *St; - FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} + FindUndefExpr(const ProgramState *S) : St(S) {} - const Expr* FindExpr(const Expr* Ex) { + const Expr *FindExpr(const Expr *Ex) { if (!MatchesCriteria(Ex)) return 0; for (Stmt::const_child_iterator I = Ex->child_begin(), E = Ex->child_end();I!=E;++I) - if (const Expr* ExI = dyn_cast_or_null<Expr>(*I)) { - const Expr* E2 = FindExpr(ExI); + if (const Expr *ExI = dyn_cast_or_null<Expr>(*I)) { + const Expr *E2 = FindExpr(ExI); if (E2) return E2; } return Ex; } - bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); } + bool MatchesCriteria(const Expr *Ex) { return St->getSVal(Ex).isUndef(); } }; public: @@ -59,10 +58,10 @@ public: void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder, ExprEngine &Eng) const { - const GRState *state = Builder.getState(); + const ProgramState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { - ExplodedNode *N = Builder.generateNode(state, true); + ExplodedNode *N = Builder.generateNode(Condition, state); if (N) { N->markAsSink(); if (!BT) @@ -74,33 +73,31 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, // branch condition." We do a recursive walk of the condition's // subexpressions and roughly look for the most nested subexpression // that binds to Undefined. We then highlight that expression's range. - BlockEdge B = cast<BlockEdge>(N->getLocation()); - const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition()); - assert (Ex && "Block must have a terminator."); // Get the predecessor node and check if is a PostStmt with the Stmt // being the terminator condition. We want to inspect the state // of that node instead because it will contain main information about // the subexpressions. - assert (!N->pred_empty()); // Note: any predecessor will do. They should have identical state, // since all the BlockEdge did was act as an error sink since the value // had to already be undefined. + assert (!N->pred_empty()); + const Expr *Ex = cast<Expr>(Condition); ExplodedNode *PrevN = *N->pred_begin(); ProgramPoint P = PrevN->getLocation(); - const GRState* St = N->getState(); + const ProgramState *St = N->getState(); - if (PostStmt* PS = dyn_cast<PostStmt>(&P)) + if (PostStmt *PS = dyn_cast<PostStmt>(&P)) if (PS->getStmt() == Ex) St = PrevN->getState(); - FindUndefExpr FindIt(Eng.getStateManager(), St); + FindUndefExpr FindIt(St); Ex = FindIt.FindExpr(Ex); // Emit the bug report. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + BugReport *R = new BugReport(*BT, BT->getDescription(), N); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); R->addRange(Ex->getSourceRange()); Eng.getBugReporter().EmitReport(R); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 69958d1..2aebed9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -55,7 +55,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, if (!BE->getBlockDecl()->hasCaptures()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const BlockDataRegion *R = cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); @@ -74,8 +74,9 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, // Get the VarRegion associated with VD in the local stack frame. const LocationContext *LC = C.getPredecessor()->getLocationContext(); VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC); + SVal VRVal = state->getSVal(VR); - if (state->getSVal(VR).isUndef()) + if (VRVal.isUndef()) if (ExplodedNode *N = C.generateSink()) { if (!BT) BT.reset(new BuiltinBug("uninitialized variable captured by block")); @@ -87,10 +88,10 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, os << "Variable '" << VD->getName() << "' is uninitialized when captured by block"; - EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); + BugReport *R = new BugReport(*BT, os.str(), N); if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) R->addRange(Ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerFindLastStore, VR); + R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR)); // need location of block C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 7fa3804..7ae9668 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -35,7 +35,7 @@ public: void UndefResultChecker::checkPostStmt(const BinaryOperator *B, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (state->getSVal(B).isUndef()) { // Generate an error node. ExplodedNode *N = C.generateSink(); @@ -71,13 +71,13 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, << BinaryOperator::getOpcodeStr(B->getOpcode()) << "' expression is undefined"; } - EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N); + BugReport *report = new BugReport(*BT, OS.str(), N); if (Ex) { report->addRange(Ex->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); } else - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B)); C.EmitReport(report); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index e51ab20..bb6831b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -40,10 +40,10 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, BT.reset(new BuiltinBug("Array subscript is undefined")); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(A->getIdx()->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - A->getIdx()); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + A->getIdx())); C.EmitReport(R); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 28806e3..5ca4a9f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -27,11 +27,13 @@ class UndefinedAssignmentChecker mutable llvm::OwningPtr<BugType> BT; public: - void checkBind(SVal location, SVal val, CheckerContext &C) const; + void checkBind(SVal location, SVal val, const Stmt *S, + CheckerContext &C) const; }; } void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, + const Stmt *StoreE, CheckerContext &C) const { if (!val.isUndef()) return; @@ -49,11 +51,10 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, // Generate a report for this bug. const Expr *ex = 0; - const Stmt *StoreE = C.getStmt(); while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (state->getSVal(B->getLHS()).isUndef()) { str = "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; @@ -67,17 +68,17 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, } if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) { - const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } break; } - EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N); + BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex)); } C.EmitReport(R); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 0ecc391..cec286d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -62,7 +62,8 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { // The definition of O_CREAT is platform specific. We need a better way // of querying this information from the checking environment. if (!Val_O_CREAT.hasValue()) { - if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + if (C.getASTContext().getTargetInfo().getTriple().getVendor() + == llvm::Triple::Apple) Val_O_CREAT = 0x0200; else { // FIXME: We need a more general way of getting the O_CREAT value. @@ -73,7 +74,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { } // Look at the 'oflags' argument for the O_CREAT flag. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); if (CE->getNumArgs() < 2) { // The frontend should issue a warning for this case, so this is a sanity @@ -101,7 +102,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC); // Check if maskedFlags is non-zero. - const GRState *trueState, *falseState; + const ProgramState *trueState, *falseState; llvm::tie(trueState, falseState) = state->assume(maskedFlags); // Only emit an error if the value of 'maskedFlags' is properly @@ -116,8 +117,8 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { LazyInitialize(BT_open, "Improper use of 'open'"); - RangedBugReport *report = - new RangedBugReport(*BT_open, + BugReport *report = + new BugReport(*BT_open, "Call to 'open' requires a third argument when " "the 'O_CREAT' flag is set", N); report->addRange(oflagsEx->getSourceRange()); @@ -140,7 +141,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, // Check if the first argument is stack allocated. If so, issue a warning // because that's likely to be bad news. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; @@ -163,7 +164,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'"); - RangedBugReport *report = new RangedBugReport(*BT_pthreadOnce, os.str(), N); + BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); C.EmitReport(report); } @@ -182,13 +183,13 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C, return; // Check if the allocation size is 0. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SVal argVal = state->getSVal(CE->getArg(0)); if (argVal.isUnknownOrUndef()) return; - const GRState *trueState, *falseState; + const ProgramState *trueState, *falseState; llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal)); // Is the value perfectly constrained to zero? @@ -202,12 +203,12 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C, LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes"); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_mallocZero, "Call to 'malloc' has an allocation" + BugReport *report = + new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation" " size of 0 bytes", N); report->addRange(CE->getArg(0)->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - CE->getArg(0)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, + CE->getArg(0))); C.EmitReport(report); return; } @@ -225,7 +226,7 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C, void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { // Get the callee. All the functions we care about are C functions // with simple identifiers. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index b540bce..459ee65 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -60,11 +60,12 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, CFG *C = 0; ParentMap *PM = 0; + const LocationContext *LC = 0; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); - const LocationContext *LC = P.getLocationContext(); + LC = P.getLocationContext(); // Save the CFG if we don't have it already if (!C) @@ -111,22 +112,30 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { - CFGElement First = CB->front(); - if (const CFGStmt *S = First.getAs<CFGStmt>()) { - if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { - if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) - continue; - } + bool foundUnreachable = false; + for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end(); + ci != ce; ++ci) { + if (const CFGStmt *S = (*ci).getAs<CFGStmt>()) + if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { + if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) { + foundUnreachable = true; + break; + } + } } + if (foundUnreachable) + continue; } // We found a block that wasn't covered - find the statement to report SourceRange SR; + PathDiagnosticLocation DL; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { SR = S->getSourceRange(); - SL = S->getLocStart(); - if (SR.isInvalid() || SL.isInvalid()) + DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC); + SL = DL.asLocation(); + if (SR.isInvalid() || !SL.isValid()) continue; } else @@ -138,7 +147,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, continue; B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" - " executed", SL, SR); + " executed", DL, SR); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 875dce2..b34b97c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -48,8 +48,8 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { return; // FIXME: Handle multi-dimensional VLAs. - const Expr* SE = VLA->getSizeExpr(); - const GRState *state = C.getState(); + const Expr *SE = VLA->getSizeExpr(); + const ProgramState *state = C.getState(); SVal sizeV = state->getSVal(SE); if (sizeV.isUndef()) { @@ -62,10 +62,10 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) " "uses a garbage value as its size")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_undef, BT_undef->getName(), N); + BugReport *report = + new BugReport(*BT_undef, BT_undef->getName(), N); report->addRange(SE->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE)); C.EmitReport(report); return; } @@ -78,19 +78,19 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { // Check if the size is zero. DefinedSVal sizeD = cast<DefinedSVal>(sizeV); - const GRState *stateNotZero, *stateZero; + const ProgramState *stateNotZero, *stateZero; llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); if (stateZero && !stateNotZero) { - ExplodedNode* N = C.generateSink(stateZero); + ExplodedNode *N = C.generateSink(stateZero); if (!BT_zero) BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has " "zero size")); - EnhancedBugReport *report = - new EnhancedBugReport(*BT_zero, BT_zero->getName(), N); + BugReport *report = + new BugReport(*BT_zero, BT_zero->getName(), N); report->addRange(SE->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE)); C.EmitReport(report); return; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp index 901190d..0936d61 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp @@ -46,7 +46,7 @@ public: void AggExprVisitor::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { default: - assert(0 && "Unhandled cast kind"); + llvm_unreachable("Unhandled cast kind"); case CK_NoOp: case CK_ConstructorConversion: case CK_UserDefinedConversion: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 5f4f83c..17ec70d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -14,6 +14,58 @@ using namespace clang; using namespace ento; +AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, + const LangOptions &lang, + PathDiagnosticConsumer *pd, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + CheckerManager *checkerMgr, + idx::Indexer *idxer, + unsigned maxnodes, unsigned maxvisit, + bool vizdot, bool vizubi, + AnalysisPurgeMode purge, + bool eager, bool trim, + bool inlinecall, bool useUnoptimizedCFG, + bool addImplicitDtors, bool addInitializers, + bool eagerlyTrimEGraph) + : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers), + Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + CheckerMgr(checkerMgr), Idxer(idxer), + AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit), + VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), + EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall), + EagerlyTrimEGraph(eagerlyTrimEGraph) +{ + AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); +} + +AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, + AnalysisManager &ParentAM) + : AnaCtxMgr(ParentAM.AnaCtxMgr.getUseUnoptimizedCFG(), + ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors, + ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers), + Ctx(ctx), Diags(diags), + LangInfo(ParentAM.LangInfo), PD(ParentAM.getPathDiagnosticConsumer()), + CreateStoreMgr(ParentAM.CreateStoreMgr), + CreateConstraintMgr(ParentAM.CreateConstraintMgr), + CheckerMgr(ParentAM.CheckerMgr), + Idxer(ParentAM.Idxer), + AScope(ScopeDecl), + MaxNodes(ParentAM.MaxNodes), + MaxVisit(ParentAM.MaxVisit), + VisualizeEGDot(ParentAM.VisualizeEGDot), + VisualizeEGUbi(ParentAM.VisualizeEGUbi), + PurgeDead(ParentAM.PurgeDead), + EagerlyAssume(ParentAM.EagerlyAssume), + TrimGraph(ParentAM.TrimGraph), + InlineCall(ParentAM.InlineCall), + EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph) +{ + AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); +} + + AnalysisContext * AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) { idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D), diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp index 3050ca3..6c748b6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp @@ -8,14 +8,13 @@ //===----------------------------------------------------------------------===// // // This file defines BasicConstraintManager, a class that tracks simple -// equality and inequality constraints on symbolic values of GRState. +// equality and inequality constraints on symbolic values of ProgramState. // //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -25,7 +24,7 @@ using namespace ento; namespace { class ConstNotEq {}; } namespace { class ConstEq {}; } -typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy; +typedef llvm::ImmutableMap<SymbolRef,ProgramState::IntSetTy> ConstNotEqTy; typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy; static int ConstEqIndex = 0; @@ -34,13 +33,14 @@ static int ConstNotEqIndex = 0; namespace clang { namespace ento { template<> -struct GRStateTrait<ConstNotEq> : public GRStatePartialTrait<ConstNotEqTy> { - static inline void* GDMIndex() { return &ConstNotEqIndex; } +struct ProgramStateTrait<ConstNotEq> : + public ProgramStatePartialTrait<ConstNotEqTy> { + static inline void *GDMIndex() { return &ConstNotEqIndex; } }; template<> -struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> { - static inline void* GDMIndex() { return &ConstEqIndex; } +struct ProgramStateTrait<ConstEq> : public ProgramStatePartialTrait<ConstEqTy> { + static inline void *GDMIndex() { return &ConstEqIndex; } }; } } @@ -50,62 +50,81 @@ namespace { // constants and integer variables. class BasicConstraintManager : public SimpleConstraintManager { - GRState::IntSetTy::Factory ISetFactory; + ProgramState::IntSetTy::Factory ISetFactory; public: - BasicConstraintManager(GRStateManager &statemgr, SubEngine &subengine) + BasicConstraintManager(ProgramStateManager &statemgr, SubEngine &subengine) : SimpleConstraintManager(subengine), ISetFactory(statemgr.getAllocator()) {} - const GRState *assumeSymNE(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState *assumeSymEQ(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState *assumeSymLT(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState *assumeSymGT(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState *assumeSymGE(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState *assumeSymLE(const GRState* state, SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - const GRState* AddEQ(const GRState* state, SymbolRef sym, const llvm::APSInt& V); - - const GRState* AddNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V); - - const llvm::APSInt* getSymVal(const GRState* state, SymbolRef sym) const; - bool isNotEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V) - const; - bool isEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V) - const; - - const GRState* removeDeadBindings(const GRState* state, SymbolReaper& SymReaper); - - void print(const GRState* state, llvm::raw_ostream& Out, - const char* nl, const char *sep); + const ProgramState *assumeSymNE(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *assumeSymEQ(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *assumeSymLT(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *assumeSymGT(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *assumeSymGE(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *assumeSymLE(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V, + const llvm::APSInt& Adjustment); + + const ProgramState *AddEQ(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V); + + const ProgramState *AddNE(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V); + + const llvm::APSInt* getSymVal(const ProgramState *state, + SymbolRef sym) const; + + bool isNotEqual(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V) const; + + bool isEqual(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V) const; + + const ProgramState *removeDeadBindings(const ProgramState *state, + SymbolReaper& SymReaper); + + void print(const ProgramState *state, + raw_ostream &Out, + const char* nl, + const char *sep); }; } // end anonymous namespace -ConstraintManager* ento::CreateBasicConstraintManager(GRStateManager& statemgr, - SubEngine &subengine) { +ConstraintManager* +ento::CreateBasicConstraintManager(ProgramStateManager& statemgr, + SubEngine &subengine) { return new BasicConstraintManager(statemgr, subengine); } - -const GRState* -BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymNE(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // First, determine if sym == X, where X+Adjustment != V. @@ -124,8 +143,9 @@ BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym, return AddNE(state, sym, Adjusted); } -const GRState* -BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymEQ(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // First, determine if sym == X, where X+Adjustment != V. @@ -145,8 +165,9 @@ BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym, } // The logic for these will be handled in another ConstraintManager. -const GRState* -BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymLT(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // Is 'V' the smallest possible value? @@ -159,8 +180,9 @@ BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym, return assumeSymNE(state, sym, V, Adjustment); } -const GRState* -BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymGT(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // Is 'V' the largest possible value? @@ -173,8 +195,9 @@ BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym, return assumeSymNE(state, sym, V, Adjustment); } -const GRState* -BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymGE(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // Reject a path if the value of sym is a constant X and !(X+Adj >= V). @@ -201,8 +224,9 @@ BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym, return state; } -const GRState* -BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym, +const ProgramState* +BasicConstraintManager::assumeSymLE(const ProgramState *state, + SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment) { // Reject a path if the value of sym is a constant X and !(X+Adj <= V). @@ -229,18 +253,20 @@ BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym, return state; } -const GRState* BasicConstraintManager::AddEQ(const GRState* state, SymbolRef sym, +const ProgramState *BasicConstraintManager::AddEQ(const ProgramState *state, + SymbolRef sym, const llvm::APSInt& V) { // Create a new state with the old binding replaced. return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V)); } -const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym, - const llvm::APSInt& V) { +const ProgramState *BasicConstraintManager::AddNE(const ProgramState *state, + SymbolRef sym, + const llvm::APSInt& V) { // First, retrieve the NE-set associated with the given symbol. ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym); - GRState::IntSetTy S = T ? *T : ISetFactory.getEmptySet(); + ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet(); // Now add V to the NE set. S = ISetFactory.add(S, &state->getBasicVals().getValue(V)); @@ -249,13 +275,14 @@ const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym return state->set<ConstNotEq>(sym, S); } -const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state, +const llvm::APSInt* BasicConstraintManager::getSymVal(const ProgramState *state, SymbolRef sym) const { const ConstEqTy::data_type* T = state->get<ConstEq>(sym); return T ? *T : NULL; } -bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym, +bool BasicConstraintManager::isNotEqual(const ProgramState *state, + SymbolRef sym, const llvm::APSInt& V) const { // Retrieve the NE-set associated with the given symbol. @@ -265,7 +292,8 @@ bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym, return T ? T->contains(&state->getBasicVals().getValue(V)) : false; } -bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym, +bool BasicConstraintManager::isEqual(const ProgramState *state, + SymbolRef sym, const llvm::APSInt& V) const { // Retrieve the EQ-set associated with the given symbol. const ConstEqTy::data_type* T = state->get<ConstEq>(sym); @@ -275,8 +303,8 @@ bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym, /// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. -const GRState* -BasicConstraintManager::removeDeadBindings(const GRState* state, +const ProgramState* +BasicConstraintManager::removeDeadBindings(const ProgramState *state, SymbolReaper& SymReaper) { ConstEqTy CE = state->get<ConstEq>(); @@ -301,7 +329,8 @@ BasicConstraintManager::removeDeadBindings(const GRState* state, return state->set<ConstNotEq>(CNE); } -void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, +void BasicConstraintManager::print(const ProgramState *state, + raw_ostream &Out, const char* nl, const char *sep) { // Print equality constraints. @@ -324,7 +353,7 @@ void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, Out << nl << " $" << I.getKey() << " : "; bool isFirst = true; - GRState::IntSetTy::iterator J = I.getData().begin(), + ProgramState::IntSetTy::iterator J = I.getData().begin(), EJ = I.getData().end(); for ( ; J != EJ; ++J) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp deleted file mode 100644 index 7c9f45a..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp +++ /dev/null @@ -1,605 +0,0 @@ -//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defined the BasicStore and BasicStoreManager classes. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/DeclCXX.h" -#include "clang/AST/ExprObjC.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "llvm/ADT/ImmutableMap.h" - -using namespace clang; -using namespace ento; - -typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy; - -namespace { - -class BasicStoreSubRegionMap : public SubRegionMap { -public: - BasicStoreSubRegionMap() {} - - bool iterSubRegions(const MemRegion* R, Visitor& V) const { - return true; // Do nothing. No subregions. - } -}; - -class BasicStoreManager : public StoreManager { - BindingsTy::Factory VBFactory; -public: - BasicStoreManager(GRStateManager& mgr) - : StoreManager(mgr), VBFactory(mgr.getAllocator()) {} - - ~BasicStoreManager() {} - - SubRegionMap *getSubRegionMap(Store store) { - return new BasicStoreSubRegionMap(); - } - - SVal Retrieve(Store store, Loc loc, QualType T = QualType()); - - StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E, - unsigned Count, InvalidatedSymbols &IS); - - StoreRef invalidateRegions(Store store, const MemRegion * const *Begin, - const MemRegion * const *End, const Expr *E, - unsigned Count, InvalidatedSymbols &IS, - bool invalidateGlobals, - InvalidatedRegions *Regions); - - StoreRef scanForIvars(Stmt *B, const Decl* SelfDecl, - const MemRegion *SelfRegion, Store St); - - StoreRef Bind(Store St, Loc loc, SVal V); - StoreRef Remove(Store St, Loc loc); - StoreRef getInitialStore(const LocationContext *InitLoc); - - StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr*, - const LocationContext*, SVal val) { - return StoreRef(store, *this); - } - - /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit - /// conversions between arrays and pointers. - SVal ArrayToPointer(Loc Array) { return Array; } - - /// removeDeadBindings - Scans a BasicStore of 'state' for dead values. - /// It updatees the GRState object in place with the values removed. - StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); - - void iterBindings(Store store, BindingsHandler& f); - - StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal) { - return BindDeclInternal(store, VR, &InitVal); - } - - StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) { - return BindDeclInternal(store, VR, 0); - } - - StoreRef BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal); - - static inline BindingsTy GetBindings(Store store) { - return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store)); - } - - void print(Store store, llvm::raw_ostream& Out, const char* nl, - const char *sep); - -private: - SVal LazyRetrieve(Store store, const TypedRegion *R); -}; - -} // end anonymous namespace - - -StoreManager* ento::CreateBasicStoreManager(GRStateManager& StMgr) { - return new BasicStoreManager(StMgr); -} - -static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { - bool foundPointer = false; - while (1) { - const PointerType *PT = T->getAs<PointerType>(); - if (!PT) { - if (!foundPointer) - return false; - - // intptr_t* or intptr_t**, etc? - if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy)) - return true; - - QualType X = C.getCanonicalType(T).getUnqualifiedType(); - return X == C.VoidTy; - } - - foundPointer = true; - T = PT->getPointeeType(); - } -} - -SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) { - const VarRegion *VR = dyn_cast<VarRegion>(R); - if (!VR) - return UnknownVal(); - - const VarDecl *VD = VR->getDecl(); - QualType T = VD->getType(); - - // Only handle simple types that we can symbolicate. - if (!SymbolManager::canSymbolicate(T) || !T->isScalarType()) - return UnknownVal(); - - // Globals and parameters start with symbolic values. - // Local variables initially are undefined. - - // Non-static globals may have had their values reset by invalidateRegions. - const MemSpaceRegion *MS = VR->getMemorySpace(); - if (isa<NonStaticGlobalSpaceRegion>(MS)) { - BindingsTy B = GetBindings(store); - // FIXME: Copy-and-pasted from RegionStore.cpp. - if (BindingsTy::data_type *Val = B.lookup(MS)) { - if (SymbolRef parentSym = Val->getAsSymbol()) - return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R); - - if (Val->isZeroConstant()) - return svalBuilder.makeZeroVal(T); - - if (Val->isUnknownOrUndef()) - return *Val; - - assert(0 && "Unknown default value."); - } - } - - if (VR->hasGlobalsOrParametersStorage() || - isa<UnknownSpaceRegion>(VR->getMemorySpace())) - return svalBuilder.getRegionValueSymbolVal(R); - - return UndefinedVal(); -} - -SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) { - if (isa<UnknownVal>(loc)) - return UnknownVal(); - - assert(!isa<UndefinedVal>(loc)); - - switch (loc.getSubKind()) { - - case loc::MemRegionKind: { - const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); - - if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || - isa<CXXThisRegion>(R))) - return UnknownVal(); - - BindingsTy B = GetBindings(store); - BindingsTy::data_type *Val = B.lookup(R); - const TypedRegion *TR = cast<TypedRegion>(R); - - if (Val) - return CastRetrievedVal(*Val, TR, T); - - SVal V = LazyRetrieve(store, TR); - return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T); - } - - case loc::ObjCPropRefKind: - case loc::ConcreteIntKind: - // Support direct accesses to memory. It's up to individual checkers - // to flag an error. - return UnknownVal(); - - default: - assert (false && "Invalid Loc."); - break; - } - - return UnknownVal(); -} - -StoreRef BasicStoreManager::Bind(Store store, Loc loc, SVal V) { - if (isa<loc::ConcreteInt>(loc)) - return StoreRef(store, *this); - - const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); - - // Special case: a default symbol assigned to the NonStaticGlobalsSpaceRegion - // that is used to derive other symbols. - if (isa<NonStaticGlobalSpaceRegion>(R)) { - BindingsTy B = GetBindings(store); - return StoreRef(VBFactory.add(B, R, V).getRoot(), *this); - } - - // Special case: handle store of pointer values (Loc) to pointers via - // a cast to intXX_t*, void*, etc. This is needed to handle - // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier. - if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V)) - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // FIXME: Should check for index 0. - QualType T = ER->getLocationType(); - - if (isHigherOrderRawPtr(T, Ctx)) - R = ER->getSuperRegion(); - } - - if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || isa<CXXThisRegion>(R))) - return StoreRef(store, *this); - - const TypedRegion *TyR = cast<TypedRegion>(R); - - // Do not bind to arrays. We need to explicitly check for this so that - // we do not encounter any weirdness of trying to load/store from arrays. - if (TyR->isBoundable() && TyR->getValueType()->isArrayType()) - return StoreRef(store, *this); - - if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) { - // Only convert 'V' to a location iff the underlying region type - // is a location as well. - // FIXME: We are allowing a store of an arbitrary location to - // a pointer. We may wish to flag a type error here if the types - // are incompatible. This may also cause lots of breakage - // elsewhere. Food for thought. - if (TyR->isBoundable() && Loc::isLocType(TyR->getValueType())) - V = X->getLoc(); - } - - BindingsTy B = GetBindings(store); - return StoreRef(V.isUnknown() - ? VBFactory.remove(B, R).getRoot() - : VBFactory.add(B, R, V).getRoot(), *this); -} - -StoreRef BasicStoreManager::Remove(Store store, Loc loc) { - switch (loc.getSubKind()) { - case loc::MemRegionKind: { - const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); - - if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || - isa<CXXThisRegion>(R))) - return StoreRef(store, *this); - - return StoreRef(VBFactory.remove(GetBindings(store), R).getRoot(), *this); - } - default: - assert ("Remove for given Loc type not yet implemented."); - return StoreRef(store, *this); - } -} - -StoreRef BasicStoreManager::removeDeadBindings(Store store, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) -{ - BindingsTy B = GetBindings(store); - typedef SVal::symbol_iterator symbol_iterator; - - // Iterate over the variable bindings. - for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { - if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) { - if (SymReaper.isLive(VR)) - RegionRoots.push_back(VR); - else - continue; - } - else if (isa<ObjCIvarRegion>(I.getKey()) || - isa<NonStaticGlobalSpaceRegion>(I.getKey()) || - isa<CXXThisRegion>(I.getKey())) - RegionRoots.push_back(I.getKey()); - else - continue; - - // Mark the bindings in the data as live. - SVal X = I.getData(); - for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) - SymReaper.markLive(*SI); - } - - // Scan for live variables and live symbols. - llvm::SmallPtrSet<const MemRegion*, 10> Marked; - - while (!RegionRoots.empty()) { - const MemRegion* MR = RegionRoots.back(); - RegionRoots.pop_back(); - - while (MR) { - if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) { - SymReaper.markLive(SymR->getSymbol()); - break; - } - else if (isa<VarRegion>(MR) || isa<ObjCIvarRegion>(MR) || - isa<NonStaticGlobalSpaceRegion>(MR) || isa<CXXThisRegion>(MR)) { - if (Marked.count(MR)) - break; - - Marked.insert(MR); - SVal X = Retrieve(store, loc::MemRegionVal(MR)); - - // FIXME: We need to handle symbols nested in region definitions. - for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI) - SymReaper.markLive(*SI); - - if (!isa<loc::MemRegionVal>(X)) - break; - - const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X); - RegionRoots.push_back(LVD.getRegion()); - break; - } - else if (const SubRegion* R = dyn_cast<SubRegion>(MR)) - MR = R->getSuperRegion(); - else - break; - } - } - - // Remove dead variable bindings. - StoreRef newStore(store, *this); - for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { - const MemRegion* R = I.getKey(); - - if (!Marked.count(R)) { - newStore = Remove(newStore.getStore(), svalBuilder.makeLoc(R)); - SVal X = I.getData(); - - for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) - SymReaper.maybeDead(*SI); - } - } - - return newStore; -} - -StoreRef BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, - const MemRegion *SelfRegion, - Store St) { - - StoreRef newStore(St, *this); - - for (Stmt::child_iterator CI=B->child_begin(), CE=B->child_end(); - CI != CE; ++CI) { - - if (!*CI) - continue; - - // Check if the statement is an ivar reference. We only - // care about self.ivar. - if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(*CI)) { - const Expr *Base = IV->getBase()->IgnoreParenCasts(); - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) { - if (DR->getDecl() == SelfDecl) { - const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(), - SelfRegion); - SVal X = svalBuilder.getRegionValueSymbolVal(IVR); - newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(IVR), X); - } - } - } - else - newStore = scanForIvars(*CI, SelfDecl, SelfRegion, newStore.getStore()); - } - - return newStore; -} - -StoreRef BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { - // The LiveVariables information already has a compilation of all VarDecls - // used in the function. Iterate through this set, and "symbolicate" - // any VarDecl whose value originally comes from outside the function. - typedef LiveVariables::AnalysisDataTy LVDataTy; - LVDataTy& D = InitLoc->getLiveVariables()->getAnalysisData(); - StoreRef St(VBFactory.getEmptyMap().getRoot(), *this); - - for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) { - const NamedDecl* ND = I->first; - - // Handle implicit parameters. - if (const ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) { - const Decl& CD = *InitLoc->getDecl(); - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) { - if (MD->getSelfDecl() == PD) { - // FIXME: Add type constraints (when they become available) to - // SelfRegion? (i.e., it implements MD->getClassInterface()). - const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc); - const MemRegion *SelfRegion = - svalBuilder.getRegionValueSymbolVal(VR).getAsRegion(); - assert(SelfRegion); - St = Bind(St.getStore(), svalBuilder.makeLoc(VR), - loc::MemRegionVal(SelfRegion)); - // Scan the method for ivar references. While this requires an - // entire AST scan, the cost should not be high in practice. - St = scanForIvars(MD->getBody(), PD, SelfRegion, St.getStore()); - } - } - } - } - - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(InitLoc->getDecl())) { - // For C++ non-static member variables, add a symbolic region for 'this' in - // the initial stack frame. - if (MD->isInstance()) { - QualType ThisT = MD->getThisType(StateMgr.getContext()); - MemRegionManager &RegMgr = svalBuilder.getRegionManager(); - const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc); - SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR); - St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV); - } - } - - return St; -} - -StoreRef BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, - SVal* InitVal) { - - BasicValueFactory& BasicVals = StateMgr.getBasicVals(); - const VarDecl *VD = VR->getDecl(); - StoreRef newStore(store, *this); - - // BasicStore does not model arrays and structs. - if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType()) - return newStore; - - if (VD->hasGlobalStorage()) { - // Handle variables with global storage: extern, static, PrivateExtern. - - // FIXME:: static variables may have an initializer, but the second time a - // function is called those values may not be current. Currently, a function - // will not be called more than once. - - // Static global variables should not be visited here. - assert(!(VD->getStorageClass() == SC_Static && - VD->isFileVarDecl())); - - // Process static variables. - if (VD->getStorageClass() == SC_Static) { - // C99: 6.7.8 Initialization - // If an object that has static storage duration is not initialized - // explicitly, then: - // -if it has pointer type, it is initialized to a null pointer; - // -if it has arithmetic type, it is initialized to (positive or - // unsigned) zero; - if (!InitVal) { - QualType T = VD->getType(); - if (Loc::isLocType(T)) - newStore = Bind(store, loc::MemRegionVal(VR), - loc::ConcreteInt(BasicVals.getValue(0, T))); - else if (T->isIntegerType() && T->isScalarType()) - newStore = Bind(store, loc::MemRegionVal(VR), - nonloc::ConcreteInt(BasicVals.getValue(0, T))); - } else { - newStore = Bind(store, loc::MemRegionVal(VR), *InitVal); - } - } - } else { - // Process local scalar variables. - QualType T = VD->getType(); - // BasicStore only supports scalars. - if ((T->isScalarType() || T->isReferenceType()) && - svalBuilder.getSymbolManager().canSymbolicate(T)) { - SVal V = InitVal ? *InitVal : UndefinedVal(); - newStore = Bind(store, loc::MemRegionVal(VR), V); - } - } - - return newStore; -} - -void BasicStoreManager::print(Store store, llvm::raw_ostream& Out, - const char* nl, const char *sep) { - - BindingsTy B = GetBindings(store); - Out << "Variables:" << nl; - - bool isFirst = true; - - for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) { - if (isFirst) - isFirst = false; - else - Out << nl; - - Out << ' ' << I.getKey() << " : " << I.getData(); - } -} - - -void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) { - BindingsTy B = GetBindings(store); - - for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) - if (!f.HandleBinding(*this, store, I.getKey(), I.getData())) - return; - -} - -StoreManager::BindingsHandler::~BindingsHandler() {} - -//===----------------------------------------------------------------------===// -// Binding invalidation. -//===----------------------------------------------------------------------===// - - -StoreRef BasicStoreManager::invalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *End, - const Expr *E, unsigned Count, - InvalidatedSymbols &IS, - bool invalidateGlobals, - InvalidatedRegions *Regions) { - StoreRef newStore(store, *this); - - if (invalidateGlobals) { - BindingsTy B = GetBindings(store); - for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) { - const MemRegion *R = I.getKey(); - if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace())) - newStore = invalidateRegion(newStore.getStore(), R, E, Count, IS); - } - } - - for ( ; I != End ; ++I) { - const MemRegion *R = *I; - // Don't invalidate globals twice. - if (invalidateGlobals) { - if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace())) - continue; - } - newStore = invalidateRegion(newStore.getStore(), *I, E, Count, IS); - if (Regions) - Regions->push_back(R); - } - - // FIXME: This is copy-and-paste from RegionStore.cpp. - if (invalidateGlobals) { - // Bind the non-static globals memory space to a new symbol that we will - // use to derive the bindings for all non-static globals. - const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(); - SVal V = - svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, E, - /* symbol type, doesn't matter */ Ctx.IntTy, - Count); - - newStore = Bind(newStore.getStore(), loc::MemRegionVal(GS), V); - if (Regions) - Regions->push_back(GS); - } - - return newStore; -} - - -StoreRef BasicStoreManager::invalidateRegion(Store store, - const MemRegion *R, - const Expr *E, - unsigned Count, - InvalidatedSymbols &IS) { - R = R->StripCasts(); - - if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) - return StoreRef(store, *this); - - BindingsTy B = GetBindings(store); - if (BindingsTy::data_type *Val = B.lookup(R)) { - if (SymbolRef Sym = Val->getAsSymbol()) - IS.insert(Sym); - } - - QualType T = cast<TypedRegion>(R)->getValueType(); - SVal V = svalBuilder.getConjuredSymbolVal(R, E, T, Count); - return Bind(store, loc::MemRegionVal(R), V); -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 0ed4ff1..fe96700 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -27,7 +27,7 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID, const StoreRef &store, - const TypedRegion *region) { + const TypedValueRegion *region) { ID.AddPointer(store.getStore()); ID.AddPointer(region); } @@ -70,7 +70,7 @@ BasicValueFactory::~BasicValueFactory() { const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { llvm::FoldingSetNodeID ID; - void* InsertPos; + void *InsertPos; typedef llvm::FoldingSetNodeWrapper<llvm::APSInt> FoldNodeTy; X.Profile(ID); @@ -113,7 +113,7 @@ BasicValueFactory::getCompoundValData(QualType T, llvm::FoldingSetNodeID ID; CompoundValData::Profile(ID, T, Vals); - void* InsertPos; + void *InsertPos; CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); @@ -128,10 +128,10 @@ BasicValueFactory::getCompoundValData(QualType T, const LazyCompoundValData* BasicValueFactory::getLazyCompoundValData(const StoreRef &store, - const TypedRegion *region) { + const TypedValueRegion *region) { llvm::FoldingSetNodeID ID; LazyCompoundValData::Profile(ID, store, region); - void* InsertPos; + void *InsertPos; LazyCompoundValData *D = LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); @@ -243,7 +243,7 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { if (!PersistentSVals) PersistentSVals = new PersistentSValsTy(); llvm::FoldingSetNodeID ID; - void* InsertPos; + void *InsertPos; V.Profile(ID); ID.AddPointer((void*) Data); @@ -268,7 +268,7 @@ BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy(); llvm::FoldingSetNodeID ID; - void* InsertPos; + void *InsertPos; V1.Profile(ID); V2.Profile(ID); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp index ed52b6b..74d761e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BlockCounter.cpp @@ -48,11 +48,11 @@ public: typedef llvm::ImmutableMap<CountKey, unsigned> CountMap; -static inline CountMap GetMap(void* D) { +static inline CountMap GetMap(void *D) { return CountMap(static_cast<CountMap::TreeTy*>(D)); } -static inline CountMap::Factory& GetFactory(void* F) { +static inline CountMap::Factory& GetFactory(void *F) { return *static_cast<CountMap::Factory*>(F); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 8b5d383..fbbdb04 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -33,52 +33,31 @@ using namespace clang; using namespace ento; BugReporterVisitor::~BugReporterVisitor() {} -BugReporterContext::~BugReporterContext() { - for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) - if ((*I)->isOwnedByReporterContext()) delete *I; -} - -void BugReporterContext::addVisitor(BugReporterVisitor* visitor) { - if (!visitor) - return; - - llvm::FoldingSetNodeID ID; - visitor->Profile(ID); - void *InsertPos; - - if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) { - delete visitor; - return; - } - - CallbacksSet.InsertNode(visitor, InsertPos); - Callbacks = F.add(visitor, Callbacks); -} //===----------------------------------------------------------------------===// // Helper routines for walking the ExplodedGraph and fetching statements. //===----------------------------------------------------------------------===// -static inline const Stmt* GetStmt(const ProgramPoint &P) { +static inline const Stmt *GetStmt(const ProgramPoint &P) { if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P)) return SP->getStmt(); - else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) + else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) return BE->getSrc()->getTerminator(); return 0; } static inline const ExplodedNode* -GetPredecessorNode(const ExplodedNode* N) { +GetPredecessorNode(const ExplodedNode *N) { return N->pred_empty() ? NULL : *(N->pred_begin()); } static inline const ExplodedNode* -GetSuccessorNode(const ExplodedNode* N) { +GetSuccessorNode(const ExplodedNode *N) { return N->succ_empty() ? NULL : *(N->succ_begin()); } -static const Stmt* GetPreviousStmt(const ExplodedNode* N) { +static const Stmt *GetPreviousStmt(const ExplodedNode *N) { for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N)) if (const Stmt *S = GetStmt(N->getLocation())) return S; @@ -86,7 +65,7 @@ static const Stmt* GetPreviousStmt(const ExplodedNode* N) { return 0; } -static const Stmt* GetNextStmt(const ExplodedNode* N) { +static const Stmt *GetNextStmt(const ExplodedNode *N) { for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N)) if (const Stmt *S = GetStmt(N->getLocation())) { // Check if the statement is '?' or '&&'/'||'. These are "merges", @@ -104,11 +83,6 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) { default: break; } - - // Some expressions don't have locations. - if (S->getLocStart().isInvalid()) - continue; - return S; } @@ -116,7 +90,7 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) { } static inline const Stmt* -GetCurrentOrPreviousStmt(const ExplodedNode* N) { +GetCurrentOrPreviousStmt(const ExplodedNode *N) { if (const Stmt *S = GetStmt(N->getLocation())) return S; @@ -124,7 +98,7 @@ GetCurrentOrPreviousStmt(const ExplodedNode* N) { } static inline const Stmt* -GetCurrentOrNextStmt(const ExplodedNode* N) { +GetCurrentOrNextStmt(const ExplodedNode *N) { if (const Stmt *S = GetStmt(N->getLocation())) return S; @@ -145,7 +119,7 @@ public: NodeMapClosure(NodeBackMap *m) : M(*m) {} ~NodeMapClosure() {} - const ExplodedNode* getOriginalNode(const ExplodedNode* N) { + const ExplodedNode *getOriginalNode(const ExplodedNode *N) { NodeBackMap::iterator I = M.find(N); return I == M.end() ? 0 : I->second; } @@ -153,25 +127,29 @@ public: class PathDiagnosticBuilder : public BugReporterContext { BugReport *R; - PathDiagnosticClient *PDC; + PathDiagnosticConsumer *PDC; llvm::OwningPtr<ParentMap> PM; NodeMapClosure NMC; public: PathDiagnosticBuilder(GRBugReporter &br, BugReport *r, NodeBackMap *Backmap, - PathDiagnosticClient *pdc) + PathDiagnosticConsumer *pdc) : BugReporterContext(br), - R(r), PDC(pdc), NMC(Backmap) { - addVisitor(R); - } + R(r), PDC(pdc), NMC(Backmap) {} - PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N); + PathDiagnosticLocation ExecutionContinues(const ExplodedNode *N); - PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os, - const ExplodedNode* N); + PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream &os, + const ExplodedNode *N); + + BugReport *getBugReport() { return R; } Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); } + const LocationContext* getLocationContext() { + return R->getErrorNode()->getLocationContext(); + } + ParentMap& getParentMap() { return R->getErrorNode()->getParentMap(); } const Stmt *getParent(const Stmt *S) { @@ -182,8 +160,8 @@ public: PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S); - PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const { - return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive; + PathDiagnosticConsumer::PathGenerationScheme getGenerationScheme() const { + return PDC ? PDC->getGenerationScheme() : PathDiagnosticConsumer::Extensive; } bool supportsLogicalOpControlFlow() const { @@ -193,17 +171,17 @@ public: } // end anonymous namespace PathDiagnosticLocation -PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) { +PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) { if (const Stmt *S = GetNextStmt(N)) - return PathDiagnosticLocation(S, getSourceManager()); + return PathDiagnosticLocation(S, getSourceManager(), getLocationContext()); - return FullSourceLoc(N->getLocationContext()->getDecl()->getBodyRBrace(), - getSourceManager()); + return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(), + getSourceManager()); } PathDiagnosticLocation -PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os, - const ExplodedNode* N) { +PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os, + const ExplodedNode *N) { // Slow, but probably doesn't matter. if (os.str().empty()) @@ -213,7 +191,7 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os, if (Loc.asStmt()) os << "Execution continues on line " - << getSourceManager().getInstantiationLineNumber(Loc.asLocation()) + << getSourceManager().getExpansionLineNumber(Loc.asLocation()) << '.'; else { os << "Execution jumps to the end of the "; @@ -253,9 +231,10 @@ static bool IsNested(const Stmt *S, ParentMap &PM) { PathDiagnosticLocation PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { - assert(S && "Null Stmt* passed to getEnclosingStmtLocation"); + assert(S && "Null Stmt *passed to getEnclosingStmtLocation"); ParentMap &P = getParentMap(); SourceManager &SMgr = getSourceManager(); + const LocationContext *LC = getLocationContext(); while (IsNested(S, P)) { const Stmt *Parent = P.getParentIgnoreParens(S); @@ -267,44 +246,44 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { case Stmt::BinaryOperatorClass: { const BinaryOperator *B = cast<BinaryOperator>(Parent); if (B->isLogicalOp()) - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); break; } case Stmt::CompoundStmtClass: case Stmt::StmtExprClass: - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); case Stmt::ChooseExprClass: // Similar to '?' if we are referring to condition, just have the edge // point to the entire choose expression. if (cast<ChooseExpr>(Parent)->getCond() == S) - return PathDiagnosticLocation(Parent, SMgr); + return PathDiagnosticLocation(Parent, SMgr, LC); else - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: // For '?', if we are referring to condition, just have the edge point // to the entire '?' expression. if (cast<AbstractConditionalOperator>(Parent)->getCond() == S) - return PathDiagnosticLocation(Parent, SMgr); + return PathDiagnosticLocation(Parent, SMgr, LC); else - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); case Stmt::DoStmtClass: - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); case Stmt::ForStmtClass: if (cast<ForStmt>(Parent)->getBody() == S) - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); break; case Stmt::IfStmtClass: if (cast<IfStmt>(Parent)->getCond() != S) - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); break; case Stmt::ObjCForCollectionStmtClass: if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S) - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); break; case Stmt::WhileStmtClass: if (cast<WhileStmt>(Parent)->getCond() != S) - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); break; default: break; @@ -322,7 +301,7 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { switch (Parent->getStmtClass()) { case Stmt::ForStmtClass: case Stmt::ObjCForCollectionStmtClass: - return PathDiagnosticLocation(Parent, SMgr); + return PathDiagnosticLocation(Parent, SMgr, LC); default: break; } @@ -335,20 +314,20 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { if (const ForStmt *FS = dyn_cast_or_null<ForStmt>(P.getParentIgnoreParens(S))) { if (FS->getInit() == S) - return PathDiagnosticLocation(FS, SMgr); + return PathDiagnosticLocation(FS, SMgr, LC); } } - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr, LC); } //===----------------------------------------------------------------------===// // ScanNotableSymbols: closure-like callback for scanning Store bindings. //===----------------------------------------------------------------------===// -static const VarDecl* -GetMostRecentVarDeclBinding(const ExplodedNode* N, - GRStateManager& VMgr, SVal X) { +static const VarDecl* GetMostRecentVarDeclBinding(const ExplodedNode *N, + ProgramStateManager& VMgr, + SVal X) { for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) { @@ -357,7 +336,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N, if (!isa<PostStmt>(P)) continue; - const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt()); + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt()); if (!DR) continue; @@ -367,7 +346,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N, if (X != Y) continue; - const VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()); + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) continue; @@ -383,19 +362,29 @@ class NotableSymbolHandler : public StoreManager::BindingsHandler { SymbolRef Sym; - const GRState* PrevSt; - const Stmt* S; - GRStateManager& VMgr; - const ExplodedNode* Pred; + const ProgramState *PrevSt; + const Stmt *S; + ProgramStateManager& VMgr; + const ExplodedNode *Pred; PathDiagnostic& PD; BugReporter& BR; public: - NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s, - GRStateManager& vmgr, const ExplodedNode* pred, - PathDiagnostic& pd, BugReporter& br) - : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {} + NotableSymbolHandler(SymbolRef sym, + const ProgramState *prevst, + const Stmt *s, + ProgramStateManager& vmgr, + const ExplodedNode *pred, + PathDiagnostic& pd, + BugReporter& br) + : Sym(sym), + PrevSt(prevst), + S(s), + VMgr(vmgr), + Pred(pred), + PD(pd), + BR(br) {} bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal V) { @@ -422,14 +411,14 @@ public: return true; // What variable did we assign to? - DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts()); + DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts()); if (!DR) return true; VD = dyn_cast<VarDecl>(DR->getDecl()); } - else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) { + else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { // FIXME: Eventually CFGs won't have DeclStmts. Right now we // assume that each DeclStmt has a single Decl. This invariant // holds by construction in the CFG. @@ -440,19 +429,20 @@ public: return true; // What is the most recently referenced variable with this binding? - const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V); + const VarDecl *MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V); if (!MostRecent) return true; // Create the diagnostic. - FullSourceLoc L(S->getLocStart(), BR.getSourceManager()); - if (Loc::isLocType(VD->getType())) { - std::string msg = "'" + std::string(VD->getNameAsString()) + - "' now aliases '" + MostRecent->getNameAsString() + "'"; - - PD.push_front(new PathDiagnosticEventPiece(L, msg)); + llvm::SmallString<64> buf; + llvm::raw_svector_ostream os(buf); + os << '\'' << *VD << "' now aliases '" << *MostRecent << '\''; + PathDiagnosticLocation L = + PathDiagnosticLocation::createBegin(S, BR.getSourceManager(), + Pred->getLocationContext()); + PD.push_front(new PathDiagnosticEventPiece(L, os.str())); } return true; @@ -460,20 +450,20 @@ public: }; } -static void HandleNotableSymbol(const ExplodedNode* N, - const Stmt* S, +static void HandleNotableSymbol(const ExplodedNode *N, + const Stmt *S, SymbolRef Sym, BugReporter& BR, PathDiagnostic& PD) { - const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin(); - const GRState* PrevSt = Pred ? Pred->getState() : 0; + const ExplodedNode *Pred = N->pred_empty() ? 0 : *N->pred_begin(); + const ProgramState *PrevSt = Pred ? Pred->getState() : 0; if (!PrevSt) return; // Look at the region bindings of the current state that map to the // specified symbol. Are any of them not in the previous state? - GRStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager(); + ProgramStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager(); NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR); cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H); } @@ -483,13 +473,13 @@ class ScanNotableSymbols : public StoreManager::BindingsHandler { llvm::SmallSet<SymbolRef, 10> AlreadyProcessed; - const ExplodedNode* N; - const Stmt* S; + const ExplodedNode *N; + const Stmt *S; GRBugReporter& BR; PathDiagnostic& PD; public: - ScanNotableSymbols(const ExplodedNode* n, const Stmt* s, + ScanNotableSymbols(const ExplodedNode *n, const Stmt *s, GRBugReporter& br, PathDiagnostic& pd) : N(n), S(s), BR(br), PD(pd) {} @@ -526,7 +516,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, const ExplodedNode *N) { SourceManager& SMgr = PDB.getSourceManager(); - const ExplodedNode* NextNode = N->pred_empty() + const LocationContext *LC = PDB.getLocationContext(); + const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; @@ -534,15 +525,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, ProgramPoint P = N->getLocation(); - if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) { - const CFGBlock* Src = BE->getSrc(); - const CFGBlock* Dst = BE->getDst(); - const Stmt* T = Src->getTerminator(); + if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + const CFGBlock *Src = BE->getSrc(); + const CFGBlock *Dst = BE->getDst(); + const Stmt *T = Src->getTerminator(); if (!T) continue; - FullSourceLoc Start(T->getLocStart(), SMgr); + PathDiagnosticLocation Start = + PathDiagnosticLocation::createBegin(T, SMgr, + N->getLocationContext()); switch (T->getStmtClass()) { default: @@ -550,7 +543,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, case Stmt::GotoStmtClass: case Stmt::IndirectGotoStmtClass: { - const Stmt* S = GetNextStmt(N); + const Stmt *S = GetNextStmt(N); if (!S) continue; @@ -560,7 +553,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S); os << "Control jumps to line " - << End.asLocation().getInstantiationLineNumber(); + << End.asLocation().getExpansionLineNumber(); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); break; @@ -571,45 +564,45 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, std::string sbuf; llvm::raw_string_ostream os(sbuf); - if (const Stmt* S = Dst->getLabel()) { - PathDiagnosticLocation End(S, SMgr); + if (const Stmt *S = Dst->getLabel()) { + PathDiagnosticLocation End(S, SMgr, LC); switch (S->getStmtClass()) { default: os << "No cases match in the switch statement. " "Control jumps to line " - << End.asLocation().getInstantiationLineNumber(); + << End.asLocation().getExpansionLineNumber(); break; case Stmt::DefaultStmtClass: os << "Control jumps to the 'default' case at line " - << End.asLocation().getInstantiationLineNumber(); + << End.asLocation().getExpansionLineNumber(); break; case Stmt::CaseStmtClass: { os << "Control jumps to 'case "; - const CaseStmt* Case = cast<CaseStmt>(S); - const Expr* LHS = Case->getLHS()->IgnoreParenCasts(); + const CaseStmt *Case = cast<CaseStmt>(S); + const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); // Determine if it is an enum. bool GetRawInt = true; - if (const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) { + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) { // FIXME: Maybe this should be an assertion. Are there cases // were it is not an EnumConstantDecl? - const EnumConstantDecl* D = + const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(DR->getDecl()); if (D) { GetRawInt = false; - os << D; + os << *D; } } if (GetRawInt) - os << LHS->EvaluateAsInt(PDB.getASTContext()); + os << LHS->EvaluateKnownConstInt(PDB.getASTContext()); os << ":' at line " - << End.asLocation().getInstantiationLineNumber(); + << End.asLocation().getExpansionLineNumber(); break; } } @@ -673,14 +666,15 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (*(Src->succ_begin()+1) == Dst) { os << "false"; - PathDiagnosticLocation End(B->getLHS(), SMgr); - PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr); + PathDiagnosticLocation End(B->getLHS(), SMgr, LC); + PathDiagnosticLocation Start = + PathDiagnosticLocation::createOperatorLoc(B, SMgr); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } else { os << "true"; - PathDiagnosticLocation Start(B->getLHS(), SMgr); + PathDiagnosticLocation Start(B->getLHS(), SMgr, LC); PathDiagnosticLocation End = PDB.ExecutionContinues(N); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); @@ -692,15 +686,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (*(Src->succ_begin()+1) == Dst) { os << "false"; - PathDiagnosticLocation Start(B->getLHS(), SMgr); + PathDiagnosticLocation Start(B->getLHS(), SMgr, LC); PathDiagnosticLocation End = PDB.ExecutionContinues(N); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } else { os << "true"; - PathDiagnosticLocation End(B->getLHS(), SMgr); - PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr); + PathDiagnosticLocation End(B->getLHS(), SMgr, LC); + PathDiagnosticLocation Start = + PathDiagnosticLocation::createOperatorLoc(B, SMgr); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } @@ -781,14 +776,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } if (NextNode) { - for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(), - E = PDB.visitor_end(); I!=E; ++I) { - if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) + // Add diagnostic pieces from custom visitors. + BugReport *R = PDB.getBugReport(); + for (BugReport::visitor_iterator I = R->visitor_begin(), + E = R->visitor_end(); I!=E; ++I) { + if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) PD.push_front(p); } } - if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) { + if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { // Scan the region bindings, and see if a "notable" symbol has a new // lval binding. ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD); @@ -882,11 +879,11 @@ class EdgeBuilder { } if (S != Original) - L = PathDiagnosticLocation(S, L.getManager()); + L = PathDiagnosticLocation(S, L.getManager(), PDB.getLocationContext()); } if (firstCharOnly) - L = PathDiagnosticLocation(L.asLocation()); + L = PathDiagnosticLocation::createSingleLocation(L); return L; } @@ -915,17 +912,14 @@ public: ~EdgeBuilder() { while (!CLocs.empty()) popLocation(); - + // Finally, add an initial edge from the start location of the first // statement (if it doesn't already exist). - // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. - if (const CompoundStmt *CS = - dyn_cast_or_null<CompoundStmt>(PDB.getCodeDecl().getBody())) - if (!CS->body_empty()) { - SourceLocation Loc = (*CS->body_begin())->getLocStart(); - rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager())); - } - + PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin( + PDB.getLocationContext(), + PDB.getSourceManager()); + if (L.isValid()) + rawAddEdge(L); } void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false); @@ -974,15 +968,15 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container, SourceRange ContaineeR = Containee.asRange(); SourceManager &SM = PDB.getSourceManager(); - SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin()); - SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd()); - SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin()); - SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd()); + SourceLocation ContainerRBeg = SM.getExpansionLoc(ContainerR.getBegin()); + SourceLocation ContainerREnd = SM.getExpansionLoc(ContainerR.getEnd()); + SourceLocation ContaineeRBeg = SM.getExpansionLoc(ContaineeR.getBegin()); + SourceLocation ContaineeREnd = SM.getExpansionLoc(ContaineeR.getEnd()); - unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg); - unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd); - unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg); - unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd); + unsigned ContainerBegLine = SM.getExpansionLineNumber(ContainerRBeg); + unsigned ContainerEndLine = SM.getExpansionLineNumber(ContainerREnd); + unsigned ContaineeBegLine = SM.getExpansionLineNumber(ContaineeRBeg); + unsigned ContaineeEndLine = SM.getExpansionLineNumber(ContaineeREnd); assert(ContainerBegLine <= ContainerEndLine); assert(ContaineeBegLine <= ContaineeEndLine); @@ -990,11 +984,11 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container, return (ContainerBegLine <= ContaineeBegLine && ContainerEndLine >= ContaineeEndLine && (ContainerBegLine != ContaineeBegLine || - SM.getInstantiationColumnNumber(ContainerRBeg) <= - SM.getInstantiationColumnNumber(ContaineeRBeg)) && + SM.getExpansionColumnNumber(ContainerRBeg) <= + SM.getExpansionColumnNumber(ContaineeRBeg)) && (ContainerEndLine != ContaineeEndLine || - SM.getInstantiationColumnNumber(ContainerREnd) >= - SM.getInstantiationColumnNumber(ContainerREnd))); + SM.getExpansionColumnNumber(ContainerREnd) >= + SM.getExpansionColumnNumber(ContainerREnd))); } void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { @@ -1010,8 +1004,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { return; // FIXME: Ignore intra-macro edges for now. - if (NewLocClean.asLocation().getInstantiationLoc() == - PrevLocClean.asLocation().getInstantiationLoc()) + if (NewLocClean.asLocation().getExpansionLoc() == + PrevLocClean.asLocation().getExpansionLoc()) return; PD.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean)); @@ -1099,7 +1093,7 @@ void EdgeBuilder::addContext(const Stmt *S) { if (!S) return; - PathDiagnosticLocation L(S, PDB.getSourceManager()); + PathDiagnosticLocation L(S, PDB.getSourceManager(), PDB.getLocationContext()); while (!CLocs.empty()) { const PathDiagnosticLocation &TopContextLoc = CLocs.back(); @@ -1124,8 +1118,9 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N) { EdgeBuilder EB(PD, PDB); + const SourceManager& SM = PDB.getSourceManager(); - const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); + const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; NextNode = GetPredecessorNode(N); @@ -1139,7 +1134,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getDst()->getLoopTarget()) { - PathDiagnosticLocation L(Loop, PDB.getSourceManager()); + PathDiagnosticLocation L(Loop, SM, PDB.getLocationContext()); const CompoundStmt *CS = NULL; if (!Term) { @@ -1157,9 +1152,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PD.push_front(p); if (CS) { - PathDiagnosticLocation BL(CS->getRBracLoc(), - PDB.getSourceManager()); - BL = PathDiagnosticLocation(BL.asLocation()); + PathDiagnosticLocation BL = + PathDiagnosticLocation::createEndBrace(CS, SM); EB.addEdge(BL); } } @@ -1188,9 +1182,11 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, if (!NextNode) continue; - for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(), - E = PDB.visitor_end(); I!=E; ++I) { - if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) { + // Add pieces from custom visitors. + BugReport *R = PDB.getBugReport(); + for (BugReport::visitor_iterator I = R->visitor_begin(), + E = R->visitor_end(); I!=E; ++I) { + if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) { const PathDiagnosticLocation &Loc = p->getLocation(); EB.addEdge(Loc, true); PD.push_front(p); @@ -1211,14 +1207,58 @@ void BugType::FlushReports(BugReporter &BR) {} //===----------------------------------------------------------------------===// // Methods for BugReport and subclasses. //===----------------------------------------------------------------------===// -BugReport::~BugReport() {} -RangedBugReport::~RangedBugReport() {} -const Stmt* BugReport::getStmt() const { +void BugReport::addVisitor(BugReporterVisitor* visitor) { + if (!visitor) + return; + + llvm::FoldingSetNodeID ID; + visitor->Profile(ID); + void *InsertPos; + + if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) { + delete visitor; + return; + } + + CallbacksSet.InsertNode(visitor, InsertPos); + Callbacks = F.add(visitor, Callbacks); +} + +BugReport::~BugReport() { + for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) { + delete *I; + } +} + +void BugReport::Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddPointer(&BT); + hash.AddString(Description); + if (Location.isValid()) { + Location.Profile(hash); + } else { + assert(ErrorNode); + hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode)); + } + + for (SmallVectorImpl<SourceRange>::const_iterator I = + Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const SourceRange range = *I; + if (!range.isValid()) + continue; + hash.AddInteger(range.getBegin().getRawEncoding()); + hash.AddInteger(range.getEnd().getRawEncoding()); + } +} + +const Stmt *BugReport::getStmt() const { + if (!ErrorNode) + return 0; + ProgramPoint ProgP = ErrorNode->getLocation(); const Stmt *S = NULL; - if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) { + if (BlockEntrance *BE = dyn_cast<BlockEntrance>(&ProgP)) { CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit(); if (BE->getBlock() == &Exit) S = GetPreviousStmt(ErrorNode); @@ -1229,61 +1269,47 @@ const Stmt* BugReport::getStmt() const { return S; } -PathDiagnosticPiece* -BugReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndPathNode) { - - const Stmt* S = getStmt(); - - if (!S) - return NULL; - - BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = getRanges(); - PathDiagnosticLocation L(S, BRC.getSourceManager()); - - // Only add the statement itself as a range if we didn't specify any - // special ranges for this report. - PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription(), - Beg == End); +std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator> +BugReport::getRanges() { + // If no custom ranges, add the range of the statement corresponding to + // the error node. + if (Ranges.empty()) { + if (const Expr *E = dyn_cast_or_null<Expr>(getStmt())) + addRange(E->getSourceRange()); + else + return std::make_pair(ranges_iterator(), ranges_iterator()); + } - for (; Beg != End; ++Beg) - P->addRange(*Beg); + // User-specified absence of range info. + if (Ranges.size() == 1 && !Ranges.begin()->isValid()) + return std::make_pair(ranges_iterator(), ranges_iterator()); - return P; + return std::make_pair(Ranges.begin(), Ranges.end()); } -std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator> -BugReport::getRanges() const { - if (const Expr* E = dyn_cast_or_null<Expr>(getStmt())) { - R = E->getSourceRange(); - assert(R.isValid()); - return std::make_pair(&R, &R+1); - } - else - return std::make_pair(ranges_iterator(), ranges_iterator()); -} +PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { + if (ErrorNode) { + assert(!Location.isValid() && + "Either Location or ErrorNode should be specified but not both."); + + if (const Stmt *S = GetCurrentOrPreviousStmt(ErrorNode)) { + const LocationContext *LC = ErrorNode->getLocationContext(); -SourceLocation BugReport::getLocation() const { - if (ErrorNode) - if (const Stmt* S = GetCurrentOrPreviousStmt(ErrorNode)) { // For member expressions, return the location of the '.' or '->'. if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) - return ME->getMemberLoc(); + return PathDiagnosticLocation::createMemberLoc(ME, SM); // For binary operators, return the location of the operator. if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) - return B->getOperatorLoc(); + return PathDiagnosticLocation::createOperatorLoc(B, SM); - return S->getLocStart(); + return PathDiagnosticLocation::createBegin(S, SM, LC); } + } else { + assert(Location.isValid()); + return Location; + } - return FullSourceLoc(); -} - -PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, - BugReporterContext &BRC) { - return NULL; + return PathDiagnosticLocation(); } //===----------------------------------------------------------------------===// @@ -1299,10 +1325,19 @@ BugReporterData::~BugReporterData() {} ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); } -GRStateManager& +ProgramStateManager& GRBugReporter::getStateManager() { return Eng.getStateManager(); } -BugReporter::~BugReporter() { FlushReports(); } +BugReporter::~BugReporter() { + FlushReports(); + + // Free the bug reports we are tracking. + typedef std::vector<BugReportEquivClass *> ContTy; + for (ContTy::iterator I = EQClassesVector.begin(), E = EQClassesVector.end(); + I != E; ++I) { + delete *I; + } +} void BugReporter::FlushReports() { if (BugTypes.isEmpty()) @@ -1312,10 +1347,10 @@ void BugReporter::FlushReports() { // warnings and new BugTypes. // FIXME: Only NSErrorChecker needs BugType's FlushReports. // Turn NSErrorChecker into a proper checker and remove this. - llvm::SmallVector<const BugType*, 16> bugTypes; + SmallVector<const BugType*, 16> bugTypes; for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) bugTypes.push_back(*I); - for (llvm::SmallVector<const BugType*, 16>::iterator + for (SmallVector<const BugType*, 16>::iterator I = bugTypes.begin(), E = bugTypes.end(); I != E; ++I) const_cast<BugType*>(*I)->FlushReports(*this); @@ -1344,7 +1379,7 @@ void BugReporter::FlushReports() { static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>, std::pair<ExplodedNode*, unsigned> > MakeReportGraph(const ExplodedGraph* G, - llvm::SmallVectorImpl<const ExplodedNode*> &nodes) { + SmallVectorImpl<const ExplodedNode*> &nodes) { // Create the trimmed graph. It will contain the shortest paths from the // error nodes to the root. In the new graph we should only have one @@ -1390,10 +1425,10 @@ MakeReportGraph(const ExplodedGraph* G, llvm::DenseMap<const void*,unsigned> Visited; unsigned cnt = 0; - const ExplodedNode* Root = 0; + const ExplodedNode *Root = 0; while (!WS.empty()) { - const ExplodedNode* Node = WS.front(); + const ExplodedNode *Node = WS.front(); WS.pop(); if (Visited.find(Node) != Visited.end()) @@ -1426,7 +1461,7 @@ MakeReportGraph(const ExplodedGraph* G, // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode* NewN = GNew->getNode(N->getLocation(), N->getState()); + ExplodedNode *NewN = GNew->getNode(N->getLocation(), N->getState()); // Store the mapping to the original node. llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N); @@ -1495,7 +1530,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { // Determine the instantiation location, which is the location we group // related PathDiagnosticPieces. SourceLocation InstantiationLoc = Loc.isMacroID() ? - SM.getInstantiationLoc(Loc) : + SM.getExpansionLoc(Loc) : SourceLocation(); if (Loc.isFileID()) { @@ -1517,7 +1552,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { PathDiagnosticMacroPiece *MacroGroup = 0; SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ? - SM.getInstantiationLoc(Loc) : + SM.getExpansionLoc(Loc) : SourceLocation(); // Walk the entire macro stack. @@ -1537,7 +1572,9 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) { // Create a new macro group and add it to the stack. - PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc); + PathDiagnosticMacroPiece *NewGroup = + new PathDiagnosticMacroPiece( + PathDiagnosticLocation::createSingleLocation(I->getLocation())); if (MacroGroup) MacroGroup->push_back(NewGroup); @@ -1569,11 +1606,11 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, - llvm::SmallVectorImpl<BugReport *> &bugReports) { + SmallVectorImpl<BugReport *> &bugReports) { assert(!bugReports.empty()); - llvm::SmallVector<const ExplodedNode *, 10> errorNodes; - for (llvm::SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(), + SmallVector<const ExplodedNode *, 10> errorNodes; + for (SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(), E = bugReports.end(); I != E; ++I) { errorNodes.push_back((*I)->getErrorNode()); } @@ -1594,22 +1631,36 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, const ExplodedNode *N = GPair.second.first; // Start building the path diagnostic... - PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient()); - - if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N)) - PD.push_back(Piece); + PathDiagnosticBuilder PDB(*this, R, BackMap.get(), + getPathDiagnosticConsumer()); + + // Register additional node visitors. + R->addVisitor(new NilReceiverBRVisitor()); + R->addVisitor(new ConditionBRVisitor()); + + // Generate the very last diagnostic piece - the piece is visible before + // the trace is expanded. + PathDiagnosticPiece *LastPiece = 0; + for (BugReport::visitor_iterator I = R->visitor_begin(), + E = R->visitor_end(); I!=E; ++I) { + if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { + assert (!LastPiece && + "There can only be one final piece in a diagnostic."); + LastPiece = Piece; + } + } + if (!LastPiece) + LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); + if (LastPiece) + PD.push_back(LastPiece); else return; - // Register node visitors. - R->registerInitialVisitors(PDB, N); - bugreporter::registerNilReceiverVisitor(PDB); - switch (PDB.getGenerationScheme()) { - case PathDiagnosticClient::Extensive: + case PathDiagnosticConsumer::Extensive: GenerateExtensivePathDiagnostic(PD, PDB, N); break; - case PathDiagnosticClient::Minimal: + case PathDiagnosticConsumer::Minimal: GenerateMinimalPathDiagnostic(PD, PDB, N); break; } @@ -1633,6 +1684,7 @@ void BugReporter::EmitReport(BugReport* R) { if (!EQ) { EQ = new BugReportEquivClass(R); EQClasses.InsertNode(EQ, InsertPos); + EQClassesVector.push_back(EQ); } else EQ->AddReport(R); @@ -1655,7 +1707,7 @@ struct FRIEC_WLItem { static BugReport * FindReportInEquivalenceClass(BugReportEquivClass& EQ, - llvm::SmallVectorImpl<BugReport*> &bugReports) { + SmallVectorImpl<BugReport*> &bugReports) { BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end(); assert(I != E); @@ -1667,7 +1719,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // to 'Nodes'. Any of the reports will serve as a "representative" report. if (!BT.isSuppressOnSink()) { for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) { - const ExplodedNode* N = I->getErrorNode(); + const ExplodedNode *N = I->getErrorNode(); if (N) { R = *I; bugReports.push_back(R); @@ -1691,9 +1743,8 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, if (!errorNode) continue; if (errorNode->isSink()) { - assert(false && + llvm_unreachable( "BugType::isSuppressSink() should not be 'true' for sink end nodes"); - return 0; } // No successors? By definition this nodes isn't post-dominated by a sink. if (errorNode->succ_empty()) { @@ -1706,7 +1757,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, // At this point we know that 'N' is not a sink and it has at least one // successor. Use a DFS worklist to find a non-sink end-of-path node. typedef FRIEC_WLItem WLItem; - typedef llvm::SmallVector<WLItem, 10> DFSWorkList; + typedef SmallVector<WLItem, 10> DFSWorkList; llvm::DenseMap<const ExplodedNode *, unsigned> Visited; DFSWorkList WL; @@ -1763,11 +1814,8 @@ class DiagCacheItem : public llvm::FoldingSetNode { llvm::FoldingSetNodeID ID; public: DiagCacheItem(BugReport *R, PathDiagnostic *PD) { - ID.AddString(R->getBugType().getName()); - ID.AddString(R->getBugType().getCategory()); - ID.AddString(R->getDescription()); - ID.AddInteger(R->getLocation().getRawEncoding()); - PD->Profile(ID); + R->Profile(ID); + PD->Profile(ID); } void Profile(llvm::FoldingSetNodeID &id) { @@ -1798,12 +1846,12 @@ static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) { } void BugReporter::FlushReport(BugReportEquivClass& EQ) { - llvm::SmallVector<BugReport*, 10> bugReports; + SmallVector<BugReport*, 10> bugReports; BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports); if (!exampleReport) return; - PathDiagnosticClient* PD = getPathDiagnosticClient(); + PathDiagnosticConsumer* PD = getPathDiagnosticConsumer(); // FIXME: Make sure we use the 'R' for the path that was actually used. // Probably doesn't make a difference in practice. @@ -1823,47 +1871,50 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { return; // Get the meta data. - std::pair<const char**, const char**> Meta = - exampleReport->getExtraDescriptiveText(); - for (const char** s = Meta.first; s != Meta.second; ++s) - D->addMeta(*s); + const BugReport::ExtraTextList &Meta = + exampleReport->getExtraText(); + for (BugReport::ExtraTextList::const_iterator i = Meta.begin(), + e = Meta.end(); i != e; ++i) { + D->addMeta(*i); + } // Emit a summary diagnostic to the regular Diagnostics engine. BugReport::ranges_iterator Beg, End; llvm::tie(Beg, End) = exampleReport->getRanges(); - Diagnostic &Diag = getDiagnostic(); - FullSourceLoc L(exampleReport->getLocation(), getSourceManager()); + DiagnosticsEngine &Diag = getDiagnostic(); // Search the description for '%', as that will be interpretted as a // format character by FormatDiagnostics. - llvm::StringRef desc = exampleReport->getShortDescription(); + StringRef desc = exampleReport->getShortDescription(); unsigned ErrorDiag; { llvm::SmallString<512> TmpStr; llvm::raw_svector_ostream Out(TmpStr); - for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) + for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) if (*I == '%') Out << "%%"; else Out << *I; Out.flush(); - ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr); + ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr); } { - DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag); + DiagnosticBuilder diagBuilder = Diag.Report( + exampleReport->getLocation(getSourceManager()).asLocation(), ErrorDiag); for (BugReport::ranges_iterator I = Beg; I != End; ++I) diagBuilder << *I; } - // Emit a full diagnostic for the path if we have a PathDiagnosticClient. + // Emit a full diagnostic for the path if we have a PathDiagnosticConsumer. if (!PD) return; if (D->empty()) { - PathDiagnosticPiece* piece = - new PathDiagnosticEventPiece(L, exampleReport->getDescription()); + PathDiagnosticPiece *piece = new PathDiagnosticEventPiece( + exampleReport->getLocation(getSourceManager()), + exampleReport->getDescription()); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); D->push_back(piece); @@ -1872,27 +1923,26 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { PD->HandlePathDiagnostic(D.take()); } -void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str, - SourceLocation Loc, +void BugReporter::EmitBasicReport(StringRef name, StringRef str, + PathDiagnosticLocation Loc, SourceRange* RBeg, unsigned NumRanges) { EmitBasicReport(name, "", str, Loc, RBeg, NumRanges); } -void BugReporter::EmitBasicReport(llvm::StringRef name, - llvm::StringRef category, - llvm::StringRef str, SourceLocation Loc, +void BugReporter::EmitBasicReport(StringRef name, + StringRef category, + StringRef str, PathDiagnosticLocation Loc, SourceRange* RBeg, unsigned NumRanges) { // 'BT' is owned by BugReporter. BugType *BT = getBugTypeForName(name, category); - FullSourceLoc L = getContext().getFullLoc(Loc); - RangedBugReport *R = new DiagBugReport(*BT, str, L); + BugReport *R = new BugReport(*BT, str, Loc); for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg); EmitReport(R); } -BugType *BugReporter::getBugTypeForName(llvm::StringRef name, - llvm::StringRef category) { +BugType *BugReporter::getBugTypeForName(StringRef name, + StringRef category) { llvm::SmallString<136> fullDesc; llvm::raw_svector_ostream(fullDesc) << name << ":" << category; llvm::StringMapEntry<BugType *> & diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 8e31ade..1abd8ba 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -11,13 +11,15 @@ // enhance the diagnostics reported for a bug. // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; using namespace ento; @@ -39,8 +41,6 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { return ME->getBase()->IgnoreParenCasts(); } else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { - // Retrieve the base for arrays since BasicStoreManager doesn't know how - // to reason about them. return AE->getBase(); } @@ -73,248 +73,255 @@ const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) { // Definitions for bug reporter visitors. //===----------------------------------------------------------------------===// -namespace { -class FindLastStoreBRVisitor : public BugReporterVisitor { - const MemRegion *R; - SVal V; - bool satisfied; - const ExplodedNode *StoreSite; -public: - FindLastStoreBRVisitor(SVal v, const MemRegion *r) - : R(r), V(v), satisfied(false), StoreSite(0) {} - - virtual void Profile(llvm::FoldingSetNodeID &ID) const { - static int tag = 0; - ID.AddPointer(&tag); - ID.AddPointer(R); - ID.Add(V); +PathDiagnosticPiece* +BugReporterVisitor::getEndPath(BugReporterContext &BRC, + const ExplodedNode *EndPathNode, + BugReport &BR) { + return 0; +} + +PathDiagnosticPiece* +BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, + const ExplodedNode *EndPathNode, + BugReport &BR) { + const ProgramPoint &PP = EndPathNode->getLocation(); + PathDiagnosticLocation L; + + if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) { + const CFGBlock *block = BE->getBlock(); + if (block->getBlockID() == 0) { + L = PathDiagnosticLocation::createDeclEnd(PP.getLocationContext(), + BRC.getSourceManager()); + } } - PathDiagnosticPiece* VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext& BRC) { + if (!L.isValid()) { + const Stmt *S = BR.getStmt(); - if (satisfied) + if (!S) return NULL; - if (!StoreSite) { - const ExplodedNode *Node = N, *Last = NULL; + L = PathDiagnosticLocation(S, BRC.getSourceManager(), + PP.getLocationContext()); + } - for ( ; Node ; Last = Node, Node = Node->getFirstPred()) { + BugReport::ranges_iterator Beg, End; + llvm::tie(Beg, End) = BR.getRanges(); - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - if (const PostStmt *P = Node->getLocationAs<PostStmt>()) - if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) - if (DS->getSingleDecl() == VR->getDecl()) { - Last = Node; - break; - } - } + // Only add the statement itself as a range if we didn't specify any + // special ranges for this report. + PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L, + BR.getDescription(), + Beg == End); + for (; Beg != End; ++Beg) + P->addRange(*Beg); - if (Node->getState()->getSVal(R) != V) - break; - } + return P; +} - if (!Node || !Last) { - satisfied = true; - return NULL; + +void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { + static int tag = 0; + ID.AddPointer(&tag); + ID.AddPointer(R); + ID.Add(V); +} + +PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + + if (satisfied) + return NULL; + + if (!StoreSite) { + const ExplodedNode *Node = N, *Last = NULL; + + for ( ; Node ; Last = Node, Node = Node->getFirstPred()) { + + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + if (const PostStmt *P = Node->getLocationAs<PostStmt>()) + if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) + if (DS->getSingleDecl() == VR->getDecl()) { + Last = Node; + break; + } } - StoreSite = Last; + if (Node->getState()->getSVal(R) != V) + break; } - if (StoreSite != N) + if (!Node || !Last) { + satisfied = true; return NULL; + } - satisfied = true; - llvm::SmallString<256> sbuf; - llvm::raw_svector_ostream os(sbuf); + StoreSite = Last; + } - if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { - if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { + if (StoreSite != N) + return NULL; - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << "Variable '" << VR->getDecl() << "' "; - } - else - return NULL; - - if (isa<loc::ConcreteInt>(V)) { - bool b = false; - if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { - if (TR->getValueType()->isObjCObjectPointerType()) { - os << "initialized to nil"; - b = true; - } - } - } + satisfied = true; + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream os(sbuf); - if (!b) - os << "initialized to a null pointer value"; - } - else if (isa<nonloc::ConcreteInt>(V)) { - os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); - } - else if (V.isUndef()) { - if (isa<VarRegion>(R)) { - const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); - if (VD->getInit()) - os << "initialized to a garbage value"; - else - os << "declared without an initial value"; - } - } + if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { + if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { + + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + os << "Variable '" << *VR->getDecl() << "' "; } - } + else + return NULL; - if (os.str().empty()) { if (isa<loc::ConcreteInt>(V)) { bool b = false; if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { - os << "nil object reference stored to "; + os << "initialized to nil"; b = true; } } } if (!b) - os << "Null pointer value stored to "; - } - else if (V.isUndef()) { - os << "Uninitialized value stored to "; + os << "initialized to a null pointer value"; } else if (isa<nonloc::ConcreteInt>(V)) { - os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() - << " is assigned to "; + os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); } - else - return NULL; - - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << '\'' << VR->getDecl() << '\''; + else if (V.isUndef()) { + if (isa<VarRegion>(R)) { + const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); + if (VD->getInit()) + os << "initialized to a garbage value"; + else + os << "declared without an initial value"; + } } - else - return NULL; } + } - // FIXME: Refactor this into BugReporterContext. - const Stmt *S = 0; - ProgramPoint P = N->getLocation(); + if (os.str().empty()) { + if (isa<loc::ConcreteInt>(V)) { + bool b = false; + if (R->isBoundable()) { + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { + if (TR->getValueType()->isObjCObjectPointerType()) { + os << "nil object reference stored to "; + b = true; + } + } + } - if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { - const CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); + if (!b) + os << "Null pointer value stored to "; } - else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) { - S = PS->getStmt(); + else if (V.isUndef()) { + os << "Uninitialized value stored to "; } - - if (!S) + else if (isa<nonloc::ConcreteInt>(V)) { + os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() + << " is assigned to "; + } + else return NULL; - // Construct a new PathDiagnosticPiece. - PathDiagnosticLocation L(S, BRC.getSourceManager()); - return new PathDiagnosticEventPiece(L, os.str()); + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + os << '\'' << *VR->getDecl() << '\''; + } + else + return NULL; } -}; - -static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R, - SVal V) { - BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); + // Construct a new PathDiagnosticPiece. + ProgramPoint P = N->getLocation(); + PathDiagnosticLocation L = + PathDiagnosticLocation::create(P, BRC.getSourceManager()); + if (!L.isValid()) + return NULL; + return new PathDiagnosticEventPiece(L, os.str()); } -class TrackConstraintBRVisitor : public BugReporterVisitor { - DefinedSVal Constraint; - const bool Assumption; - bool isSatisfied; -public: - TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) - : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} - - void Profile(llvm::FoldingSetNodeID &ID) const { - static int tag = 0; - ID.AddPointer(&tag); - ID.AddBoolean(Assumption); - ID.Add(Constraint); - } - - PathDiagnosticPiece* VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext& BRC) { - if (isSatisfied) - return NULL; - - // Check if in the previous state it was feasible for this constraint - // to *not* be true. - if (PrevN->getState()->assume(Constraint, !Assumption)) { - - isSatisfied = true; - - // As a sanity check, make sure that the negation of the constraint - // was infeasible in the current state. If it is feasible, we somehow - // missed the transition point. - if (N->getState()->assume(Constraint, !Assumption)) - return NULL; - - // We found the transition point for the constraint. We now need to - // pretty-print the constraint. (work-in-progress) - std::string sbuf; - llvm::raw_string_ostream os(sbuf); +void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { + static int tag = 0; + ID.AddPointer(&tag); + ID.AddBoolean(Assumption); + ID.Add(Constraint); +} - if (isa<Loc>(Constraint)) { - os << "Assuming pointer value is "; - os << (Assumption ? "non-null" : "null"); - } +PathDiagnosticPiece * +TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + if (isSatisfied) + return NULL; - if (os.str().empty()) - return NULL; + // Check if in the previous state it was feasible for this constraint + // to *not* be true. + if (PrevN->getState()->assume(Constraint, !Assumption)) { - // FIXME: Refactor this into BugReporterContext. - const Stmt *S = 0; - ProgramPoint P = N->getLocation(); + isSatisfied = true; - if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { - const CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); - } - else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) { - S = PS->getStmt(); - } + // As a sanity check, make sure that the negation of the constraint + // was infeasible in the current state. If it is feasible, we somehow + // missed the transition point. + if (N->getState()->assume(Constraint, !Assumption)) + return NULL; - if (!S) - return NULL; + // We found the transition point for the constraint. We now need to + // pretty-print the constraint. (work-in-progress) + std::string sbuf; + llvm::raw_string_ostream os(sbuf); - // Construct a new PathDiagnosticPiece. - PathDiagnosticLocation L(S, BRC.getSourceManager()); - return new PathDiagnosticEventPiece(L, os.str()); + if (isa<Loc>(Constraint)) { + os << "Assuming pointer value is "; + os << (Assumption ? "non-null" : "null"); } - return NULL; + if (os.str().empty()) + return NULL; + + // Construct a new PathDiagnosticPiece. + ProgramPoint P = N->getLocation(); + PathDiagnosticLocation L = + PathDiagnosticLocation::create(P, BRC.getSourceManager()); + if (!L.isValid()) + return NULL; + return new PathDiagnosticEventPiece(L, os.str()); } -}; -} // end anonymous namespace -static void registerTrackConstraint(BugReporterContext& BRC, - DefinedSVal Constraint, - bool Assumption) { - BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption)); + return NULL; } -void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, - const void *data, - const ExplodedNode* N) { - - const Stmt *S = static_cast<const Stmt*>(data); - - if (!S) - return; +BugReporterVisitor * +bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, + const Stmt *S) { + if (!S || !N) + return 0; + + ProgramStateManager &StateMgr = N->getState()->getStateManager(); + + // Walk through nodes until we get one that matches the statement + // exactly. + while (N) { + const ProgramPoint &pp = N->getLocation(); + if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { + if (ps->getStmt() == S) + break; + } + N = N->getFirstPred(); + } - GRStateManager &StateMgr = BRC.getStateManager(); - const GRState *state = N->getState(); + if (!N) + return 0; + + const ProgramState *state = N->getState(); // Walk through lvalue-to-rvalue conversions. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) { @@ -327,7 +334,7 @@ void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V) || V.isUndef()) { - ::registerFindLastStore(BRC, R, V); + return new FindLastStoreBRVisitor(V, R); } } } @@ -347,94 +354,73 @@ void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, if (R) { assert(isa<SymbolicRegion>(R)); - registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); } } -} - -void bugreporter::registerFindLastStore(BugReporterContext& BRC, - const void *data, - const ExplodedNode* N) { - const MemRegion *R = static_cast<const MemRegion*>(data); + return 0; +} - if (!R) - return; +BugReporterVisitor * +FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, + const MemRegion *R) { + assert(R && "The memory region is null."); - const GRState *state = N->getState(); + const ProgramState *state = N->getState(); SVal V = state->getSVal(R); - if (V.isUnknown()) - return; + return 0; - BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); + return new FindLastStoreBRVisitor(V, R); } -namespace { -class NilReceiverVisitor : public BugReporterVisitor { -public: - NilReceiverVisitor() {} - - void Profile(llvm::FoldingSetNodeID &ID) const { - static int x = 0; - ID.AddPointer(&x); - } - - PathDiagnosticPiece* VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext& BRC) { - - const PostStmt *P = N->getLocationAs<PostStmt>(); - if (!P) - return 0; - const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); - if (!ME) - return 0; - const Expr *Receiver = ME->getInstanceReceiver(); - if (!Receiver) - return 0; - const GRState *state = N->getState(); - const SVal &V = state->getSVal(Receiver); - const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); - if (!DV) - return 0; - state = state->assume(*DV, true); - if (state) - return 0; - - // The receiver was nil, and hence the method was skipped. - // Register a BugReporterVisitor to issue a message telling us how - // the receiver was null. - bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N); - // Issue a message saying that the method was skipped. - PathDiagnosticLocation L(Receiver, BRC.getSourceManager()); - return new PathDiagnosticEventPiece(L, "No method actually called " - "because the receiver is nil"); - } -}; -} // end anonymous namespace - -void bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) { - BRC.addVisitor(new NilReceiverVisitor()); +PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + const PostStmt *P = N->getLocationAs<PostStmt>(); + if (!P) + return 0; + const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); + if (!ME) + return 0; + const Expr *Receiver = ME->getInstanceReceiver(); + if (!Receiver) + return 0; + const ProgramState *state = N->getState(); + const SVal &V = state->getSVal(Receiver); + const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); + if (!DV) + return 0; + state = state->assume(*DV, true); + if (state) + return 0; + + // The receiver was nil, and hence the method was skipped. + // Register a BugReporterVisitor to issue a message telling us how + // the receiver was null. + BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver)); + // Issue a message saying that the method was skipped. + PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), + N->getLocationContext()); + return new PathDiagnosticEventPiece(L, "No method actually called " + "because the receiver is nil"); } -// Registers every VarDecl inside a Stmt with a last store vistor. -void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC, - const void *stmt, - const ExplodedNode *N) { - const Stmt *S = static_cast<const Stmt *>(stmt); - +// Registers every VarDecl inside a Stmt with a last store visitor. +void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, + const Stmt *S) { + const ExplodedNode *N = BR.getErrorNode(); std::deque<const Stmt *> WorkList; - WorkList.push_back(S); while (!WorkList.empty()) { const Stmt *Head = WorkList.front(); WorkList.pop_front(); - GRStateManager &StateMgr = BRC.getStateManager(); - const GRState *state = N->getState(); + const ProgramState *state = N->getState(); + ProgramStateManager &StateMgr = state->getStateManager(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { @@ -445,7 +431,8 @@ void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC, SVal V = state->getSVal(S); if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { - ::registerFindLastStore(BRC, R, V); + // Register a new visitor with the BugReport. + BR.addVisitor(new FindLastStoreBRVisitor(V, R)); } } } @@ -455,3 +442,248 @@ void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC, WorkList.push_back(*I); } } + +//===----------------------------------------------------------------------===// +// Visitor that tries to report interesting diagnostics from conditions. +//===----------------------------------------------------------------------===// +PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) { + + const ProgramPoint &progPoint = N->getLocation(); + + const ProgramState *CurrentState = N->getState(); + const ProgramState *PrevState = Prev->getState(); + + // Compare the GDMs of the state, because that is where constraints + // are managed. Note that ensure that we only look at nodes that + // were generated by the analyzer engine proper, not checkers. + if (CurrentState->getGDM().getRoot() == + PrevState->getGDM().getRoot()) + return 0; + + // If an assumption was made on a branch, it should be caught + // here by looking at the state transition. + if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { + const CFGBlock *srcBlk = BE->getSrc(); + if (const Stmt *term = srcBlk->getTerminator()) + return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC); + return 0; + } + + if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { + // FIXME: Assuming that BugReporter is a GRBugReporter is a layering + // violation. + const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = + cast<GRBugReporter>(BRC.getBugReporter()). + getEngine().getEagerlyAssumeTags(); + + const ProgramPointTag *tag = PS->getTag(); + if (tag == tags.first) + return VisitTrueTest(cast<Expr>(PS->getStmt()), true, + BRC, N->getLocationContext()); + if (tag == tags.second) + return VisitTrueTest(cast<Expr>(PS->getStmt()), false, + BRC, N->getLocationContext()); + + return 0; + } + + return 0; +} + +PathDiagnosticPiece * +ConditionBRVisitor::VisitTerminator(const Stmt *Term, + const ExplodedNode *N, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReporterContext &BRC) { + const Expr *Cond = 0; + + switch (Term->getStmtClass()) { + default: + return 0; + case Stmt::IfStmtClass: + Cond = cast<IfStmt>(Term)->getCond(); + break; + case Stmt::ConditionalOperatorClass: + Cond = cast<ConditionalOperator>(Term)->getCond(); + break; + } + + assert(Cond); + assert(srcBlk->succ_size() == 2); + const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; + return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), + tookTrue, BRC, N->getLocationContext()); +} + +PathDiagnosticPiece * +ConditionBRVisitor::VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC, + const LocationContext *LC) { + + const Expr *Ex = Cond; + + while (true) { + Ex = Ex->IgnoreParens(); + switch (Ex->getStmtClass()) { + default: + return 0; + case Stmt::BinaryOperatorClass: + return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC); + case Stmt::DeclRefExprClass: + return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC); + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(Ex); + if (UO->getOpcode() == UO_LNot) { + tookTrue = !tookTrue; + Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); + continue; + } + return 0; + } + } + } +} + +bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, + BugReporterContext &BRC) { + const Expr *OriginalExpr = Ex; + Ex = Ex->IgnoreParenCasts(); + + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { + const bool quotes = isa<VarDecl>(DR->getDecl()); + if (quotes) + Out << '\''; + Out << DR->getDecl()->getDeclName().getAsString(); + if (quotes) + Out << '\''; + return quotes; + } + + if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { + QualType OriginalTy = OriginalExpr->getType(); + if (OriginalTy->isPointerType()) { + if (IL->getValue() == 0) { + Out << "null"; + return false; + } + } + else if (OriginalTy->isObjCObjectPointerType()) { + if (IL->getValue() == 0) { + Out << "nil"; + return false; + } + } + + Out << IL->getValue(); + return false; + } + + return false; +} + +PathDiagnosticPiece * +ConditionBRVisitor::VisitTrueTest(const Expr *Cond, + const BinaryOperator *BExpr, + const bool tookTrue, + BugReporterContext &BRC, + const LocationContext *LC) { + + bool shouldInvert = false; + + llvm::SmallString<128> LhsString, RhsString; + { + llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); + const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC); + const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC); + + shouldInvert = !isVarLHS && isVarRHS; + } + + if (LhsString.empty() || RhsString.empty()) + return 0; + + // Should we invert the strings if the LHS is not a variable name? + + llvm::SmallString<256> buf; + llvm::raw_svector_ostream Out(buf); + Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; + + // Do we need to invert the opcode? + BinaryOperator::Opcode Op = BExpr->getOpcode(); + + if (shouldInvert) + switch (Op) { + default: break; + case BO_LT: Op = BO_GT; break; + case BO_GT: Op = BO_LT; break; + case BO_LE: Op = BO_GE; break; + case BO_GE: Op = BO_LE; break; + } + + if (!tookTrue) + switch (Op) { + case BO_EQ: Op = BO_NE; break; + case BO_NE: Op = BO_EQ; break; + case BO_LT: Op = BO_GE; break; + case BO_GT: Op = BO_LE; break; + case BO_LE: Op = BO_GT; break; + case BO_GE: Op = BO_LT; break; + default: + return 0; + } + + switch (BExpr->getOpcode()) { + case BO_EQ: + Out << "equal to "; + break; + case BO_NE: + Out << "not equal to "; + break; + default: + Out << BinaryOperator::getOpcodeStr(Op) << ' '; + break; + } + + Out << (shouldInvert ? LhsString : RhsString); + + PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); + return new PathDiagnosticEventPiece(Loc, Out.str()); +} + +PathDiagnosticPiece * +ConditionBRVisitor::VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC, + const LocationContext *LC) { + + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + if (!VD) + return 0; + + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream Out(Buf); + + Out << "Assuming '"; + VD->getDeclName().printName(Out); + Out << "' is "; + + QualType VDTy = VD->getType(); + + if (VDTy->isPointerType()) + Out << (tookTrue ? "non-null" : "null"); + else if (VDTy->isObjCObjectPointerType()) + Out << (tookTrue ? "non-nil" : "nil"); + else if (VDTy->isScalarType()) + Out << (tookTrue ? "not equal to 0" : "0"); + else + return 0; + + PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); + return new PathDiagnosticEventPiece(Loc, Out.str()); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CMakeLists.txt deleted file mode 100644 index 14c636c..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite) - -add_clang_library(clangStaticAnalyzerCore - AggExprVisitor.cpp - AnalysisManager.cpp - BasicConstraintManager.cpp - BasicStore.cpp - BasicValueFactory.cpp - BugReporter.cpp - BugReporterVisitors.cpp - CFRefCount.cpp - Checker.cpp - CheckerHelpers.cpp - CheckerManager.cpp - Environment.cpp - ExplodedGraph.cpp - FlatStore.cpp - BlockCounter.cpp - CXXExprEngine.cpp - CoreEngine.cpp - GRState.cpp - HTMLDiagnostics.cpp - MemRegion.cpp - ObjCMessage.cpp - PathDiagnostic.cpp - PlistDiagnostics.cpp - RangeConstraintManager.cpp - RegionStore.cpp - SimpleConstraintManager.cpp - SimpleSValBuilder.cpp - Store.cpp - SValBuilder.cpp - SVals.cpp - SymbolManager.cpp - TextPathDiagnostics.cpp - ) - -add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes - ClangStmtNodes) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp new file mode 100644 index 0000000..a3bf2c2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp @@ -0,0 +1,22 @@ +//== Checker.cpp - Registration mechanism for checkers -----------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Checker, used to create and register checkers. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/Checker.h" + +using namespace clang; +using namespace ento; + +StringRef CheckerBase::getTagDescription() const { + // FIXME: We want to return the package + name of the checker here. + return "A Checker"; +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index f6fb8f2..5356edc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -23,8 +23,8 @@ CheckerContext::~CheckerContext() { // if we are building sinks or we generated a node and decided to not // add it as a transition. if (Dst.size() == size && !B.BuildSinks && !B.hasGeneratedNode) { - if (ST && ST != B.GetState(Pred)) { - static int autoTransitionTag = 0; + if (ST && ST != Pred->getState()) { + static SimpleProgramPointTag autoTransitionTag("CheckerContext : auto"); addTransition(ST, &autoTransitionTag); } else diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index ba7c384..acacfb0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -12,8 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/AST/DeclBase.h" @@ -33,7 +34,8 @@ bool CheckerManager::hasPathSensitiveCheckers() const { !DeadSymbolsCheckers.empty() || !RegionChangesCheckers.empty() || !EvalAssumeCheckers.empty() || - !EvalCallCheckers.empty(); + !EvalCallCheckers.empty() || + !InlineCallCheckers.empty(); } void CheckerManager::finishedCheckerRegistration() { @@ -122,7 +124,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx, namespace { struct CheckStmtContext { - typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; + typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; bool IsPreVisit; const CheckersTy &Checkers; const Stmt *S; @@ -138,9 +140,12 @@ namespace { void runChecker(CheckerManager::CheckStmtFunc checkFn, ExplodedNodeSet &Dst, ExplodedNode *Pred) { // FIXME: Remove respondsToCallback from CheckerContext; - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, - IsPreVisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, 0, S); + ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + checkFn(S, C); } }; @@ -174,10 +179,12 @@ namespace { void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, ExplodedNodeSet &Dst, ExplodedNode *Pred) { - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, - IsPreVisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, 0, - Msg.getOriginExpr()); + ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(), + K, Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + checkFn(Msg, C); } }; @@ -214,10 +221,13 @@ namespace { void runChecker(CheckerManager::CheckLocationFunc checkFn, ExplodedNodeSet &Dst, ExplodedNode *Pred) { - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, - IsLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, 0, S); - checkFn(Loc, IsLoad, C); + ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : + ProgramPoint::PreStoreKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + + checkFn(Loc, IsLoad, S, C); } }; } @@ -249,9 +259,12 @@ namespace { void runChecker(CheckerManager::CheckBindFunc checkFn, ExplodedNodeSet &Dst, ExplodedNode *Pred) { - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, - ProgramPoint::PreStmtKind, 0, S); - checkFn(Loc, Val, C); + ProgramPoint::Kind K = ProgramPoint::PreStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + + checkFn(Loc, Val, S, C); } }; } @@ -293,7 +306,7 @@ void CheckerManager::runCheckersForBranchCondition(const Stmt *condition, } /// \brief Run checkers for live symbols. -void CheckerManager::runCheckersForLiveSymbols(const GRState *state, +void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state, SymbolReaper &SymReaper) { for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i) LiveSymbolsCheckers[i](state, SymReaper); @@ -316,8 +329,11 @@ namespace { void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, ExplodedNodeSet &Dst, ExplodedNode *Pred) { - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, - ProgramPoint::PostPurgeDeadSymbolsKind, 0, S); + ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + checkFn(SR, C); } }; @@ -334,7 +350,7 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, } /// \brief True if at least one checker wants to check region changes. -bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) { +bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) if (RegionChangesCheckers[i].WantUpdateFn(state)) return true; @@ -343,24 +359,25 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) { } /// \brief Run checkers for region changes. -const GRState * -CheckerManager::runCheckersForRegionChanges(const GRState *state, +const ProgramState * +CheckerManager::runCheckersForRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End) { + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) return NULL; - state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End); + state = RegionChangesCheckers[i].CheckFn(state, invalidated, + ExplicitRegions, Regions); } return state; } /// \brief Run checkers for handling assumptions on symbolic values. -const GRState * -CheckerManager::runCheckersForEvalAssume(const GRState *state, +const ProgramState * +CheckerManager::runCheckersForEvalAssume(const ProgramState *state, SVal Cond, bool Assumption) { for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { // If any checker declares the state infeasible (or if it starts that way), @@ -379,7 +396,9 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExprEngine &Eng, GraphExpander *defaultEval) { - if (EvalCallCheckers.empty() && defaultEval == 0) { + if (EvalCallCheckers.empty() && + InlineCallCheckers.empty() && + defaultEval == 0) { Dst.insert(Src); return; } @@ -389,13 +408,50 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred = *NI; bool anyEvaluated = false; + + // First, check if any of the InlineCall callbacks can evaluate the call. + assert(InlineCallCheckers.size() <= 1 && + "InlineCall is a special hacky callback to allow intrusive" + "evaluation of the call (which simulates inlining). It is " + "currently only used by OSAtomicChecker and should go away " + "at some point."); + for (std::vector<InlineCallFunc>::iterator + EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); + EI != EE; ++EI) { + ExplodedNodeSet checkDst; + bool evaluated = (*EI)(CE, Eng, Pred, checkDst); + assert(!(evaluated && anyEvaluated) + && "There are more than one checkers evaluating the call"); + if (evaluated) { + anyEvaluated = true; + Dst.insert(checkDst); +#ifdef NDEBUG + break; // on release don't check that no other checker also evals. +#endif + } + } + +#ifdef NDEBUG // on release don't check that no other checker also evals. + if (anyEvaluated) { + break; + } +#endif + + // Next, check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { ExplodedNodeSet checkDst; - CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker, - ProgramPoint::PostStmtKind, 0, CE); - bool evaluated = (*EI)(CE, C); + ProgramPoint::Kind K = ProgramPoint::PostStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, + Pred->getLocationContext(), EI->Checker); + bool evaluated = false; + { // CheckerContext generates transitions(populates checkDest) on + // destruction, so introduce the scope to make sure it gets properly + // populated. + CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0); + evaluated = (*EI)(CE, C); + } assert(!(evaluated && anyEvaluated) && "There are more than one checkers evaluating the call"); if (evaluated) { @@ -407,6 +463,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, } } + // If none of the checkers evaluated the call, ask ExprEngine to handle it. if (!anyEvaluated) { if (defaultEval) defaultEval->expandGraph(Dst, Pred); @@ -425,6 +482,14 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit( EndOfTranslationUnitCheckers[i](TU, mgr, BR); } +void CheckerManager::runCheckersForPrintState(raw_ostream &Out, + const ProgramState *State, + const char *NL, const char *Sep) { + for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator + I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) + I->second->printState(Out, State, NL, Sep); +} + //===----------------------------------------------------------------------===// // Internal registration functions for AST traversing. //===----------------------------------------------------------------------===// @@ -504,6 +569,10 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { EvalCallCheckers.push_back(checkfn); } +void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) { + InlineCallCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEndOfTranslationUnit( CheckEndOfTranslationUnit checkfn) { EndOfTranslationUnitCheckers.push_back(checkfn); @@ -542,7 +611,4 @@ CheckerManager::~CheckerManager() { } // Anchor for the vtable. -CheckerProvider::~CheckerProvider() { } - -// Anchor for the vtable. GraphExpander::~GraphExpander() { } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp new file mode 100644 index 0000000..13401ac --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -0,0 +1,149 @@ +//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" +#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" + +using namespace clang; +using namespace ento; + +static const char PackageSeparator = '.'; +typedef llvm::DenseSet<const CheckerRegistry::CheckerInfo *> CheckerInfoSet; + + +static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, + const CheckerRegistry::CheckerInfo &b) { + return a.FullName < b.FullName; +} + +static bool isInPackage(const CheckerRegistry::CheckerInfo &checker, + StringRef packageName) { + // Does the checker's full name have the package as a prefix? + if (!checker.FullName.startswith(packageName)) + return false; + + // Is the package actually just the name of a specific checker? + if (checker.FullName.size() == packageName.size()) + return true; + + // Is the checker in the package (or a subpackage)? + if (checker.FullName[packageName.size()] == PackageSeparator) + return true; + + return false; +} + +static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, + const llvm::StringMap<size_t> &packageSizes, + CheckerOptInfo &opt, CheckerInfoSet &collected) { + // Use a binary search to find the possible start of the package. + CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), ""); + CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); + CheckerRegistry::CheckerInfoList::const_iterator i = + std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); + + // If we didn't even find a possible package, give up. + if (i == e) + return; + + // If what we found doesn't actually start the package, give up. + if (!isInPackage(*i, opt.getName())) + return; + + // There is at least one checker in the package; claim the option. + opt.claim(); + + // See how large the package is. + // If the package doesn't exist, assume the option refers to a single checker. + size_t size = 1; + llvm::StringMap<size_t>::const_iterator packageSize = + packageSizes.find(opt.getName()); + if (packageSize != packageSizes.end()) + size = packageSize->getValue(); + + // Step through all the checkers in the package. + for (e = i+size; i != e; ++i) { + if (opt.isEnabled()) + collected.insert(&*i); + else + collected.erase(&*i); + } +} + +void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, + StringRef desc) { + Checkers.push_back(CheckerInfo(fn, name, desc)); + + // Record the presence of the checker in its packages. + StringRef packageName, leafName; + llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator); + while (!leafName.empty()) { + Packages[packageName] += 1; + llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); + } +} + +void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, + SmallVectorImpl<CheckerOptInfo> &opts) const { + // Sort checkers for efficient collection. + std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); + + // Collect checkers enabled by the options. + CheckerInfoSet enabledCheckers; + for (SmallVectorImpl<CheckerOptInfo>::iterator + i = opts.begin(), e = opts.end(); i != e; ++i) { + collectCheckers(Checkers, Packages, *i, enabledCheckers); + } + + // Initialize the CheckerManager with all enabled checkers. + for (CheckerInfoSet::iterator + i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { + (*i)->Initialize(checkerMgr); + } +} + +void CheckerRegistry::printHelp(llvm::raw_ostream &out, + size_t maxNameChars) const { + // FIXME: Alphabetical sort puts 'experimental' in the middle. + // Would it be better to name it '~experimental' or something else + // that's ASCIIbetically last? + std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); + + // FIXME: Print available packages. + + out << "CHECKERS:\n"; + + // Find the maximum option length. + size_t optionFieldWidth = 0; + for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); + i != e; ++i) { + // Limit the amount of padding we are willing to give up for alignment. + // Package.Name Description [Hidden] + size_t nameLength = i->FullName.size(); + if (nameLength <= maxNameChars) + optionFieldWidth = std::max(optionFieldWidth, nameLength); + } + + const size_t initialPad = 2; + for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); + i != e; ++i) { + out.indent(initialPad) << i->FullName; + + int pad = optionFieldWidth - i->FullName.size(); + + // Break on long option names. + if (pad < 0) { + out << '\n'; + pad = optionFieldWidth + initialPad; + } + out.indent(pad + 2) << i->Desc; + + out << '\n'; + } +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 34cd6e8..5252198 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -17,22 +17,12 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/Index/TranslationUnit.h" #include "clang/AST/Expr.h" +#include "clang/AST/StmtCXX.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" - -using llvm::cast; -using llvm::isa; using namespace clang; using namespace ento; -// This should be removed in the future. -namespace clang { -namespace ento { -TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); -} -} - //===----------------------------------------------------------------------===// // Worklist classes for exploration of reachable states. //===----------------------------------------------------------------------===// @@ -41,7 +31,7 @@ WorkList::Visitor::~Visitor() {} namespace { class DFS : public WorkList { - llvm::SmallVector<WorkListUnit,20> Stack; + SmallVector<WorkListUnit,20> Stack; public: virtual bool hasWork() const { return !Stack.empty(); @@ -59,7 +49,7 @@ public: } virtual bool visitItemsInWorkList(Visitor &V) { - for (llvm::SmallVectorImpl<WorkListUnit>::iterator + for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) return true; @@ -107,7 +97,7 @@ WorkList *WorkList::makeBFS() { return new BFS(); } namespace { class BFSBlockDFSContents : public WorkList { std::deque<WorkListUnit> Queue; - llvm::SmallVector<WorkListUnit,20> Stack; + SmallVector<WorkListUnit,20> Stack; public: virtual bool hasWork() const { return !Queue.empty() || !Stack.empty(); @@ -136,7 +126,7 @@ namespace { return U; } virtual bool visitItemsInWorkList(Visitor &V) { - for (llvm::SmallVectorImpl<WorkListUnit>::iterator + for (SmallVectorImpl<WorkListUnit>::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) { if (V.visit(*I)) return true; @@ -162,12 +152,12 @@ WorkList* WorkList::makeBFSBlockDFSContents() { /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, - const GRState *InitState) { + const ProgramState *InitState) { if (G->num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. - const CFGBlock* Entry = &(L->getCFG()->getEntry()); + const CFGBlock *Entry = &(L->getCFG()->getEntry()); assert (Entry->empty() && "Entry block must be empty."); @@ -176,7 +166,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, "Entry block must have 1 successor."); // Get the solitary successor. - const CFGBlock* Succ = *(Entry->succ_begin()); + const CFGBlock *Succ = *(Entry->succ_begin()); // Construct an edge representing the // starting location in the function. @@ -208,7 +198,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, WList->setBlockCounter(WU.getBlockCounter()); // Retrieve the node. - ExplodedNode* Node = WU.getNode(); + ExplodedNode *Node = WU.getNode(); // Dispatch on the location type. switch (Node->getLocation().getKind()) { @@ -246,11 +236,11 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, } void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, - unsigned Steps, - const GRState *InitState, - ExplodedNodeSet &Dst) { + unsigned Steps, + const ProgramState *InitState, + ExplodedNodeSet &Dst) { ExecuteWorkList(L, Steps, InitState); - for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(), + for (SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(), E = G->EndNodes.end(); I != E; ++I) { Dst.Add(*I); } @@ -268,9 +258,9 @@ void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { SubEng.processCallExit(Builder); } -void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { +void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { - const CFGBlock* Blk = L.getDst(); + const CFGBlock *Blk = L.getDst(); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { @@ -305,15 +295,15 @@ void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { } } - for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator + for (SmallVectorImpl<ExplodedNode*>::const_iterator I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end(); I != E; ++I) { blocksExhausted.push_back(std::make_pair(L, *I)); } } -void CoreEngine::HandleBlockEntrance(const BlockEntrance& L, - ExplodedNode* Pred) { +void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, + ExplodedNode *Pred) { // Increment the block counter. BlockCounter Counter = WList->getBlockCounter(); @@ -324,21 +314,19 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance& L, // Process the entrance of the block. if (CFGElement E = L.getFirstElement()) { - StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, - SubEng.getStateManager()); + StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this); SubEng.processCFGElement(E, Builder); } else HandleBlockExit(L.getBlock(), Pred); } -void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { +void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { - if (const Stmt* Term = B->getTerminator()) { + if (const Stmt *Term = B->getTerminator()) { switch (Term->getStmtClass()) { default: - assert(false && "Analysis for this terminator not implemented."); - break; + llvm_unreachable("Analysis for this terminator not implemented."); case Stmt::BinaryOperatorClass: // '&&' and '||' HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred); @@ -361,6 +349,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred); return; + case Stmt::CXXForRangeStmtClass: + HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred); + return; + case Stmt::ForStmtClass: HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred); return; @@ -422,34 +414,34 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { Pred->State, Pred); } -void CoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, - const CFGBlock * B, ExplodedNode* Pred) { +void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, + const CFGBlock * B, ExplodedNode *Pred) { assert(B->succ_size() == 2); BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), Pred, this); SubEng.processBranch(Cond, Term, Builder); } -void CoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, - ExplodedNode* Pred) { +void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, + ExplodedNode *Pred) { assert (!B->empty()); if (StmtIdx == B->size()) HandleBlockExit(B, Pred); else { - StmtNodeBuilder Builder(B, StmtIdx, Pred, this, - SubEng.getStateManager()); + StmtNodeBuilder Builder(B, StmtIdx, Pred, this); SubEng.processCFGElement((*B)[StmtIdx], Builder); } } /// generateNode - Utility method to generate nodes, hook up successors, /// and add nodes to the worklist. -void CoreEngine::generateNode(const ProgramPoint& Loc, - const GRState* State, ExplodedNode* Pred) { +void CoreEngine::generateNode(const ProgramPoint &Loc, + const ProgramState *State, + ExplodedNode *Pred) { bool IsNew; - ExplodedNode* Node = G->getNode(Loc, State, &IsNew); + ExplodedNode *Node = G->getNode(Loc, State, &IsNew); if (Pred) Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. @@ -463,7 +455,7 @@ void CoreEngine::generateNode(const ProgramPoint& Loc, } ExplodedNode * -GenericNodeBuilderImpl::generateNodeImpl(const GRState *state, +GenericNodeBuilderImpl::generateNodeImpl(const ProgramState *state, ExplodedNode *pred, ProgramPoint programPoint, bool asSink) { @@ -483,14 +475,14 @@ GenericNodeBuilderImpl::generateNodeImpl(const GRState *state, return 0; } -StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx, - ExplodedNode* N, CoreEngine* e, - GRStateManager &mgr) - : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), +StmtNodeBuilder::StmtNodeBuilder(const CFGBlock *b, + unsigned idx, + ExplodedNode *N, + CoreEngine* e) + : Eng(*e), B(*b), Idx(idx), Pred(N), PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false), PointKind(ProgramPoint::PostStmtKind), Tag(0) { Deferred.insert(N); - CleanedState = Pred->getState(); } StmtNodeBuilder::~StmtNodeBuilder() { @@ -499,7 +491,7 @@ StmtNodeBuilder::~StmtNodeBuilder() { GenerateAutoTransition(*I); } -void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { +void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) { assert (!N->isSink()); // Check if this node entered a callee. @@ -526,18 +518,20 @@ void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { } bool IsNew; - ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew); + ExplodedNode *Succ = Eng.G->getNode(Loc, N->State, &IsNew); Succ->addPredecessor(N, *Eng.G); if (IsNew) Eng.WList->enqueue(Succ, &B, Idx+1); } -ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, - ExplodedNode* Pred, const GRState* St, - ProgramPoint::Kind K) { +ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &Dst, + const Stmt *S, + ExplodedNode *Pred, + const ProgramState *St, + ProgramPoint::Kind K) { - ExplodedNode* N = generateNode(S, St, Pred, K); + ExplodedNode *N = generateNode(S, St, Pred, K); if (N) { if (BuildSinks) @@ -549,46 +543,24 @@ ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, return N; } -static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, - const LocationContext *LC, const void *tag){ - switch (K) { - default: - assert(false && "Unhandled ProgramPoint kind"); - case ProgramPoint::PreStmtKind: - return PreStmt(S, LC, tag); - case ProgramPoint::PostStmtKind: - return PostStmt(S, LC, tag); - case ProgramPoint::PreLoadKind: - return PreLoad(S, LC, tag); - case ProgramPoint::PostLoadKind: - return PostLoad(S, LC, tag); - case ProgramPoint::PreStoreKind: - return PreStore(S, LC, tag); - case ProgramPoint::PostStoreKind: - return PostStore(S, LC, tag); - case ProgramPoint::PostLValueKind: - return PostLValue(S, LC, tag); - case ProgramPoint::PostPurgeDeadSymbolsKind: - return PostPurgeDeadSymbols(S, LC, tag); - } -} - ExplodedNode* -StmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, - ExplodedNode* Pred, - ProgramPoint::Kind K, - const void *tag) { +StmtNodeBuilder::generateNodeInternal(const Stmt *S, + const ProgramState *state, + ExplodedNode *Pred, + ProgramPoint::Kind K, + const ProgramPointTag *tag) { - const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), tag); return generateNodeInternal(L, state, Pred); } ExplodedNode* StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, - const GRState* State, - ExplodedNode* Pred) { + const ProgramState *State, + ExplodedNode *Pred) { bool IsNew; - ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew); + ExplodedNode *N = Eng.G->getNode(Loc, State, &IsNew); N->addPredecessor(Pred, *Eng.G); Deferred.erase(Pred); @@ -601,11 +573,11 @@ StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, } // This function generate a new ExplodedNode but not a new branch(block edge). -ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition, - const GRState* State) { +ExplodedNode *BranchNodeBuilder::generateNode(const Stmt *Condition, + const ProgramState *State) { bool IsNew; - ExplodedNode* Succ + ExplodedNode *Succ = Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State, &IsNew); @@ -619,8 +591,8 @@ ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition, return NULL; } -ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State, - bool branch) { +ExplodedNode *BranchNodeBuilder::generateNode(const ProgramState *State, + bool branch) { // If the branch has been marked infeasible we should not generate a node. if (!isFeasible(branch)) @@ -628,7 +600,7 @@ ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State, bool IsNew; - ExplodedNode* Succ = + ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()), State, &IsNew); @@ -657,11 +629,12 @@ BranchNodeBuilder::~BranchNodeBuilder() { ExplodedNode* -IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St, - bool isSink) { +IndirectGotoNodeBuilder::generateNode(const iterator &I, + const ProgramState *St, + bool isSink) { bool IsNew; - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()), St, &IsNew); Succ->addPredecessor(Pred, *Eng.G); @@ -681,34 +654,38 @@ IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St, ExplodedNode* -SwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){ +SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, + const ProgramState *St) { bool IsNew; - - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), - Pred->getLocationContext()), St, &IsNew); + ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + Pred->getLocationContext()), + St, &IsNew); Succ->addPredecessor(Pred, *Eng.G); - if (IsNew) { Eng.WList->enqueue(Succ); return Succ; } - return NULL; } ExplodedNode* -SwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) { - +SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St, + bool isSink) { // Get the block for the default case. - assert (Src->succ_rbegin() != Src->succ_rend()); - CFGBlock* DefaultBlock = *Src->succ_rbegin(); + assert(Src->succ_rbegin() != Src->succ_rend()); + CFGBlock *DefaultBlock = *Src->succ_rbegin(); + // Sanity check for default blocks that are unreachable and not caught + // by earlier stages. + if (!DefaultBlock) + return NULL; + bool IsNew; - ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, - Pred->getLocationContext()), St, &IsNew); + ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, + Pred->getLocationContext()), St, &IsNew); Succ->addPredecessor(Pred, *Eng.G); if (IsNew) { @@ -735,12 +712,13 @@ EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() { } ExplodedNode* -EndOfFunctionNodeBuilder::generateNode(const GRState* State, - ExplodedNode* P, const void *tag) { +EndOfFunctionNodeBuilder::generateNode(const ProgramState *State, + ExplodedNode *P, + const ProgramPointTag *tag) { hasGeneratedNode = true; bool IsNew; - ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B, + ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B, Pred->getLocationContext(), tag ? tag : Tag), State, &IsNew); @@ -754,7 +732,7 @@ EndOfFunctionNodeBuilder::generateNode(const GRState* State, return NULL; } -void EndOfFunctionNodeBuilder::GenerateCallExitNode(const GRState *state) { +void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) { hasGeneratedNode = true; // Create a CallExit node and enqueue it. const StackFrameContext *LocCtx @@ -773,7 +751,7 @@ void EndOfFunctionNodeBuilder::GenerateCallExitNode(const GRState *state) { } -void CallEnterNodeBuilder::generateNode(const GRState *state) { +void CallEnterNodeBuilder::generateNode(const ProgramState *state) { // Check if the callee is in the same translation unit. if (CalleeCtx->getTranslationUnit() != Pred->getLocationContext()->getTranslationUnit()) { @@ -787,30 +765,13 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) { // Create a new AnalysisManager with components of the callee's // TranslationUnit. - // The Diagnostic is actually shared when we create ASTUnits from AST files. - AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), - OldMgr.getLangOptions(), - OldMgr.getPathDiagnosticClient(), - OldMgr.getStoreManagerCreator(), - OldMgr.getConstraintManagerCreator(), - OldMgr.getCheckerManager(), - OldMgr.getIndexer(), - OldMgr.getMaxNodes(), OldMgr.getMaxVisit(), - OldMgr.shouldVisualizeGraphviz(), - OldMgr.shouldVisualizeUbigraph(), - OldMgr.shouldPurgeDead(), - OldMgr.shouldEagerlyAssume(), - OldMgr.shouldTrimGraph(), - OldMgr.shouldInlineCall(), - OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(), - OldMgr.getAnalysisContextManager().getAddImplicitDtors(), - OldMgr.getAnalysisContextManager().getAddInitializers(), - OldMgr.shouldEagerlyTrimExplodedGraph()); - llvm::OwningPtr<TransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(), - /* GCEnabled */ false, - AMgr.getLangOptions())); + // The Diagnostic is actually shared when we create ASTUnits from AST files. + AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr); + // Create the new engine. - ExprEngine NewEng(AMgr, TF.take()); + // FIXME: This cast isn't really safe. + bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled(); + ExprEngine NewEng(AMgr, GCEnabled); // Create the new LocationContext. AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), @@ -823,8 +784,8 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) { OldLocCtx->getIndex()); // Now create an initial state for the new engine. - const GRState *NewState = NewEng.getStateManager().MarshalState(state, - NewLocCtx); + const ProgramState *NewState = + NewEng.getStateManager().MarshalState(state, NewLocCtx); ExplodedNodeSet ReturnNodes; NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), NewState, ReturnNodes); @@ -850,7 +811,7 @@ void CallEnterNodeBuilder::generateNode(const GRState *state) { Eng.WList->enqueue(Node); } -void CallExitNodeBuilder::generateNode(const GRState *state) { +void CallExitNodeBuilder::generateNode(const ProgramState *state) { // Get the callee's location context. const StackFrameContext *LocCtx = cast<StackFrameContext>(Pred->getLocationContext()); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp index 3961c7b..e1b982c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ExprObjC.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" using namespace clang; using namespace ento; -SVal Environment::lookupExpr(const Stmt* E) const { +SVal Environment::lookupExpr(const Stmt *E) const { const SVal* X = ExprBindings.lookup(E); if (X) { SVal V = *X; @@ -83,9 +84,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, case Stmt::CXXBindTemporaryExprClass: E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); continue; - case Stmt::MaterializeTemporaryExprClass: - E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(); - continue; + case Stmt::ObjCPropertyRefExprClass: + return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E)); + // Handle all other Stmt* using a lookup. default: break; @@ -129,18 +130,6 @@ public: }; } // end anonymous namespace -static bool isBlockExprInCallers(const Stmt *E, const LocationContext *LC) { - const LocationContext *ParentLC = LC->getParent(); - while (ParentLC) { - CFG &C = *ParentLC->getCFG(); - if (C.isBlkExpr(E)) - return true; - ParentLC = ParentLC->getParent(); - } - - return false; -} - // In addition to mapping from Stmt * - > SVals in the Environment, we also // maintain a mapping from Stmt * -> SVals (locations) that were used during // a load and store. @@ -158,24 +147,27 @@ static inline bool IsLocation(const Stmt *S) { Environment EnvironmentManager::removeDeadBindings(Environment Env, SymbolReaper &SymReaper, - const GRState *ST, - llvm::SmallVectorImpl<const MemRegion*> &DRoots) { - - CFG &C = *SymReaper.getLocationContext()->getCFG(); + const ProgramState *ST) { // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); - llvm::SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations; + SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations; + + MarkLiveCallback CB(SymReaper); + ScanReachableSymbols RSScaner(ST, CB); + + llvm::ImmutableMapRef<const Stmt*,SVal> + EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), + F.getTreeFactory()); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const Stmt *BlkExpr = I.getKey(); - // For recorded locations (used when evaluating loads and stores), we // consider them live only when their associated normal expression is // also live. @@ -185,41 +177,20 @@ EnvironmentManager::removeDeadBindings(Environment Env, deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); continue; } - const SVal &X = I.getData(); - // Block-level expressions in callers are assumed always live. - if (isBlockExprInCallers(BlkExpr, SymReaper.getLocationContext())) { - NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); - - if (isa<loc::MemRegionVal>(X)) { - const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); - DRoots.push_back(R); - } - - // Mark all symbols in the block expr's value live. - MarkLiveCallback cb(SymReaper); - ST->scanReachableSymbols(X, cb); - continue; - } - - // Not a block-level expression? - if (!C.isBlkExpr(BlkExpr)) - continue; - if (SymReaper.isLive(BlkExpr)) { // Copy the binding to the new map. - NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); + EBMapRef = EBMapRef.add(BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa<loc::MemRegionVal>(X)) { - const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); - DRoots.push_back(R); + const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion(); + SymReaper.markLive(R); } // Mark all symbols in the block expr's value live. - MarkLiveCallback cb(SymReaper); - ST->scanReachableSymbols(X, cb); + RSScaner.scan(X); continue; } @@ -228,17 +199,18 @@ EnvironmentManager::removeDeadBindings(Environment Env, // beginning of itself, but we need its UndefinedVal to determine its // SVal. if (X.isUndef() && cast<UndefinedVal>(X).getData()) - NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); + EBMapRef = EBMapRef.add(BlkExpr, X); } // Go through he deferred locations and add them to the new environment if // the correspond Stmt* is in the map as well. - for (llvm::SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator + for (SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1); - if (NewEnv.ExprBindings.lookup(S)) - NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, I->first, I->second); + if (EBMapRef.lookup(S)) + EBMapRef = EBMapRef.add(I->first, I->second); } + NewEnv.ExprBindings = EBMapRef.asImmutableMap(); return NewEnv; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index fa16fea..5762a21 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/Stmt.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" @@ -93,18 +93,17 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() { ProgramPoint progPoint = node->getLocation(); if (!isa<PostStmt>(progPoint)) continue; - // Condition 4. PostStmt ps = cast<PostStmt>(progPoint); - if (ps.getTag() || isa<PostStmtCustom>(ps)) + if (ps.getTag()) continue; if (isa<BinaryOperator>(ps.getStmt())) continue; // Conditions 5, 6, and 7. - const GRState *state = node->getState(); - const GRState *pred_state = pred->getState(); + const ProgramState *state = node->getState(); + const ProgramState *pred_state = pred->getState(); if (state->store != pred_state->store || state->GDM != pred_state->GDM || progPoint.getLocationContext() != pred->getLocationContext()) continue; @@ -134,11 +133,11 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() { // ExplodedNode. //===----------------------------------------------------------------------===// -static inline BumpVector<ExplodedNode*>& getVector(void* P) { +static inline BumpVector<ExplodedNode*>& getVector(void *P) { return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P); } -void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) { +void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); Preds.addNode(V, G); V->Succs.addNode(this, G); @@ -153,12 +152,12 @@ void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) { assert(getKind() == Size1); } -void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) { +void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) { assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0); assert(!getFlag()); if (getKind() == Size1) { - if (ExplodedNode* NOld = getNode()) { + if (ExplodedNode *NOld = getNode()) { BumpVectorContext &Ctx = G.getNodeAllocator(); BumpVector<ExplodedNode*> *V = G.getAllocator().Allocate<BumpVector<ExplodedNode*> >(); @@ -215,11 +214,11 @@ ExplodedNode** ExplodedNode::NodeGroup::end() const { } } -ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L, - const GRState* State, bool* IsNew) { +ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, + const ProgramState *State, bool* IsNew) { // Profile 'State' to determine if we already have an existing node. llvm::FoldingSetNodeID profile; - void* InsertPos = 0; + void *InsertPos = 0; NodeTy::Profile(profile, L, State); NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); @@ -285,7 +284,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty; Pass2Ty& Pass2 = M->M; - llvm::SmallVector<const ExplodedNode*, 10> WL1, WL2; + SmallVector<const ExplodedNode*, 10> WL1, WL2; // ===- Pass 1 (reverse DFS) -=== for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) { @@ -326,7 +325,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, // ===- Pass 2 (forward DFS to construct the new graph) -=== while (!WL2.empty()) { - const ExplodedNode* N = WL2.back(); + const ExplodedNode *N = WL2.back(); WL2.pop_back(); // Skip this node if we have already processed it. @@ -335,7 +334,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. - ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL); + ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, NULL); Pass2[N] = NewN; // Also record the reverse mapping from the new node to the old node. @@ -383,7 +382,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, } ExplodedNode* -InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const { +InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const { llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I = M.find(N); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ffe5f0b..ac9cf0b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -18,6 +18,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" @@ -35,25 +36,13 @@ using namespace clang; using namespace ento; -using llvm::dyn_cast; -using llvm::dyn_cast_or_null; -using llvm::cast; using llvm::APSInt; -namespace { - // Trait class for recording returned expression in the state. - struct ReturnExpr { - static int TagInt; - typedef const Stmt *data_type; - }; - int ReturnExpr::TagInt; -} - //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { +static inline Selector GetNullarySelector(const char* name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); } @@ -62,7 +51,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { // Engine construction and deletion. //===----------------------------------------------------------------------===// -ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) +ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled) : AMgr(mgr), Engine(*this), G(Engine.getGraph()), @@ -75,11 +64,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) EntryNode(NULL), currentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", getContext())), - BR(mgr, *this), TF(tf) { - - // FIXME: Eventually remove the TF object entirely. - TF->RegisterChecks(*this); - TF->RegisterPrinters(getStateManager().Printers); + ObjCGCEnabled(gcEnabled), BR(mgr, *this) { if (mgr.shouldEagerlyTrimExplodedGraph()) { // Enable eager node reclaimation when constructing the ExplodedGraph. @@ -96,8 +81,8 @@ ExprEngine::~ExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { - const GRState *state = StateMgr.getInitialState(InitLoc); +const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc) { + const ProgramState *state = StateMgr.getInitialState(InitLoc); // Preconditions. @@ -132,7 +117,7 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { if (!Constraint) break; - if (const GRState *newState = state->assume(*Constraint, true)) + if (const ProgramState *newState = state->assume(*Constraint, true)) state = newState; break; @@ -162,11 +147,11 @@ ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) { SVal calleeV = callOrMessage.getFunctionCallee(); if (const FunctionTextRegion *codeR = - llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) { + dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) { const FunctionDecl *fd = codeR->getDecl(); if (const IdentifierInfo *ii = fd->getIdentifier()) { - llvm::StringRef fname = ii->getName(); + StringRef fname = ii->getName(); if (fname == "strlen") return false; } @@ -183,28 +168,27 @@ ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const /// evalAssume - Called by ConstraintManager. Used to call checker-specific /// logic for handling assumptions on symbolic values. -const GRState *ExprEngine::processAssume(const GRState *state, SVal cond, - bool assumption) { - state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); - - // If the state is infeasible at this point, bail out. - if (!state) - return NULL; - - return TF->evalAssume(state, cond, assumption); +const ProgramState *ExprEngine::processAssume(const ProgramState *state, + SVal cond, bool assumption) { + return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); } -bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) { +bool ExprEngine::wantsRegionChangeUpdate(const ProgramState *state) { return getCheckerManager().wantsRegionChangeUpdate(state); } -const GRState * -ExprEngine::processRegionChanges(const GRState *state, +const ProgramState * +ExprEngine::processRegionChanges(const ProgramState *state, const StoreManager::InvalidatedSymbols *invalidated, - const MemRegion * const *Begin, - const MemRegion * const *End) { + ArrayRef<const MemRegion *> Explicits, + ArrayRef<const MemRegion *> Regions) { return getCheckerManager().runCheckersForRegionChanges(state, invalidated, - Begin, End); + Explicits, Regions); +} + +void ExprEngine::printState(raw_ostream &Out, const ProgramState *State, + const char *NL, const char *Sep) { + getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep); } void ExprEngine::processEndWorklist(bool hasWorkRemaining) { @@ -217,7 +201,7 @@ void ExprEngine::processCFGElement(const CFGElement E, case CFGElement::Invalid: llvm_unreachable("Unexpected CFGElement kind."); case CFGElement::Statement: - ProcessStmt(E.getAs<CFGStmt>()->getStmt(), builder); + ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), builder); return; case CFGElement::Initializer: ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), builder); @@ -232,9 +216,12 @@ void ExprEngine::processCFGElement(const CFGElement E, } void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { + // TODO: Use RAII to remove the unnecessary, tagged nodes. + //RegisterCreatedNodes registerCreatedNodes(getGraph()); + // Reclaim any unnecessary nodes in the ExplodedGraph. G.reclaimRecentlyAllocatedNodes(); - // Recycle any unused states in the GRStateManager. + // Recycle any unused states in the ProgramStateManager. StateMgr.recycleUnusedStates(); currentStmt = S.getStmt(); @@ -242,74 +229,93 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { currentStmt->getLocStart(), "Error evaluating statement"); + // A tag to track convenience transitions, which can be removed at cleanup. + static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node"); Builder = &builder; EntryNode = builder.getPredecessor(); + const ProgramState *EntryState = EntryNode->getState(); + CleanedState = EntryState; + ExplodedNode *CleanedNode = 0; + // Create the cleaned state. const LocationContext *LC = EntryNode->getLocationContext(); - SymbolReaper SymReaper(LC, currentStmt, SymMgr); + SymbolReaper SymReaper(LC, currentStmt, SymMgr, getStoreManager()); - if (AMgr.shouldPurgeDead()) { - const GRState *St = EntryNode->getState(); - getCheckerManager().runCheckersForLiveSymbols(St, SymReaper); + if (AMgr.getPurgeMode() != PurgeNone) { + getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); const StackFrameContext *SFC = LC->getCurrentStackFrame(); - CleanedState = StateMgr.removeDeadBindings(St, SFC, SymReaper); - } else { - CleanedState = EntryNode->getState(); + + // Create a state in which dead bindings are removed from the environment + // and the store. TODO: The function should just return new env and store, + // not a new state. + CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper); } // Process any special transfer function for dead symbols. ExplodedNodeSet Tmp; + if (!SymReaper.hasDeadSymbols()) { + // Generate a CleanedNode that has the environment and store cleaned + // up. Since no symbols are dead, we can optimize and not clean out + // the constraint manager. + CleanedNode = + Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag); + Tmp.Add(CleanedNode); - if (!SymReaper.hasDeadSymbols()) - Tmp.Add(EntryNode); - else { + } else { SaveAndRestore<bool> OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->hasGeneratedNode); SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); Builder->PurgingDeadSymbols = true; - // FIXME: This should soon be removed. - ExplodedNodeSet Tmp2; - getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, - CleanedState, SymReaper); - - getCheckerManager().runCheckersForDeadSymbols(Tmp, Tmp2, + // Call checkers with the non-cleaned state so that they could query the + // values of the soon to be dead symbols. + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForDeadSymbols(CheckedSet, EntryNode, SymReaper, currentStmt, *this); - if (!Builder->BuildSinks && !Builder->hasGeneratedNode) - Tmp.Add(EntryNode); - } + // For each node in CheckedSet, generate CleanedNodes that have the + // environment, the store, and the constraints cleaned up but have the + // user-supplied states as the predecessors. + for (ExplodedNodeSet::const_iterator + I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { + const ProgramState *CheckerState = (*I)->getState(); - bool HasAutoGenerated = false; + // The constraint manager has not been cleaned up yet, so clean up now. + CheckerState = getConstraintManager().removeDeadBindings(CheckerState, + SymReaper); - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - ExplodedNodeSet Dst; + assert(StateMgr.haveEqualEnvironments(CheckerState, EntryState) && + "Checkers are not allowed to modify the Environment as a part of " + "checkDeadSymbols processing."); + assert(StateMgr.haveEqualStores(CheckerState, EntryState) && + "Checkers are not allowed to modify the Store as a part of " + "checkDeadSymbols processing."); - // Set the cleaned state. - Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); + // Create a state based on CleanedState with CheckerState GDM and + // generate a transition to that state. + const ProgramState *CleanedCheckerSt = + StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); + ExplodedNode *CleanedNode = Builder->generateNode(currentStmt, + CleanedCheckerSt, *I, + &cleanupTag); + Tmp.Add(CleanedNode); + } + } + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + // TODO: Remove Dest set, it's no longer needed. + ExplodedNodeSet Dst; // Visit the statement. Visit(currentStmt, *I, Dst); - - // Do we need to auto-generate a node? We only need to do this to generate - // a node with a "cleaned" state; CoreEngine will actually handle - // auto-transitions for other cases. - if (Dst.size() == 1 && *Dst.begin() == EntryNode - && !Builder->hasGeneratedNode && !HasAutoGenerated) { - HasAutoGenerated = true; - builder.generateNode(currentStmt, GetState(EntryNode), *I); - } } // NULL out these variables to cleanup. CleanedState = NULL; EntryNode = NULL; - currentStmt = 0; - Builder = NULL; } @@ -334,7 +340,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){ ExplodedNode *Pred = *I; - const GRState *state = Pred->getState(); + const ProgramState *state = Pred->getState(); const FieldDecl *FD = BMI->getAnyMember(); @@ -391,7 +397,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor, StmtNodeBuilder &builder) { ExplodedNode *pred = builder.getPredecessor(); - const GRState *state = pred->getState(); + const ProgramState *state = pred->getState(); const VarDecl *varDecl = dtor.getVarDecl(); QualType varType = varDecl->getType(); @@ -422,8 +428,8 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, StmtNodeBuilder &builder) { } -void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { +void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), S->getLocStart(), "Error evaluating statement"); @@ -447,9 +453,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXCatchStmtClass: case Stmt::CXXDependentScopeMemberExprClass: - case Stmt::CXXForRangeStmtClass: case Stmt::CXXPseudoDestructorExprClass: - case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXThrowExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: @@ -472,7 +476,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, { SaveAndRestore<bool> OldSink(Builder->BuildSinks); Builder->BuildSinks = true; - const ExplodedNode *node = MakeNode(Dst, S, Pred, GetState(Pred)); + const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState()); Engine.addAbortedBlock(node, Builder->getBlock()); break; } @@ -495,6 +499,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::CaseStmtClass: case Stmt::CompoundStmtClass: case Stmt::ContinueStmtClass: + case Stmt::CXXForRangeStmtClass: case Stmt::DefaultStmtClass: case Stmt::DoStmtClass: case Stmt::ForStmtClass: @@ -511,7 +516,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::GNUNullExprClass: { // GNU __null is a pointer-width integer, not an actual pointer. - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false)); MakeNode(Dst, S, Pred, state); break; @@ -522,11 +527,12 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; case Stmt::ObjCPropertyRefExprClass: - VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst); + // Implicitly handled by Environment::getSVal(). + Dst.Add(Pred); break; case Stmt::ImplicitValueInitExprClass: { - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); QualType ty = cast<ImplicitValueInitExpr>(S)->getType(); SVal val = svalBuilder.makeZeroVal(ty); MakeNode(Dst, S, Pred, state->BindExpr(S, val)); @@ -558,6 +564,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: + case Stmt::AtomicExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need @@ -597,7 +604,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } else if (B->getOpcode() == BO_Comma) { - const GRState* state = GetState(Pred); + const ProgramState *state = Pred->getState(); MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); break; } @@ -621,6 +628,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } + case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXConstructExprClass: { const CXXConstructExpr *C = cast<CXXConstructExpr>(S); // For block-level CXXConstructExpr, we don't have a destination region. @@ -644,7 +652,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, // the CFG do not model them as explicit control-flow. case Stmt::ChooseExprClass: { // __builtin_choose_expr - const ChooseExpr* C = cast<ChooseExpr>(S); + const ChooseExpr *C = cast<ChooseExpr>(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } @@ -687,7 +695,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::CXXConstCastExprClass: case Stmt::CXXFunctionalCastExprClass: case Stmt::ObjCBridgedCastExprClass: { - const CastExpr* C = cast<CastExpr>(S); + const CastExpr *C = cast<CastExpr>(S); // Handle the previsit checks. ExplodedNodeSet dstPrevisit; getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this); @@ -708,7 +716,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, const MaterializeTemporaryExpr *Materialize = cast<MaterializeTemporaryExpr>(S); if (!Materialize->getType()->isRecordType()) - CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst); + CreateCXXTemporaryObject(Materialize, Pred, Dst); else Visit(Materialize->GetTemporaryExpr(), Pred, Dst); break; @@ -730,7 +738,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; case Stmt::ObjCMessageExprClass: - VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst); + VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst); break; case Stmt::ObjCAtThrowStmtClass: { @@ -738,7 +746,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, // an abort. SaveAndRestore<bool> OldSink(Builder->BuildSinks); Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, GetState(Pred)); + MakeNode(Dst, S, Pred, Pred->getState()); break; } @@ -756,7 +764,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; case Stmt::StmtExprClass: { - const StmtExpr* SE = cast<StmtExpr>(S); + const StmtExpr *SE = cast<StmtExpr>(S); if (SE->getSubStmt()->body_empty()) { // Empty statement expression. @@ -766,8 +774,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { - const GRState* state = GetState(Pred); + if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { + const ProgramState *state = Pred->getState(); MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); } else @@ -777,7 +785,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, } case Stmt::StringLiteralClass: { - const GRState* state = GetState(Pred); + const ProgramState *state = Pred->getState(); SVal V = state->getLValue(cast<StringLiteral>(S)); MakeNode(Dst, S, Pred, state->BindExpr(S, V)); return; @@ -811,8 +819,7 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes, if (nodeBuilder.getBlockCounter().getNumVisited( pred->getLocationContext()->getCurrentStackFrame(), block->getBlockID()) >= AMgr.getMaxVisit()) { - - static int tag = 0; + static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); nodeBuilder.generateNode(pred->getState(), pred, &tag, true); } } @@ -821,11 +828,12 @@ void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes, // Generic node creation. //===----------------------------------------------------------------------===// -ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, - ExplodedNode* Pred, const GRState* St, - ProgramPoint::Kind K, const void *tag) { +ExplodedNode *ExprEngine::MakeNode(ExplodedNodeSet &Dst, const Stmt *S, + ExplodedNode *Pred, const ProgramState *St, + ProgramPoint::Kind K, + const ProgramPointTag *tag) { assert (Builder && "StmtNodeBuilder not present."); - SaveAndRestore<const void*> OldTag(Builder->Tag); + SaveAndRestore<const ProgramPointTag*> OldTag(Builder->Tag); Builder->Tag = tag; return Builder->MakeNode(Dst, S, Pred, St, K); } @@ -834,8 +842,8 @@ ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, // Branch processing. //===----------------------------------------------------------------------===// -const GRState* ExprEngine::MarkBranch(const GRState* state, - const Stmt* Terminator, +const ProgramState *ExprEngine::MarkBranch(const ProgramState *state, + const Stmt *Terminator, bool branchTaken) { switch (Terminator->getStmtClass()) { @@ -855,7 +863,7 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, // For ||, if we take the false branch, then the value of the whole // expression is that of the RHS expression. - const Expr* Ex = (Op == BO_LAnd && branchTaken) || + const Expr *Ex = (Op == BO_LAnd && branchTaken) || (Op == BO_LOr && !branchTaken) ? B->getRHS() : B->getLHS(); @@ -870,7 +878,7 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, // For ?, if branchTaken == true then the value is either the LHS or // the condition itself. (GNU extension). - const Expr* Ex; + const Expr *Ex; if (branchTaken) Ex = C->getTrueExpr(); @@ -882,9 +890,9 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, case Stmt::ChooseExprClass: { // ?: - const ChooseExpr* C = cast<ChooseExpr>(Terminator); + const ChooseExpr *C = cast<ChooseExpr>(Terminator); - const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); + const Expr *Ex = branchTaken ? C->getLHS() : C->getRHS(); return state->BindExpr(C, UndefinedVal(Ex)); } } @@ -895,8 +903,10 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, /// integers that promote their values (which are currently not tracked well). /// This function returns the SVal bound to Condition->IgnoreCasts if all the // cast(s) did was sign-extend the original value. -static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, - const Stmt* Condition, ASTContext& Ctx) { +static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, + const ProgramState *state, + const Stmt *Condition, + ASTContext &Ctx) { const Expr *Ex = dyn_cast<Expr>(Condition); if (!Ex) @@ -929,7 +939,7 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, return state->getSVal(Ex); } -void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, +void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, BranchNodeBuilder& builder) { // Check for NULL conditions; e.g. "for(;;)" @@ -948,7 +958,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, if (!builder.isFeasible(true) && !builder.isFeasible(false)) return; - const GRState* PrevState = builder.getState(); + const ProgramState *PrevState = builder.getState(); SVal X = PrevState->getSVal(Condition); if (X.isUnknownOrUndef()) { @@ -980,7 +990,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, // Process the true branch. if (builder.isFeasible(true)) { - if (const GRState *state = PrevState->assume(V, true)) + if (const ProgramState *state = PrevState->assume(V, true)) builder.generateNode(MarkBranch(state, Term, true), true); else builder.markInfeasible(true); @@ -988,7 +998,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, // Process the false branch. if (builder.isFeasible(false)) { - if (const GRState *state = PrevState->assume(V, false)) + if (const ProgramState *state = PrevState->assume(V, false)) builder.generateNode(MarkBranch(state, Term, false), false); else builder.markInfeasible(false); @@ -999,7 +1009,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, /// nodes by processing the 'effects' of a computed goto jump. void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { - const GRState *state = builder.getState(); + const ProgramState *state = builder.getState(); SVal V = state->getSVal(builder.getTarget()); // Three possibilities: @@ -1021,8 +1031,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { } } - assert(false && "No block with label."); - return; + llvm_unreachable("No block with label."); } if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) { @@ -1040,31 +1049,9 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { builder.generateNode(I, state); } - -void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, - const Expr* R, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - - assert(Ex == currentStmt && - Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); - - const GRState* state = GetState(Pred); - SVal X = state->getSVal(Ex); - - assert (X.isUndef()); - - const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData(); - assert(SE); - X = state->getSVal(SE); - - // Make sure that we invalidate the previous binding. - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); -} - /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) { - getTF().evalEndPath(*this, builder); StateMgr.EndPath(builder.getState()); getCheckerManager().runCheckersForEndPath(builder, *this); } @@ -1073,8 +1060,8 @@ void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) { /// nodes by processing the 'effects' of a switch statement. void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { typedef SwitchNodeBuilder::iterator iterator; - const GRState* state = builder.getState(); - const Expr* CondE = builder.getCondition(); + const ProgramState *state = builder.getState(); + const Expr *CondE = builder.getCondition(); SVal CondV_untested = state->getSVal(CondE); if (CondV_untested.isUndef()) { @@ -1086,7 +1073,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { } DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested); - const GRState *DefaultSt = state; + const ProgramState *DefaultSt = state; iterator I = builder.begin(), EI = builder.end(); bool defaultIsFeasible = I == EI; @@ -1096,28 +1083,16 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { if (!I.getBlock()) continue; - const CaseStmt* Case = I.getCase(); + const CaseStmt *Case = I.getCase(); // Evaluate the LHS of the case value. - Expr::EvalResult V1; - bool b = Case->getLHS()->Evaluate(V1, getContext()); - - // Sanity checks. These go away in Release builds. - assert(b && V1.Val.isInt() && !V1.HasSideEffects - && "Case condition must evaluate to an integer constant."); - (void)b; // silence unused variable warning - assert(V1.Val.getInt().getBitWidth() == - getContext().getTypeSize(CondE->getType())); + llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext()); + assert(V1.getBitWidth() == getContext().getTypeSize(CondE->getType())); // Get the RHS of the case, if it exists. - Expr::EvalResult V2; - - if (const Expr* E = Case->getRHS()) { - b = E->Evaluate(V2, getContext()); - assert(b && V2.Val.isInt() && !V2.HasSideEffects - && "Case condition must evaluate to an integer constant."); - (void)b; // silence unused variable warning - } + llvm::APSInt V2; + if (const Expr *E = Case->getRHS()) + V2 = E->EvaluateKnownConstInt(getContext()); else V2 = V1; @@ -1126,12 +1101,12 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { // This should be easy once we have "ranges" for NonLVals. do { - nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); + nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1)); DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state, CondV, CaseVal); // Now "assume" that the case matches. - if (const GRState* stateNew = state->assume(Res, true)) { + if (const ProgramState *stateNew = state->assume(Res, true)) { builder.generateCaseStmtNode(I, stateNew); // If CondV evaluates to a constant, then we know that this @@ -1144,7 +1119,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { // Now "assume" that the case doesn't match. Add this state // to the default state (if it is feasible). if (DefaultSt) { - if (const GRState *stateNew = DefaultSt->assume(Res, false)) { + if (const ProgramState *stateNew = DefaultSt->assume(Res, false)) { defaultIsFeasible = true; DefaultSt = stateNew; } @@ -1155,11 +1130,11 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { } // Concretize the next value in the range. - if (V1.Val.getInt() == V2.Val.getInt()) + if (V1 == V2) break; - ++V1.Val.getInt(); - assert (V1.Val.getInt() <= V2.Val.getInt()); + ++V1; + assert (V1 <= V2); } while (true); } @@ -1184,120 +1159,16 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { builder.generateDefaultCaseNode(DefaultSt); } -void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) { - const GRState *state = B.getState()->enterStackFrame(B.getCalleeContext()); - B.generateNode(state); -} - -void ExprEngine::processCallExit(CallExitNodeBuilder &B) { - const GRState *state = B.getState(); - const ExplodedNode *Pred = B.getPredecessor(); - const StackFrameContext *calleeCtx = - cast<StackFrameContext>(Pred->getLocationContext()); - const Stmt *CE = calleeCtx->getCallSite(); - - // If the callee returns an expression, bind its value to CallExpr. - const Stmt *ReturnedExpr = state->get<ReturnExpr>(); - if (ReturnedExpr) { - SVal RetVal = state->getSVal(ReturnedExpr); - state = state->BindExpr(CE, RetVal); - // Clear the return expr GDM. - state = state->remove<ReturnExpr>(); - } - - // Bind the constructed object value to CXXConstructExpr. - if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { - const CXXThisRegion *ThisR = - getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); - - SVal ThisV = state->getSVal(ThisR); - // Always bind the region to the CXXConstructExpr. - state = state->BindExpr(CCE, ThisV); - } - - B.generateNode(state); -} - -//===----------------------------------------------------------------------===// -// Transfer functions: logical operations ('&&', '||'). -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - assert(B->getOpcode() == BO_LAnd || - B->getOpcode() == BO_LOr); - - assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); - - const GRState* state = GetState(Pred); - SVal X = state->getSVal(B); - assert(X.isUndef()); - - const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData(); - assert(Ex); - - if (Ex == B->getRHS()) { - X = state->getSVal(Ex); - - // Handle undefined values. - if (X.isUndef()) { - MakeNode(Dst, B, Pred, state->BindExpr(B, X)); - return; - } - - DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X); - - // We took the RHS. Because the value of the '&&' or '||' expression must - // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 - // or 1. Alternatively, we could take a lazy approach, and calculate this - // value later when necessary. We don't have the machinery in place for - // this right now, and since most logical expressions are used for branches, - // the payoff is not likely to be large. Instead, we do eager evaluation. - if (const GRState *newState = state->assume(XD, true)) - MakeNode(Dst, B, Pred, - newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType()))); - - if (const GRState *newState = state->assume(XD, false)) - MakeNode(Dst, B, Pred, - newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType()))); - } - else { - // We took the LHS expression. Depending on whether we are '&&' or - // '||' we know what the value of the expression is via properties of - // the short-circuiting. - X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U, - B->getType()); - MakeNode(Dst, B, Pred, state->BindExpr(B, X)); - } -} - //===----------------------------------------------------------------------===// // Transfer functions: Loads and stores. //===----------------------------------------------------------------------===// -void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - - ExplodedNodeSet Tmp; - - CanQualType T = getContext().getCanonicalType(BE->getType()); - SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, - Pred->getLocationContext()); - - MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), - ProgramPoint::PostLValueKind); - - // Post-visit the BlockExpr. - getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); -} - void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); - if (const VarDecl* VD = dyn_cast<VarDecl>(D)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { assert(Ex->isLValue()); SVal V = state->getLValue(VD, Pred->getLocationContext()); @@ -1314,13 +1185,13 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ProgramPoint::PostLValueKind); return; } - if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) { + if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) { assert(!Ex->isLValue()); SVal V = svalBuilder.makeIntVal(ED->getInitVal()); MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); return; } - if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), ProgramPoint::PostLValueKind); @@ -1331,124 +1202,93 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } /// VisitArraySubscriptExpr - Transfer function for array accesses -void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A, - ExplodedNode* Pred, - ExplodedNodeSet& Dst){ +void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, + ExplodedNode *Pred, + ExplodedNodeSet &Dst){ - const Expr* Base = A->getBase()->IgnoreParens(); - const Expr* Idx = A->getIdx()->IgnoreParens(); + const Expr *Base = A->getBase()->IgnoreParens(); + const Expr *Idx = A->getIdx()->IgnoreParens(); - // Evaluate the base. - ExplodedNodeSet Tmp; - Visit(Base, Pred, Tmp); - - for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { - ExplodedNodeSet Tmp2; - Visit(Idx, *I1, Tmp2); // Evaluate the index. - ExplodedNodeSet Tmp3; - getCheckerManager().runCheckersForPreStmt(Tmp3, Tmp2, A, *this); - - for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { - const GRState* state = GetState(*I2); - SVal V = state->getLValue(A->getType(), state->getSVal(Idx), - state->getSVal(Base)); - assert(A->isLValue()); - MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind); - } + + ExplodedNodeSet checkerPreStmt; + getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this); + + for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(), + ei = checkerPreStmt.end(); it != ei; ++it) { + const ProgramState *state = (*it)->getState(); + SVal V = state->getLValue(A->getType(), state->getSVal(Idx), + state->getSVal(Base)); + assert(A->isLValue()); + MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind); } } /// VisitMemberExpr - Transfer function for member expressions. -void ExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - Expr *baseExpr = M->getBase()->IgnoreParens(); - ExplodedNodeSet dstBase; - Visit(baseExpr, Pred, dstBase); +void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { - FieldDecl *field = dyn_cast<FieldDecl>(M->getMemberDecl()); + Decl *member = M->getMemberDecl(); + if (VarDecl *VD = dyn_cast<VarDecl>(member)) { + assert(M->isLValue()); + VisitCommonDeclRefExpr(M, VD, Pred, Dst); + return; + } + + FieldDecl *field = dyn_cast<FieldDecl>(member); if (!field) // FIXME: skipping member expressions for non-fields return; - for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); - I != E; ++I) { - const GRState* state = GetState(*I); - SVal baseExprVal = state->getSVal(baseExpr); - if (isa<nonloc::LazyCompoundVal>(baseExprVal) || - isa<nonloc::CompoundVal>(baseExprVal) || - // FIXME: This can originate by conjuring a symbol for an unknown - // temporary struct object, see test/Analysis/fields.c: - // (p = getit()).x - isa<nonloc::SymbolVal>(baseExprVal)) { - MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal())); - continue; - } + Expr *baseExpr = M->getBase()->IgnoreParens(); + const ProgramState *state = Pred->getState(); + SVal baseExprVal = state->getSVal(baseExpr); + if (isa<nonloc::LazyCompoundVal>(baseExprVal) || + isa<nonloc::CompoundVal>(baseExprVal) || + // FIXME: This can originate by conjuring a symbol for an unknown + // temporary struct object, see test/Analysis/fields.c: + // (p = getit()).x + isa<nonloc::SymbolVal>(baseExprVal)) { + MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal())); + return; + } - // FIXME: Should we insert some assumption logic in here to determine - // if "Base" is a valid piece of memory? Before we put this assumption - // later when using FieldOffset lvals (which we no longer have). + // FIXME: Should we insert some assumption logic in here to determine + // if "Base" is a valid piece of memory? Before we put this assumption + // later when using FieldOffset lvals (which we no longer have). - // For all other cases, compute an lvalue. - SVal L = state->getLValue(field, baseExprVal); - if (M->isLValue()) - MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); - else - evalLoad(Dst, M, *I, state, L); - } + // For all other cases, compute an lvalue. + SVal L = state->getLValue(field, baseExprVal); + if (M->isLValue()) + MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind); + else + evalLoad(Dst, M, Pred, state, L); } /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore and (soon) VisitDeclStmt, and others. -void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, - ExplodedNode* Pred, const GRState* state, - SVal location, SVal Val, bool atDeclInit) { - +void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, + ExplodedNode *Pred, + SVal location, SVal Val, bool atDeclInit) { // Do a previsit of the bind. - ExplodedNodeSet CheckedSet, Src; - Src.Add(Pred); - getCheckerManager().runCheckersForBind(CheckedSet, Src, location, Val, StoreE, - *this); + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, + StoreE, *this); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { - if (Pred != *I) - state = GetState(*I); - - const GRState* newState = 0; + const ProgramState *state = (*I)->getState(); if (atDeclInit) { const VarRegion *VR = cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion()); - newState = state->bindDecl(VR, Val); - } - else { - if (location.isUnknown()) { - // We know that the new state will be the same as the old state since - // the location of the binding is "unknown". Consequently, there - // is no reason to just create a new node. - newState = state; - } - else { - // We are binding to a value other than 'unknown'. Perform the binding - // using the StoreManager. - newState = state->bindLoc(cast<Loc>(location), Val); - } + state = state->bindDecl(VR, Val); + } else { + state = state->bindLoc(location, Val); } - // The next thing to do is check if the TransferFuncs object wants to - // update the state based on the new binding. If the GRTransferFunc object - // doesn't do anything, just auto-propagate the current state. - - // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE' - // is non-NULL. Checkers typically care about - - StmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, - true); - - getTF().evalBind(BuilderRef, location, Val); + MakeNode(Dst, StoreE, *I, state); } } @@ -1460,11 +1300,11 @@ void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, /// @param state The current simulation state /// @param location The location to store the value /// @param Val The value to be stored -void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, - const Expr* LocationE, - ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val, - const void *tag) { +void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, + const Expr *LocationE, + ExplodedNode *Pred, + const ProgramState *state, SVal location, SVal Val, + const ProgramPointTag *tag) { assert(Builder && "StmtNodeBuilder must be defined."); @@ -1474,9 +1314,8 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, if (isa<loc::ObjCPropRef>(location)) { loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location); - ExplodedNodeSet src = Pred; return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(), - StoreE, Val), src, Dst); + StoreE, Val), Pred, Dst); } // Evaluate the location (checks for bad dereferences). @@ -1493,38 +1332,38 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, ProgramPoint::PostStoreKind); for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); + evalBind(Dst, StoreE, *NI, location, Val); } -void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, QualType LoadTy) { +void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, + ExplodedNode *Pred, + const ProgramState *state, SVal location, + const ProgramPointTag *tag, QualType LoadTy) { assert(!isa<NonLoc>(location) && "location cannot be a NonLoc."); if (isa<loc::ObjCPropRef>(location)) { loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location); - ExplodedNodeSet src = Pred; return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex), - src, Dst); + Pred, Dst); } // Are we loading from a region? This actually results in two loads; one // to fetch the address of the referenced value and one to fetch the // referenced value. - if (const TypedRegion *TR = - dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + if (const TypedValueRegion *TR = + dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { - static int loadReferenceTag = 0; + static SimpleProgramPointTag + loadReferenceTag("ExprEngine : Load Reference"); ExplodedNodeSet Tmp; evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, getContext().getPointerType(RT->getPointeeType())); // Perform the load from the referenced value. for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) { - state = GetState(*I); + state = (*I)->getState(); location = state->getSVal(Ex); evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); } @@ -1535,10 +1374,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex, evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); } -void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, QualType LoadTy) { +void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, + ExplodedNode *Pred, + const ProgramState *state, SVal location, + const ProgramPointTag *tag, QualType LoadTy) { // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; @@ -1554,7 +1393,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, // Proceed with the load. for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { - state = GetState(*NI); + state = (*NI)->getState(); if (location.isUnknown()) { // This is important. We must nuke the old binding. @@ -1572,9 +1411,9 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, } void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, - ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag, bool isLoad) { + ExplodedNode *Pred, + const ProgramState *state, SVal location, + const ProgramPointTag *tag, bool isLoad) { // Early checks for performance reason. if (location.isUnknown()) { Dst.Add(Pred); @@ -1582,7 +1421,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, } ExplodedNodeSet Src; - if (Builder->GetState(Pred) == state) { + if (Pred->getState() == state) { Src.Add(Pred); } else { // Associate this new state with an ExplodedNode. @@ -1593,7 +1432,11 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, // "p = 0" is not noted as "Null pointer value stored to 'p'" but // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - ExplodedNode *N = Builder->generateNode(S, state, Pred, this); + + // FIXME: why is 'tag' not used instead of etag? + static SimpleProgramPointTag etag("ExprEngine: Location"); + + ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag); Src.Add(N ? N : Pred); } getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, @@ -1611,7 +1454,7 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, // cases as well. #if 0 - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -1627,7 +1470,7 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, case Stmt::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE); methodDecl = - llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl()); + dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl()); break; } case Stmt::CXXMemberCallExprClass: { @@ -1676,126 +1519,18 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, #endif } -void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred, - ExplodedNodeSet& dst) { - - // Determine the type of function we're calling (if available). - const FunctionProtoType *Proto = NULL; - QualType FnType = CE->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) - Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - - // Should the first argument be evaluated as an lvalue? - bool firstArgumentAsLvalue = false; - switch (CE->getStmtClass()) { - case Stmt::CXXOperatorCallExprClass: - firstArgumentAsLvalue = true; - break; - default: - break; - } - - // Evaluate the arguments. - ExplodedNodeSet dstArgsEvaluated; - evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated, - firstArgumentAsLvalue); - - // Evaluate the callee. - ExplodedNodeSet dstCalleeEvaluated; - evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated); - - // Perform the previsit of the CallExpr. - ExplodedNodeSet dstPreVisit; - getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated, - CE, *this); - - // Now evaluate the call itself. - class DefaultEval : public GraphExpander { - ExprEngine &Eng; - const CallExpr *CE; - public: - - DefaultEval(ExprEngine &eng, const CallExpr *ce) - : Eng(eng), CE(ce) {} - virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { - // Should we inline the call? - if (Eng.getAnalysisManager().shouldInlineCall() && - Eng.InlineCall(Dst, CE, Pred)) { - return; - } - - StmtNodeBuilder &Builder = Eng.getBuilder(); - assert(&Builder && "StmtNodeBuilder must be defined."); - - // Dispatch to the plug-in transfer function. - unsigned oldSize = Dst.size(); - SaveOr OldHasGen(Builder.hasGeneratedNode); - - // Dispatch to transfer function logic to handle the call itself. - const Expr* Callee = CE->getCallee()->IgnoreParens(); - const GRState* state = Eng.GetState(Pred); - SVal L = state->getSVal(Callee); - Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder.BuildSinks && Dst.size() == oldSize && - !Builder.hasGeneratedNode) - Eng.MakeNode(Dst, CE, Pred, state); - } - }; - - // Finally, evaluate the function call. We try each of the checkers - // to see if the can evaluate the function call. - ExplodedNodeSet dstCallEvaluated; - DefaultEval defEval(*this, CE); - getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, - dstPreVisit, - CE, *this, &defEval); - - // Finally, perform the post-condition check of the CallExpr and store - // the created nodes in 'Dst'. - getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, - *this); -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C dot-syntax to access a property. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Ex, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet dstBase; - - // Visit the receiver (if any). - if (Ex->isObjectReceiver()) - Visit(Ex->getBase(), Pred, dstBase); - else - dstBase = Pred; - - ExplodedNodeSet dstPropRef; - - // Using the base, compute the lvalue of the instance variable. - for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); - I!=E; ++I) { - ExplodedNode *nodeBase = *I; - const GRState *state = GetState(nodeBase); - MakeNode(dstPropRef, Ex, *I, state->BindExpr(Ex, loc::ObjCPropRef(Ex))); - } - - Dst.insert(dstPropRef); +std::pair<const ProgramPointTag *, const ProgramPointTag*> +ExprEngine::getEagerlyAssumeTags() { + static SimpleProgramPointTag + EagerlyAssumeTrue("ExprEngine : Eagerly Assume True"), + EagerlyAssumeFalse("ExprEngine : Eagerly Assume False"); + return std::make_pair(&EagerlyAssumeTrue, &EagerlyAssumeFalse); } -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C ivar references. -//===----------------------------------------------------------------------===// - -static std::pair<const void*,const void*> EagerlyAssumeTag - = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0)); - void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, const Expr *Ex) { + + for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { ExplodedNode *Pred = *I; @@ -1808,25 +1543,24 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, continue; } - const GRState* state = GetState(Pred); + const ProgramState *state = Pred->getState(); SVal V = state->getSVal(Ex); if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) { + const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags = + getEagerlyAssumeTags(); + // First assume that the condition is true. - if (const GRState *stateTrue = state->assume(*SEV, true)) { - stateTrue = stateTrue->BindExpr(Ex, - svalBuilder.makeIntVal(1U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, - &EagerlyAssumeTag, Pred->getLocationContext()), - stateTrue, Pred)); + if (const ProgramState *StateTrue = state->assume(*SEV, true)) { + SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); + StateTrue = StateTrue->BindExpr(Ex, Val); + Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first)); } // Next, assume that the condition is false. - if (const GRState *stateFalse = state->assume(*SEV, false)) { - stateFalse = stateFalse->BindExpr(Ex, - svalBuilder.makeIntVal(0U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag, - Pred->getLocationContext()), - stateFalse, Pred)); + if (const ProgramState *StateFalse = state->assume(*SEV, false)) { + SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); + StateFalse = StateFalse->BindExpr(Ex, Val); + Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second)); } } else @@ -1834,954 +1568,15 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, } } -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C @synchronized. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - - // The mutex expression is a CFGElement, so we don't need to explicitly - // visit it since it will already be processed. - - // Pre-visit the ObjCAtSynchronizedStmt. - ExplodedNodeSet Tmp; - Tmp.Add(Pred); - getCheckerManager().runCheckersForPreStmt(Dst, Tmp, S, *this); -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C ivar references. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - // Visit the base expression, which is needed for computing the lvalue - // of the ivar. - ExplodedNodeSet dstBase; - const Expr *baseExpr = Ex->getBase(); - Visit(baseExpr, Pred, dstBase); - - ExplodedNodeSet dstIvar; - - // Using the base, compute the lvalue of the instance variable. - for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end(); - I!=E; ++I) { - ExplodedNode *nodeBase = *I; - const GRState *state = GetState(nodeBase); - SVal baseVal = state->getSVal(baseExpr); - SVal location = state->getLValue(Ex->getDecl(), baseVal); - MakeNode(dstIvar, Ex, *I, state->BindExpr(Ex, location)); - } - - // Perform the post-condition check of the ObjCIvarRefExpr and store - // the created nodes in 'Dst'. - getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C fast enumeration 'for' statements. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - - // ObjCForCollectionStmts are processed in two places. This method - // handles the case where an ObjCForCollectionStmt* occurs as one of the - // statements within a basic block. This transfer function does two things: - // - // (1) binds the next container value to 'element'. This creates a new - // node in the ExplodedGraph. - // - // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating - // whether or not the container has any more elements. This value - // will be tested in ProcessBranch. We need to explicitly bind - // this value because a container can contain nil elements. - // - // FIXME: Eventually this logic should actually do dispatches to - // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). - // This will require simulating a temporary NSFastEnumerationState, either - // through an SVal or through the use of MemRegions. This value can - // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop - // terminates we reclaim the temporary (it goes out of scope) and we - // we can test if the SVal is 0 or if the MemRegion is null (depending - // on what approach we take). - // - // For now: simulate (1) by assigning either a symbol or nil if the - // container is empty. Thus this transfer function will by default - // result in state splitting. - - const Stmt* elem = S->getElement(); - SVal ElementV; - - if (const DeclStmt* DS = dyn_cast<DeclStmt>(elem)) { - const VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl()); - assert (ElemD->getInit() == 0); - ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext()); - VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV); - return; - } - - ExplodedNodeSet Tmp; - Visit(cast<Expr>(elem), Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem)); - } -} - -void ExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S, - ExplodedNode* Pred, ExplodedNodeSet& Dst, - SVal ElementV) { - - // Check if the location we are writing back to is a null pointer. - const Stmt* elem = S->getElement(); - ExplodedNodeSet Tmp; - evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); - - if (Tmp.empty()) - return; - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { - Pred = *NI; - const GRState *state = GetState(Pred); - - // Handle the case where the container still has elements. - SVal TrueV = svalBuilder.makeTruthVal(1); - const GRState *hasElems = state->BindExpr(S, TrueV); - - // Handle the case where the container has no elements. - SVal FalseV = svalBuilder.makeTruthVal(0); - const GRState *noElems = state->BindExpr(S, FalseV); - - if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV)) - if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) { - // FIXME: The proper thing to do is to really iterate over the - // container. We will do this with dispatch logic to the store. - // For now, just 'conjure' up a symbolic value. - QualType T = R->getValueType(); - assert(Loc::isLocType(T)); - unsigned Count = Builder->getCurrentBlockCount(); - SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); - SVal V = svalBuilder.makeLoc(Sym); - hasElems = hasElems->bindLoc(ElementV, V); - - // Bind the location to 'nil' on the false branch. - SVal nilV = svalBuilder.makeIntVal(0, T); - noElems = noElems->bindLoc(ElementV, nilV); - } - - // Create the new nodes. - MakeNode(Dst, S, Pred, hasElems); - MakeNode(Dst, S, Pred, noElems); - } -} - -//===----------------------------------------------------------------------===// -// Transfer function: Objective-C message expressions. -//===----------------------------------------------------------------------===// - -namespace { -class ObjCMsgWLItem { -public: - ObjCMessageExpr::const_arg_iterator I; - ExplodedNode *N; - - ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} // end anonymous namespace - -void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, - ExplodedNode* Pred, - ExplodedNodeSet& Dst){ - - // Create a worklist to process both the arguments. - llvm::SmallVector<ObjCMsgWLItem, 20> WL; - - // But first evaluate the receiver (if any). - ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (const Expr *Receiver = ME->getInstanceReceiver()) { - ExplodedNodeSet Tmp; - Visit(Receiver, Pred, Tmp); - - if (Tmp.empty()) - return; - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) - WL.push_back(ObjCMsgWLItem(AI, *I)); - } - else - WL.push_back(ObjCMsgWLItem(AI, Pred)); - - // Evaluate the arguments. - ExplodedNodeSet ArgsEvaluated; - while (!WL.empty()) { - ObjCMsgWLItem Item = WL.back(); - WL.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - // Evaluate the subexpression. - ExplodedNodeSet Tmp; - - // FIXME: [Objective-C++] handle arguments that are references - Visit(*Item.I, Item.N, Tmp); - - // Enqueue evaluating the next argument on the worklist. - ++(Item.I); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - WL.push_back(ObjCMsgWLItem(Item.I, *NI)); - } - - // Now that the arguments are processed, handle the ObjC message. - VisitObjCMessage(ME, ArgsEvaluated, Dst); -} - -void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, - ExplodedNodeSet &Src, ExplodedNodeSet& Dst) { - - // Handle the previsits checks. - ExplodedNodeSet DstPrevisit; - getCheckerManager().runCheckersForPreObjCMessage(DstPrevisit, Src, msg,*this); - - // Proceed with evaluate the message expression. - ExplodedNodeSet dstEval; - - for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(), - DE = DstPrevisit.end(); DI != DE; ++DI) { - - ExplodedNode *Pred = *DI; - bool RaisesException = false; - unsigned oldSize = dstEval.size(); - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->hasGeneratedNode); - - if (const Expr *Receiver = msg.getInstanceReceiver()) { - const GRState *state = GetState(Pred); - SVal recVal = state->getSVal(Receiver); - if (!recVal.isUndef()) { - // Bifurcate the state into nil and non-nil ones. - DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); - - const GRState *notNilState, *nilState; - llvm::tie(notNilState, nilState) = state->assume(receiverVal); - - // There are three cases: can be nil or non-nil, must be nil, must be - // non-nil. We ignore must be nil, and merge the rest two into non-nil. - if (nilState && !notNilState) { - dstEval.insert(Pred); - continue; - } - - // Check if the "raise" message was sent. - assert(notNilState); - if (msg.getSelector() == RaiseSel) - RaisesException = true; - - // Check if we raise an exception. For now treat these as sinks. - // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, msg, Pred, notNilState); - } - } - else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { - IdentifierInfo* ClsName = Iface->getIdentifier(); - Selector S = msg.getSelector(); - - // Check for special instance methods. - if (!NSExceptionII) { - ASTContext& Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); - } - - if (ClsName == NSExceptionII) { - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { - ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = - new Selector[NUM_RAISE_SELECTORS]; - llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; - unsigned idx = 0; - - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - - // raise:format::arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - } - - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; - break; - } - } - - // Check if we raise an exception. For now treat these as sinks. - // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, msg, Pred, Builder->GetState(Pred)); - } - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && dstEval.size() == oldSize && - !Builder->hasGeneratedNode) - MakeNode(dstEval, msg.getOriginExpr(), Pred, GetState(Pred)); - } - - // Finally, perform the post-condition check of the ObjCMessageExpr and store - // the created nodes in 'Dst'. - getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); -} - -//===----------------------------------------------------------------------===// -// Transfer functions: Miscellaneous statements. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, - ExplodedNode *Pred, ExplodedNodeSet &Dst) { - - ExplodedNodeSet S1; - Visit(Ex, Pred, S1); - ExplodedNodeSet S2; - getCheckerManager().runCheckersForPreStmt(S2, S1, CastE, *this); - - if (CastE->getCastKind() == CK_LValueToRValue || - CastE->getCastKind() == CK_GetObjCProperty) { - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) { - ExplodedNode *subExprNode = *I; - const GRState *state = GetState(subExprNode); - evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex)); - } - return; - } - - // All other casts. - QualType T = CastE->getType(); - QualType ExTy = Ex->getType(); - - if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) - T = ExCast->getTypeAsWritten(); - - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - Pred = *I; - - switch (CastE->getCastKind()) { - case CK_LValueToRValue: - assert(false && "LValueToRValue casts handled earlier."); - case CK_GetObjCProperty: - assert(false && "GetObjCProperty casts handled earlier."); - case CK_ToVoid: - Dst.Add(Pred); - continue; - // The analyzer doesn't do anything special with these casts, - // since it understands retain/release semantics already. - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: // Fall-through. - // True no-ops. - case CK_NoOp: - case CK_FunctionToPointerDecay: { - // Copy the SVal of Ex to CastE. - const GRState *state = GetState(Pred); - SVal V = state->getSVal(Ex); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, Pred, state); - continue; - } - case CK_Dependent: - case CK_ArrayToPointerDecay: - case CK_BitCast: - case CK_LValueBitCast: - case CK_IntegralCast: - case CK_NullToPointer: - case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_PointerToBoolean: - case CK_IntegralToBoolean: - case CK_IntegralToFloating: - case CK_FloatingToIntegral: - case CK_FloatingToBoolean: - case CK_FloatingCast: - case CK_FloatingRealToComplex: - case CK_FloatingComplexToReal: - case CK_FloatingComplexToBoolean: - case CK_FloatingComplexCast: - case CK_FloatingComplexToIntegralComplex: - case CK_IntegralRealToComplex: - case CK_IntegralComplexToReal: - case CK_IntegralComplexToBoolean: - case CK_IntegralComplexCast: - case CK_IntegralComplexToFloatingComplex: - case CK_AnyPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - case CK_ObjCObjectLValueCast: { - // Delegate to SValBuilder to process. - const GRState* state = GetState(Pred); - SVal V = state->getSVal(Ex); - V = svalBuilder.evalCast(V, T, ExTy); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, Pred, state); - continue; - } - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: { - // For DerivedToBase cast, delegate to the store manager. - const GRState *state = GetState(Pred); - SVal val = state->getSVal(Ex); - val = getStoreManager().evalDerivedToBase(val, T); - state = state->BindExpr(CastE, val); - MakeNode(Dst, CastE, Pred, state); - continue; - } - // Various C++ casts that are not handled yet. - case CK_Dynamic: - case CK_ToUnion: - case CK_BaseToDerived: - case CK_NullToMemberPointer: - case CK_BaseToDerivedMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_UserDefinedConversion: - case CK_ConstructorConversion: - case CK_VectorSplat: - case CK_MemberPointerToBoolean: { - // Recover some path-sensitivty by conjuring a new value. - QualType resultType = CastE->getType(); - if (CastE->isLValue()) - resultType = getContext().getPointerType(resultType); - - SVal result = - svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, - Builder->getCurrentBlockCount()); - - const GRState *state = GetState(Pred)->BindExpr(CastE, result); - MakeNode(Dst, CastE, Pred, state); - continue; - } - } - } -} - -void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - const InitListExpr* ILE - = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); - ExplodedNodeSet Tmp; - Visit(ILE, Pred, Tmp); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { - const GRState* state = GetState(*I); - SVal ILV = state->getSVal(ILE); - const LocationContext *LC = (*I)->getLocationContext(); - state = state->bindCompoundLiteral(CL, LC, ILV); - - if (CL->isLValue()) { - MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC))); - } - else - MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); - } -} - -void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, - ExplodedNodeSet& Dst) { - - // The CFG has one DeclStmt per Decl. - const Decl* D = *DS->decl_begin(); - - if (!D || !isa<VarDecl>(D)) - return; - - const VarDecl* VD = dyn_cast<VarDecl>(D); - const Expr* InitEx = VD->getInit(); - - // FIXME: static variables may have an initializer, but the second - // time a function is called those values may not be current. - ExplodedNodeSet Tmp; - - if (InitEx) - Visit(InitEx, Pred, Tmp); - else - Tmp.Add(Pred); - - ExplodedNodeSet Tmp2; - getCheckerManager().runCheckersForPreStmt(Tmp2, Tmp, DS, *this); - - for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { - ExplodedNode *N = *I; - const GRState *state = GetState(N); - - // Decls without InitExpr are not initialized explicitly. - const LocationContext *LC = N->getLocationContext(); - - if (InitEx) { - SVal InitVal = state->getSVal(InitEx); - - // We bound the temp obj region to the CXXConstructExpr. Now recover - // the lazy compound value when the variable is not a reference. - if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && - !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){ - InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion()); - assert(isa<nonloc::LazyCompoundVal>(InitVal)); - } - - // Recover some path-sensitivity if a scalar value evaluated to - // UnknownVal. - if ((InitVal.isUnknown() || - !getConstraintManager().canReasonAbout(InitVal)) && - !VD->getType()->isReferenceType()) { - InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, - Builder->getCurrentBlockCount()); - } - - evalBind(Dst, DS, *I, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); - } - else { - state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); - MakeNode(Dst, DS, *I, state); - } - } -} - -namespace { - // This class is used by VisitInitListExpr as an item in a worklist - // for processing the values contained in an InitListExpr. -class InitListWLItem { -public: - llvm::ImmutableList<SVal> Vals; - ExplodedNode* N; - InitListExpr::const_reverse_iterator Itr; - - InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals, - InitListExpr::const_reverse_iterator itr) - : Vals(vals), N(n), Itr(itr) {} -}; -} - - -void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - const GRState* state = GetState(Pred); - QualType T = getContext().getCanonicalType(E->getType()); - unsigned NumInitElements = E->getNumInits(); - - if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { - llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList(); - - // Handle base case where the initializer has no elements. - // e.g: static int* myArray[] = {}; - if (NumInitElements == 0) { - SVal V = svalBuilder.makeCompoundVal(T, StartVals); - MakeNode(Dst, E, Pred, state->BindExpr(E, V)); - return; - } - - // Create a worklist to process the initializers. - llvm::SmallVector<InitListWLItem, 10> WorkList; - WorkList.reserve(NumInitElements); - WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); - InitListExpr::const_reverse_iterator ItrEnd = E->rend(); - assert(!(E->rbegin() == E->rend())); - - // Process the worklist until it is empty. - while (!WorkList.empty()) { - InitListWLItem X = WorkList.back(); - WorkList.pop_back(); - - ExplodedNodeSet Tmp; - Visit(*X.Itr, X.N, Tmp); - - InitListExpr::const_reverse_iterator NewItr = X.Itr + 1; - - for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { - // Get the last initializer value. - state = GetState(*NI); - SVal InitV = state->getSVal(cast<Expr>(*X.Itr)); - - // Construct the new list of values by prepending the new value to - // the already constructed list. - llvm::ImmutableList<SVal> NewVals = - getBasicVals().consVals(InitV, X.Vals); - - if (NewItr == ItrEnd) { - // Now we have a list holding all init values. Make CompoundValData. - SVal V = svalBuilder.makeCompoundVal(T, NewVals); - - // Make final state and node. - MakeNode(Dst, E, *NI, state->BindExpr(E, V)); - } - else { - // Still some initializer values to go. Push them onto the worklist. - WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr)); - } - } - } - - return; - } - - if (Loc::isLocType(T) || T->isIntegerType()) { - assert (E->getNumInits() == 1); - ExplodedNodeSet Tmp; - const Expr* Init = E->getInit(0); - Visit(Init, Pred, Tmp); - for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { - state = GetState(*I); - MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); - } - return; - } - - assert(0 && "unprocessed InitListExpr type"); -} - -/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type). -void ExprEngine::VisitUnaryExprOrTypeTraitExpr( - const UnaryExprOrTypeTraitExpr* Ex, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - QualType T = Ex->getTypeOfArgument(); - - if (Ex->getKind() == UETT_SizeOf) { - if (!T->isIncompleteType() && !T->isConstantSizeType()) { - assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); - - // FIXME: Add support for VLA type arguments, not just VLA expressions. - // When that happens, we should probably refactor VLASizeChecker's code. - if (Ex->isArgumentType()) { - Dst.Add(Pred); - return; - } - - // Get the size by getting the extent of the sub-expression. - // First, visit the sub-expression to find its region. - const Expr *Arg = Ex->getArgumentExpr(); - ExplodedNodeSet Tmp; - Visit(Arg, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - const MemRegion *MR = state->getSVal(Arg).getAsRegion(); - - // If the subexpression can't be resolved to a region, we don't know - // anything about its size. Just leave the state as is and continue. - if (!MR) { - Dst.Add(*I); - continue; - } - - // The result is the extent of the VLA. - SVal Extent = cast<SubRegion>(MR)->getExtent(svalBuilder); - MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent)); - } - - return; - } - else if (T->getAs<ObjCObjectType>()) { - // Some code tries to take the sizeof an ObjCObjectType, relying that - // the compiler has laid out its representation. Just report Unknown - // for these. - Dst.Add(Pred); - return; - } - } - - Expr::EvalResult Result; - Ex->Evaluate(Result, getContext()); - CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue()); - - MakeNode(Dst, Ex, Pred, - GetState(Pred)->BindExpr(Ex, - svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()))); -} - -void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { - Expr::EvalResult Res; - if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); - assert(OOE->getType()->isIntegerType()); - assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); - SVal X = svalBuilder.makeIntVal(IV); - MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); - return; - } - // FIXME: Handle the case where __builtin_offsetof is not a constant. - Dst.Add(Pred); -} - -void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - switch (U->getOpcode()) { - - default: - break; - - case UO_Real: { - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - - // FIXME: We don't have complex SValues yet. - if (Ex->getType()->isAnyComplexType()) { - // Just report "Unknown." - Dst.Add(*I); - continue; - } - - // For all other types, UO_Real is an identity operation. - assert (U->getType() == Ex->getType()); - const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); - } - - return; - } - - case UO_Imag: { - - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - // FIXME: We don't have complex SValues yet. - if (Ex->getType()->isAnyComplexType()) { - // Just report "Unknown." - Dst.Add(*I); - continue; - } - - // For all other types, UO_Imag returns 0. - const GRState* state = GetState(*I); - SVal X = svalBuilder.makeZeroVal(Ex->getType()); - MakeNode(Dst, U, *I, state->BindExpr(U, X)); - } - - return; - } - - case UO_Plus: - assert(!U->isLValue()); - // FALL-THROUGH. - case UO_Deref: - case UO_AddrOf: - case UO_Extension: { - - // Unary "+" is a no-op, similar to a parentheses. We still have places - // where it may be a block-level expression, so we need to - // generate an extra node that just propagates the value of the - // subexpression. - - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); - } - - return; - } - - case UO_LNot: - case UO_Minus: - case UO_Not: { - assert (!U->isLValue()); - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - - // Get the value of the subexpression. - SVal V = state->getSVal(Ex); - - if (V.isUnknownOrUndef()) { - MakeNode(Dst, U, *I, state->BindExpr(U, V)); - continue; - } - -// QualType DstT = getContext().getCanonicalType(U->getType()); -// QualType SrcT = getContext().getCanonicalType(Ex->getType()); -// -// if (DstT != SrcT) // Perform promotions. -// V = evalCast(V, DstT); -// -// if (V.isUnknownOrUndef()) { -// MakeNode(Dst, U, *I, BindExpr(St, U, V)); -// continue; -// } - - switch (U->getOpcode()) { - default: - assert(false && "Invalid Opcode."); - break; - - case UO_Not: - // FIXME: Do we need to handle promotions? - state = state->BindExpr(U, evalComplement(cast<NonLoc>(V))); - break; - - case UO_Minus: - // FIXME: Do we need to handle promotions? - state = state->BindExpr(U, evalMinus(cast<NonLoc>(V))); - break; - - case UO_LNot: - - // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." - // - // Note: technically we do "E == 0", but this is the same in the - // transfer functions as "0 == E". - SVal Result; - - if (isa<Loc>(V)) { - Loc X = svalBuilder.makeNull(); - Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X, - U->getType()); - } - else { - nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); - Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X, - U->getType()); - } - - state = state->BindExpr(U, Result); - - break; - } - - MakeNode(Dst, U, *I, state); - } - - return; - } - } - - // Handle ++ and -- (both pre- and post-increment). - assert (U->isIncrementDecrementOp()); - ExplodedNodeSet Tmp; - const Expr* Ex = U->getSubExpr()->IgnoreParens(); - Visit(Ex, Pred, Tmp); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { - - const GRState* state = GetState(*I); - SVal loc = state->getSVal(Ex); - - // Perform a load. - ExplodedNodeSet Tmp2; - evalLoad(Tmp2, Ex, *I, state, loc); - - for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { - - state = GetState(*I2); - SVal V2_untested = state->getSVal(Ex); - - // Propagate unknown and undefined values. - if (V2_untested.isUnknownOrUndef()) { - MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); - continue; - } - DefinedSVal V2 = cast<DefinedSVal>(V2_untested); - - // Handle all other values. - BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add - : BO_Sub; - - // If the UnaryOperator has non-location type, use its type to create the - // constant value. If the UnaryOperator has location type, create the - // constant with int type and pointer width. - SVal RHS; - - if (U->getType()->isAnyPointerType()) - RHS = svalBuilder.makeArrayIndex(1); - else - RHS = svalBuilder.makeIntVal(1, U->getType()); - - SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); - - // Conjure a new symbol if necessary to recover precision. - if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ - DefinedOrUnknownSVal SymVal = - svalBuilder.getConjuredSymbolVal(NULL, Ex, - Builder->getCurrentBlockCount()); - Result = SymVal; - - // If the value is a location, ++/-- should always preserve - // non-nullness. Check if the original value was non-null, and if so - // propagate that constraint. - if (Loc::isLocType(U->getType())) { - DefinedOrUnknownSVal Constraint = - svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType())); - - if (!state->assume(Constraint, true)) { - // It isn't feasible for the original value to be null. - // Propagate this constraint. - Constraint = svalBuilder.evalEQ(state, SymVal, - svalBuilder.makeZeroVal(U->getType())); - - - state = state->assume(Constraint, false); - assert(state); - } - } - } - - // Since the lvalue-to-rvalue conversion is explicit in the AST, - // we bind an l-value if the operator is prefix and an lvalue (in C++). - if (U->isLValue()) - state = state->BindExpr(U, loc); - else - state = state->BindExpr(U, U->isPostfix() ? V2 : Result); - - // Perform the store. - evalStore(Dst, NULL, U, *I2, state, loc, Result); - } - } -} - -void ExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { +void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); } -void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A, +void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt *A, AsmStmt::const_outputs_iterator I, AsmStmt::const_outputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (I == E) { VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); return; @@ -2795,11 +1590,11 @@ void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A, VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); } -void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, +void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A, AsmStmt::const_inputs_iterator I, AsmStmt::const_inputs_iterator E, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { if (I == E) { // We have processed both the inputs and the outputs. All of the outputs @@ -2809,7 +1604,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, // which interprets the inline asm and stores proper results in the // outputs. - const GRState* state = GetState(Pred); + const ProgramState *state = Pred->getState(); for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(), OE = A->end_outputs(); OI != OE; ++OI) { @@ -2834,198 +1629,6 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); } -void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Src; - if (const Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. It will be used in - // processCallExit to bind the return value to the call expr. - { - static int tag = 0; - const GRState *state = GetState(Pred); - state = state->set<ReturnExpr>(RetE); - Pred = Builder->generateNode(RetE, state, Pred, &tag); - } - // We may get a NULL Pred because we generated a cached node. - if (Pred) - Visit(RetE, Pred, Src); - } - else { - Src.Add(Pred); - } - - ExplodedNodeSet CheckedSet; - getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this); - - for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); - I != E; ++I) { - - assert(Builder && "StmtNodeBuilder must be defined."); - - Pred = *I; - unsigned size = Dst.size(); - - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->hasGeneratedNode); - - getTF().evalReturn(Dst, *this, *Builder, RS, Pred); - - // Handle the case where no nodes where generated. - if (!Builder->BuildSinks && Dst.size() == size && - !Builder->hasGeneratedNode) - MakeNode(Dst, RS, Pred, GetState(Pred)); - } -} - -//===----------------------------------------------------------------------===// -// Transfer functions: Binary operators. -//===----------------------------------------------------------------------===// - -void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, - ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - ExplodedNodeSet Tmp1; - Expr* LHS = B->getLHS()->IgnoreParens(); - Expr* RHS = B->getRHS()->IgnoreParens(); - - Visit(LHS, Pred, Tmp1); - ExplodedNodeSet Tmp3; - - for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { - SVal LeftV = GetState(*I1)->getSVal(LHS); - ExplodedNodeSet Tmp2; - Visit(RHS, *I1, Tmp2); - - ExplodedNodeSet CheckedSet; - getCheckerManager().runCheckersForPreStmt(CheckedSet, Tmp2, B, *this); - - // With both the LHS and RHS evaluated, process the operation itself. - - for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end(); - I2 != E2; ++I2) { - - const GRState *state = GetState(*I2); - SVal RightV = state->getSVal(RHS); - - BinaryOperator::Opcode Op = B->getOpcode(); - - if (Op == BO_Assign) { - // EXPERIMENTAL: "Conjured" symbols. - // FIXME: Handle structs. - if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV)) - { - unsigned Count = Builder->getCurrentBlockCount(); - RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count); - } - - SVal ExprVal = B->isLValue() ? LeftV : RightV; - - // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV); - continue; - } - - if (!B->isAssignmentOp()) { - // Process non-assignments except commas or short-circuited - // logical expressions (LAnd and LOr). - SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); - - if (Result.isUnknown()) { - MakeNode(Tmp3, B, *I2, state); - continue; - } - - state = state->BindExpr(B, Result); - - MakeNode(Tmp3, B, *I2, state); - continue; - } - - assert (B->isCompoundAssignmentOp()); - - switch (Op) { - default: - assert(0 && "Invalid opcode for compound assignment."); - case BO_MulAssign: Op = BO_Mul; break; - case BO_DivAssign: Op = BO_Div; break; - case BO_RemAssign: Op = BO_Rem; break; - case BO_AddAssign: Op = BO_Add; break; - case BO_SubAssign: Op = BO_Sub; break; - case BO_ShlAssign: Op = BO_Shl; break; - case BO_ShrAssign: Op = BO_Shr; break; - case BO_AndAssign: Op = BO_And; break; - case BO_XorAssign: Op = BO_Xor; break; - case BO_OrAssign: Op = BO_Or; break; - } - - // Perform a load (the LHS). This performs the checks for - // null dereferences, and so on. - ExplodedNodeSet Tmp4; - SVal location = state->getSVal(LHS); - evalLoad(Tmp4, LHS, *I2, state, location); - - for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4; - ++I4) { - state = GetState(*I4); - SVal V = state->getSVal(LHS); - - // Get the computation type. - QualType CTy = - cast<CompoundAssignOperator>(B)->getComputationResultType(); - CTy = getContext().getCanonicalType(CTy); - - QualType CLHSTy = - cast<CompoundAssignOperator>(B)->getComputationLHSType(); - CLHSTy = getContext().getCanonicalType(CLHSTy); - - QualType LTy = getContext().getCanonicalType(LHS->getType()); - - // Promote LHS. - V = svalBuilder.evalCast(V, CLHSTy, LTy); - - // Compute the result of the operation. - SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy), - B->getType(), CTy); - - // EXPERIMENTAL: "Conjured" symbols. - // FIXME: Handle structs. - - SVal LHSVal; - - if (Result.isUnknown() || - !getConstraintManager().canReasonAbout(Result)) { - - unsigned Count = Builder->getCurrentBlockCount(); - - // The symbolic value is actually for the type of the left-hand side - // expression, not the computation type, as this is the value the - // LValue on the LHS will bind to. - LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count); - - // However, we need to convert the symbol to the computation type. - Result = svalBuilder.evalCast(LHSVal, CTy, LTy); - } - else { - // The left-hand side may bind to a different value then the - // computation type. - LHSVal = svalBuilder.evalCast(Result, LTy, CTy); - } - - // In C++, assignment and compound assignment operators return an - // lvalue. - if (B->isLValue()) - state = state->BindExpr(B, location); - else - state = state->BindExpr(B, Result); - - evalStore(Tmp3, B, LHS, *I4, state, location, LHSVal); - } - } - } - - getCheckerManager().runCheckersForPostStmt(Dst, Tmp3, B, *this); -} //===----------------------------------------------------------------------===// // Visualization. @@ -3044,7 +1647,7 @@ struct DOTGraphTraits<ExplodedNode*> : // FIXME: Since we do not cache error nodes in ExprEngine now, this does not // work. - static std::string getNodeAttributes(const ExplodedNode* N, void*) { + static std::string getNodeAttributes(const ExplodedNode *N, void*) { #if 0 // FIXME: Replace with a general scheme to tell if the node is @@ -3065,7 +1668,7 @@ struct DOTGraphTraits<ExplodedNode*> : return ""; } - static std::string getNodeLabel(const ExplodedNode* N, void*){ + static std::string getNodeLabel(const ExplodedNode *N, void*){ std::string sbuf; llvm::raw_string_ostream Out(sbuf); @@ -3093,7 +1696,7 @@ struct DOTGraphTraits<ExplodedNode*> : default: { if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) { - const Stmt* S = L->getStmt(); + const Stmt *S = L->getStmt(); SourceLocation SLoc = S->getLocStart(); Out << S->getStmtClassName() << ' ' << (void*) S << ' '; @@ -3102,9 +1705,9 @@ struct DOTGraphTraits<ExplodedNode*> : if (SLoc.isFileID()) { Out << "\\lline=" - << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) + << GraphPrintSourceManager->getExpansionLineNumber(SLoc) << " col=" - << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc) + << GraphPrintSourceManager->getExpansionColumnNumber(SLoc) << "\\l"; } @@ -3141,11 +1744,11 @@ struct DOTGraphTraits<ExplodedNode*> : break; } - const BlockEdge& E = cast<BlockEdge>(Loc); + const BlockEdge &E = cast<BlockEdge>(Loc); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; - if (const Stmt* T = E.getSrc()->getTerminator()) { + if (const Stmt *T = E.getSrc()->getTerminator()) { SourceLocation SLoc = T->getLocStart(); @@ -3155,21 +1758,21 @@ struct DOTGraphTraits<ExplodedNode*> : if (SLoc.isFileID()) { Out << "\\lline=" - << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) + << GraphPrintSourceManager->getExpansionLineNumber(SLoc) << " col=" - << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc); + << GraphPrintSourceManager->getExpansionColumnNumber(SLoc); } if (isa<SwitchStmt>(T)) { - const Stmt* Label = E.getDst()->getLabel(); + const Stmt *Label = E.getDst()->getLabel(); if (Label) { - if (const CaseStmt* C = dyn_cast<CaseStmt>(Label)) { + if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); - if (const Stmt* RHS = C->getRHS()) { + if (const Stmt *RHS = C->getRHS()) { Out << " .. "; RHS->printPretty(Out, 0, PrintingPolicy(LO)); } @@ -3208,11 +1811,17 @@ struct DOTGraphTraits<ExplodedNode*> : } } - const GRState *state = N->getState(); + const ProgramState *state = N->getState(); Out << "\\|StateID: " << (void*) state << " NodeID: " << (void*) N << "\\|"; state->printDOT(Out, *N->getLocationContext()->getCFG()); - Out << "\\l"; + + Out << "\\l"; + + if (const ProgramPointTag *tag = Loc.getTag()) { + Out << "\\|Tag: " << tag->getTagDescription(); + Out << "\\l"; + } return Out.str(); } }; @@ -3221,7 +1830,7 @@ struct DOTGraphTraits<ExplodedNode*> : #ifndef NDEBUG template <typename ITERATOR> -ExplodedNode* GetGraphNode(ITERATOR I) { return *I; } +ExplodedNode *GetGraphNode(ITERATOR I) { return *I; } template <> ExplodedNode* GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator> diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp new file mode 100644 index 0000000..68ccc59 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -0,0 +1,752 @@ +//=-- ExprEngineC.cpp - ExprEngine support for C expressions ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ExprEngine's support for C expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/Analysis/Support/SaveAndRestore.h" + +using namespace clang; +using namespace ento; +using llvm::APSInt; + +void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + Expr *LHS = B->getLHS()->IgnoreParens(); + Expr *RHS = B->getRHS()->IgnoreParens(); + + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + ExplodedNodeSet Tmp2; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this); + + // With both the LHS and RHS evaluated, process the operation itself. + for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end(); + it != ei; ++it) { + + const ProgramState *state = (*it)->getState(); + SVal LeftV = state->getSVal(LHS); + SVal RightV = state->getSVal(RHS); + + BinaryOperator::Opcode Op = B->getOpcode(); + + if (Op == BO_Assign) { + // EXPERIMENTAL: "Conjured" symbols. + // FIXME: Handle structs. + if (RightV.isUnknown() || + !getConstraintManager().canReasonAbout(RightV)) { + unsigned Count = Builder->getCurrentBlockCount(); + RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count); + } + // Simulate the effects of a "store": bind the value of the RHS + // to the L-Value represented by the LHS. + SVal ExprVal = B->isLValue() ? LeftV : RightV; + evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, ExprVal), LeftV, RightV); + continue; + } + + if (!B->isAssignmentOp()) { + // Process non-assignments except commas or short-circuited + // logical expressions (LAnd and LOr). + SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); + if (Result.isUnknown()) { + MakeNode(Tmp2, B, *it, state); + continue; + } + + state = state->BindExpr(B, Result); + MakeNode(Tmp2, B, *it, state); + continue; + } + + assert (B->isCompoundAssignmentOp()); + + switch (Op) { + default: + llvm_unreachable("Invalid opcode for compound assignment."); + case BO_MulAssign: Op = BO_Mul; break; + case BO_DivAssign: Op = BO_Div; break; + case BO_RemAssign: Op = BO_Rem; break; + case BO_AddAssign: Op = BO_Add; break; + case BO_SubAssign: Op = BO_Sub; break; + case BO_ShlAssign: Op = BO_Shl; break; + case BO_ShrAssign: Op = BO_Shr; break; + case BO_AndAssign: Op = BO_And; break; + case BO_XorAssign: Op = BO_Xor; break; + case BO_OrAssign: Op = BO_Or; break; + } + + // Perform a load (the LHS). This performs the checks for + // null dereferences, and so on. + ExplodedNodeSet Tmp; + SVal location = LeftV; + evalLoad(Tmp, LHS, *it, state, location); + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; + ++I) { + + state = (*I)->getState(); + SVal V = state->getSVal(LHS); + + // Get the computation type. + QualType CTy = + cast<CompoundAssignOperator>(B)->getComputationResultType(); + CTy = getContext().getCanonicalType(CTy); + + QualType CLHSTy = + cast<CompoundAssignOperator>(B)->getComputationLHSType(); + CLHSTy = getContext().getCanonicalType(CLHSTy); + + QualType LTy = getContext().getCanonicalType(LHS->getType()); + + // Promote LHS. + V = svalBuilder.evalCast(V, CLHSTy, LTy); + + // Compute the result of the operation. + SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy), + B->getType(), CTy); + + // EXPERIMENTAL: "Conjured" symbols. + // FIXME: Handle structs. + + SVal LHSVal; + + if (Result.isUnknown() || + !getConstraintManager().canReasonAbout(Result)) { + + unsigned Count = Builder->getCurrentBlockCount(); + + // The symbolic value is actually for the type of the left-hand side + // expression, not the computation type, as this is the value the + // LValue on the LHS will bind to. + LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, + Count); + + // However, we need to convert the symbol to the computation type. + Result = svalBuilder.evalCast(LHSVal, CTy, LTy); + } + else { + // The left-hand side may bind to a different value then the + // computation type. + LHSVal = svalBuilder.evalCast(Result, LTy, CTy); + } + + // In C++, assignment and compound assignment operators return an + // lvalue. + if (B->isLValue()) + state = state->BindExpr(B, location); + else + state = state->BindExpr(B, Result); + + evalStore(Tmp2, B, LHS, *I, state, location, LHSVal); + } + } + + // FIXME: postvisits eventually go in ::Visit() + getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this); +} + +void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + CanQualType T = getContext().getCanonicalType(BE->getType()); + SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, + Pred->getLocationContext()); + + ExplodedNodeSet Tmp; + MakeNode(Tmp, BE, Pred, Pred->getState()->BindExpr(BE, V), + ProgramPoint::PostLValueKind); + + // FIXME: Move all post/pre visits to ::Visit(). + getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); +} + +void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + + ExplodedNodeSet dstPreStmt; + getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); + + if (CastE->getCastKind() == CK_LValueToRValue || + CastE->getCastKind() == CK_GetObjCProperty) { + for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); + I!=E; ++I) { + ExplodedNode *subExprNode = *I; + const ProgramState *state = subExprNode->getState(); + evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex)); + } + return; + } + + // All other casts. + QualType T = CastE->getType(); + QualType ExTy = Ex->getType(); + + if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) + T = ExCast->getTypeAsWritten(); + + for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); + I != E; ++I) { + + Pred = *I; + + switch (CastE->getCastKind()) { + case CK_LValueToRValue: + llvm_unreachable("LValueToRValue casts handled earlier."); + case CK_GetObjCProperty: + llvm_unreachable("GetObjCProperty casts handled earlier."); + case CK_ToVoid: + Dst.Add(Pred); + continue; + // The analyzer doesn't do anything special with these casts, + // since it understands retain/release semantics already. + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: // Fall-through. + // True no-ops. + case CK_NoOp: + case CK_FunctionToPointerDecay: { + // Copy the SVal of Ex to CastE. + const ProgramState *state = Pred->getState(); + SVal V = state->getSVal(Ex); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, Pred, state); + continue; + } + case CK_Dependent: + case CK_ArrayToPointerDecay: + case CK_BitCast: + case CK_LValueBitCast: + case CK_IntegralCast: + case CK_NullToPointer: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: { + // Delegate to SValBuilder to process. + const ProgramState *state = Pred->getState(); + SVal V = state->getSVal(Ex); + V = svalBuilder.evalCast(V, T, ExTy); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, Pred, state); + continue; + } + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: { + // For DerivedToBase cast, delegate to the store manager. + const ProgramState *state = Pred->getState(); + SVal val = state->getSVal(Ex); + val = getStoreManager().evalDerivedToBase(val, T); + state = state->BindExpr(CastE, val); + MakeNode(Dst, CastE, Pred, state); + continue; + } + // Various C++ casts that are not handled yet. + case CK_Dynamic: + case CK_ToUnion: + case CK_BaseToDerived: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_VectorSplat: + case CK_MemberPointerToBoolean: { + // Recover some path-sensitivty by conjuring a new value. + QualType resultType = CastE->getType(); + if (CastE->isLValue()) + resultType = getContext().getPointerType(resultType); + + SVal result = + svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, + Builder->getCurrentBlockCount()); + + const ProgramState *state = Pred->getState()->BindExpr(CastE, result); + MakeNode(Dst, CastE, Pred, state); + continue; + } + } + } +} + +void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + const InitListExpr *ILE + = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); + + const ProgramState *state = Pred->getState(); + SVal ILV = state->getSVal(ILE); + const LocationContext *LC = Pred->getLocationContext(); + state = state->bindCompoundLiteral(CL, LC, ILV); + + if (CL->isLValue()) + MakeNode(Dst, CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC))); + else + MakeNode(Dst, CL, Pred, state->BindExpr(CL, ILV)); +} + +void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + // FIXME: static variables may have an initializer, but the second + // time a function is called those values may not be current. + // This may need to be reflected in the CFG. + + // Assumption: The CFG has one DeclStmt per Decl. + const Decl *D = *DS->decl_begin(); + + if (!D || !isa<VarDecl>(D)) + return; + + // FIXME: all pre/post visits should eventually be handled by ::Visit(). + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); + + const VarDecl *VD = dyn_cast<VarDecl>(D); + + for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); + I!=E; ++I) { + ExplodedNode *N = *I; + const ProgramState *state = N->getState(); + + // Decls without InitExpr are not initialized explicitly. + const LocationContext *LC = N->getLocationContext(); + + if (const Expr *InitEx = VD->getInit()) { + SVal InitVal = state->getSVal(InitEx); + + // We bound the temp obj region to the CXXConstructExpr. Now recover + // the lazy compound value when the variable is not a reference. + if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && + !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){ + InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion()); + assert(isa<nonloc::LazyCompoundVal>(InitVal)); + } + + // Recover some path-sensitivity if a scalar value evaluated to + // UnknownVal. + if ((InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) && + !VD->getType()->isReferenceType()) { + InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); + } + + evalBind(Dst, DS, N, state->getLValue(VD, LC), InitVal, true); + } + else { + MakeNode(Dst, DS, N, state->bindDeclWithNoInit(state->getRegion(VD, LC))); + } + } +} + +void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + assert(B->getOpcode() == BO_LAnd || + B->getOpcode() == BO_LOr); + + const ProgramState *state = Pred->getState(); + SVal X = state->getSVal(B); + assert(X.isUndef()); + + const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData(); + assert(Ex); + + if (Ex == B->getRHS()) { + X = state->getSVal(Ex); + + // Handle undefined values. + if (X.isUndef()) { + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); + return; + } + + DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X); + + // We took the RHS. Because the value of the '&&' or '||' expression must + // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 + // or 1. Alternatively, we could take a lazy approach, and calculate this + // value later when necessary. We don't have the machinery in place for + // this right now, and since most logical expressions are used for branches, + // the payoff is not likely to be large. Instead, we do eager evaluation. + if (const ProgramState *newState = state->assume(XD, true)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType()))); + + if (const ProgramState *newState = state->assume(XD, false)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType()))); + } + else { + // We took the LHS expression. Depending on whether we are '&&' or + // '||' we know what the value of the expression is via properties of + // the short-circuiting. + X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U, + B->getType()); + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); + } +} + +void ExprEngine::VisitInitListExpr(const InitListExpr *IE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + const ProgramState *state = Pred->getState(); + QualType T = getContext().getCanonicalType(IE->getType()); + unsigned NumInitElements = IE->getNumInits(); + + if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { + llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList(); + + // Handle base case where the initializer has no elements. + // e.g: static int* myArray[] = {}; + if (NumInitElements == 0) { + SVal V = svalBuilder.makeCompoundVal(T, vals); + MakeNode(Dst, IE, Pred, state->BindExpr(IE, V)); + return; + } + + for (InitListExpr::const_reverse_iterator it = IE->rbegin(), + ei = IE->rend(); it != ei; ++it) { + vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it)), vals); + } + + MakeNode(Dst, IE, Pred, + state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals))); + return; + } + + if (Loc::isLocType(T) || T->isIntegerType()) { + assert(IE->getNumInits() == 1); + const Expr *initEx = IE->getInit(0); + MakeNode(Dst, IE, Pred, state->BindExpr(IE, state->getSVal(initEx))); + return; + } + + llvm_unreachable("unprocessed InitListExpr type"); +} + +void ExprEngine::VisitGuardedExpr(const Expr *Ex, + const Expr *L, + const Expr *R, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + const ProgramState *state = Pred->getState(); + SVal X = state->getSVal(Ex); + assert (X.isUndef()); + const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData(); + assert(SE); + X = state->getSVal(SE); + + // Make sure that we invalidate the previous binding. + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); +} + +void ExprEngine:: +VisitOffsetOfExpr(const OffsetOfExpr *OOE, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + Expr::EvalResult Res; + if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); + assert(OOE->getType()->isIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); + SVal X = svalBuilder.makeIntVal(IV); + MakeNode(Dst, OOE, Pred, Pred->getState()->BindExpr(OOE, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.Add(Pred); +} + + +void ExprEngine:: +VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + QualType T = Ex->getTypeOfArgument(); + + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { + assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); + + // FIXME: Add support for VLA type arguments and VLA expressions. + // When that happens, we should probably refactor VLASizeChecker's code. + Dst.Add(Pred); + return; + } + else if (T->getAs<ObjCObjectType>()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that + // the compiler has laid out its representation. Just report Unknown + // for these. + Dst.Add(Pred); + return; + } + } + + Expr::EvalResult Result; + Ex->Evaluate(Result, getContext()); + CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue()); + + const ProgramState *state = Pred->getState(); + state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(), + Ex->getType())); + MakeNode(Dst, Ex, Pred, state); +} + +void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + switch (U->getOpcode()) { + default: + break; + case UO_Real: { + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + // FIXME: We don't have complex SValues yet. + if (Ex->getType()->isAnyComplexType()) { + // Just report "Unknown." + Dst.Add(*I); + continue; + } + + // For all other types, UO_Real is an identity operation. + assert (U->getType() == Ex->getType()); + const ProgramState *state = (*I)->getState(); + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); + } + + return; + } + + case UO_Imag: { + + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + // FIXME: We don't have complex SValues yet. + if (Ex->getType()->isAnyComplexType()) { + // Just report "Unknown." + Dst.Add(*I); + continue; + } + + // For all other types, UO_Imag returns 0. + const ProgramState *state = (*I)->getState(); + SVal X = svalBuilder.makeZeroVal(Ex->getType()); + MakeNode(Dst, U, *I, state->BindExpr(U, X)); + } + + return; + } + + case UO_Plus: + assert(!U->isLValue()); + // FALL-THROUGH. + case UO_Deref: + case UO_AddrOf: + case UO_Extension: { + + // Unary "+" is a no-op, similar to a parentheses. We still have places + // where it may be a block-level expression, so we need to + // generate an extra node that just propagates the value of the + // subexpression. + + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const ProgramState *state = (*I)->getState(); + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); + } + + return; + } + + case UO_LNot: + case UO_Minus: + case UO_Not: { + assert (!U->isLValue()); + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const ProgramState *state = (*I)->getState(); + + // Get the value of the subexpression. + SVal V = state->getSVal(Ex); + + if (V.isUnknownOrUndef()) { + MakeNode(Dst, U, *I, state->BindExpr(U, V)); + continue; + } + + switch (U->getOpcode()) { + default: + llvm_unreachable("Invalid Opcode."); + + case UO_Not: + // FIXME: Do we need to handle promotions? + state = state->BindExpr(U, evalComplement(cast<NonLoc>(V))); + break; + + case UO_Minus: + // FIXME: Do we need to handle promotions? + state = state->BindExpr(U, evalMinus(cast<NonLoc>(V))); + break; + + case UO_LNot: + + // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." + // + // Note: technically we do "E == 0", but this is the same in the + // transfer functions as "0 == E". + SVal Result; + + if (isa<Loc>(V)) { + Loc X = svalBuilder.makeNull(); + Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X, + U->getType()); + } + else { + nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); + Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X, + U->getType()); + } + + state = state->BindExpr(U, Result); + + break; + } + + MakeNode(Dst, U, *I, state); + } + + return; + } + } + + // Handle ++ and -- (both pre- and post-increment). + assert (U->isIncrementDecrementOp()); + ExplodedNodeSet Tmp; + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + Visit(Ex, Pred, Tmp); + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { + + const ProgramState *state = (*I)->getState(); + SVal loc = state->getSVal(Ex); + + // Perform a load. + ExplodedNodeSet Tmp2; + evalLoad(Tmp2, Ex, *I, state, loc); + + for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { + + state = (*I2)->getState(); + SVal V2_untested = state->getSVal(Ex); + + // Propagate unknown and undefined values. + if (V2_untested.isUnknownOrUndef()) { + MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); + continue; + } + DefinedSVal V2 = cast<DefinedSVal>(V2_untested); + + // Handle all other values. + BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add + : BO_Sub; + + // If the UnaryOperator has non-location type, use its type to create the + // constant value. If the UnaryOperator has location type, create the + // constant with int type and pointer width. + SVal RHS; + + if (U->getType()->isAnyPointerType()) + RHS = svalBuilder.makeArrayIndex(1); + else + RHS = svalBuilder.makeIntVal(1, U->getType()); + + SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); + + // Conjure a new symbol if necessary to recover precision. + if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ + DefinedOrUnknownSVal SymVal = + svalBuilder.getConjuredSymbolVal(NULL, Ex, + Builder->getCurrentBlockCount()); + Result = SymVal; + + // If the value is a location, ++/-- should always preserve + // non-nullness. Check if the original value was non-null, and if so + // propagate that constraint. + if (Loc::isLocType(U->getType())) { + DefinedOrUnknownSVal Constraint = + svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType())); + + if (!state->assume(Constraint, true)) { + // It isn't feasible for the original value to be null. + // Propagate this constraint. + Constraint = svalBuilder.evalEQ(state, SymVal, + svalBuilder.makeZeroVal(U->getType())); + + + state = state->assume(Constraint, false); + assert(state); + } + } + } + + // Since the lvalue-to-rvalue conversion is explicit in the AST, + // we bind an l-value if the operator is prefix and an lvalue (in C++). + if (U->isLValue()) + state = state->BindExpr(U, loc); + else + state = state->BindExpr(U, U->isPostfix() ? V2 : Result); + + // Perform the store. + evalStore(Dst, NULL, U, *I2, state, loc, Result); + } + } +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index ef7bc20..acb0074 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1,4 +1,4 @@ -//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===// +//===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" #include "clang/AST/DeclCXX.h" using namespace clang; @@ -36,7 +37,7 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, bool FstArgAsLValue) { - llvm::SmallVector<CallExprWLItem, 20> WorkList; + SmallVector<CallExprWLItem, 20> WorkList; WorkList.reserve(AE - AI); WorkList.push_back(CallExprWLItem(AI, Pred)); @@ -103,24 +104,22 @@ const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, getCXXThisRegion(decl->getThisType(getContext()), frameCtx); } -void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - const GRState *state = GetState(*I); +void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); + const ProgramState *state = Pred->getState(); - // Bind the temporary object to the value of the expression. Then bind - // the expression to the location of the object. - SVal V = state->getSVal(Ex); + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(tempExpr); - const MemRegion *R = - svalBuilder.getRegionManager().getCXXTempObjectRegion(Ex, - Pred->getLocationContext()); + const MemRegion *R = + svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, + Pred->getLocationContext()); - state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R))); } void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, @@ -186,7 +185,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), NE = argsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); + const ProgramState *state = (*NI)->getState(); // Setup 'this' region, so that the ctor is evaluated on the object pointed // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); @@ -197,17 +196,6 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, #endif // Default semantics: invalidate all regions passed as arguments. - llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate; - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned blockCount = Builder->getCurrentBlockCount(); - - // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate - // global variables. ExplodedNodeSet destCall; for (ExplodedNodeSet::iterator @@ -215,25 +203,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, i != e; ++i) { ExplodedNode *Pred = *i; - const GRState *state = GetState(Pred); + const LocationContext *LC = Pred->getLocationContext(); + const ProgramState *state = Pred->getState(); - // Accumulate list of regions that are invalidated. - for (CXXConstructExpr::const_arg_iterator - ai = E->arg_begin(), ae = E->arg_end(); - ai != ae; ++ai) - { - SVal val = state->getSVal(*ai); - if (const MemRegion *region = val.getAsRegion()) - regionsToInvalidate.push_back(region); - } - - // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), - E, blockCount, 0, - /* invalidateGlobals = */ true); - + state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); Builder->MakeNode(destCall, E, Pred, state); } @@ -258,7 +231,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, CallEnter PP(S, SFC, Pred->getLocationContext()); - const GRState *state = Pred->getState(); + const ProgramState *state = Pred->getState(); state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); ExplodedNode *N = Builder->generateNode(PP, state, Pred); if (N) @@ -279,7 +252,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); MakeNode(Dst, CNE, Pred, state); return; @@ -298,12 +271,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), E = argsEvaluated.end(); I != E; ++I) { - const GRState *state = GetState(*I); + const ProgramState *state = (*I)->getState(); // Accumulate list of regions that are invalidated. // FIXME: Eventually we should unify the logic for constructor // processing in one place. - llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate; + SmallVector<const MemRegion*, 10> regionsToInvalidate; for (CXXNewExpr::const_arg_iterator ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); ai != ae; ++ai) @@ -316,17 +289,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (ObjTy->isRecordType()) { regionsToInvalidate.push_back(EleReg); // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), + state = state->invalidateRegions(regionsToInvalidate, CNE, blockCount, 0, /* invalidateGlobals = */ true); } else { // Invalidate the regions. - state = state->invalidateRegions(regionsToInvalidate.data(), - regionsToInvalidate.data() + - regionsToInvalidate.size(), + state = state->invalidateRegions(regionsToInvalidate, CNE, blockCount, 0, /* invalidateGlobals = */ true); @@ -351,7 +320,7 @@ void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, Visit(CDE->getArgument(), Pred, Argevaluated); for (ExplodedNodeSet::iterator I = Argevaluated.begin(), E = Argevaluated.end(); I != E; ++I) { - const GRState *state = GetState(*I); + const ProgramState *state = (*I)->getState(); MakeNode(Dst, CDE, *I, state); } } @@ -364,7 +333,7 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, getContext().getCanonicalType(TE->getType()), Pred->getLocationContext()); - const GRState *state = GetState(Pred); + const ProgramState *state = Pred->getState(); SVal V = state->getSVal(loc::MemRegionVal(R)); MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp new file mode 100644 index 0000000..6d377b9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -0,0 +1,253 @@ +//=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ExprEngine's support for calls and returns. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Analysis/Support/SaveAndRestore.h" + +using namespace clang; +using namespace ento; + +namespace { + // Trait class for recording returned expression in the state. + struct ReturnExpr { + static int TagInt; + typedef const Stmt *data_type; + }; + int ReturnExpr::TagInt; +} + +void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) { + const ProgramState *state = + B.getState()->enterStackFrame(B.getCalleeContext()); + B.generateNode(state); +} + +void ExprEngine::processCallExit(CallExitNodeBuilder &B) { + const ProgramState *state = B.getState(); + const ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *calleeCtx = + cast<StackFrameContext>(Pred->getLocationContext()); + const Stmt *CE = calleeCtx->getCallSite(); + + // If the callee returns an expression, bind its value to CallExpr. + const Stmt *ReturnedExpr = state->get<ReturnExpr>(); + if (ReturnedExpr) { + SVal RetVal = state->getSVal(ReturnedExpr); + state = state->BindExpr(CE, RetVal); + // Clear the return expr GDM. + state = state->remove<ReturnExpr>(); + } + + // Bind the constructed object value to CXXConstructExpr. + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { + const CXXThisRegion *ThisR = + getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); + + SVal ThisV = state->getSVal(ThisR); + // Always bind the region to the CXXConstructExpr. + state = state->BindExpr(CCE, ThisV); + } + + B.generateNode(state); +} + +const ProgramState * +ExprEngine::invalidateArguments(const ProgramState *State, + const CallOrObjCMessage &Call, + const LocationContext *LC) { + SmallVector<const MemRegion *, 8> RegionsToInvalidate; + + if (Call.isObjCMessage()) { + // Invalidate all instance variables of the receiver of an ObjC message. + // FIXME: We should be able to do better with inter-procedural analysis. + if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion()) + RegionsToInvalidate.push_back(MR); + + } else if (Call.isCXXCall()) { + // Invalidate all instance variables for the callee of a C++ method call. + // FIXME: We should be able to do better with inter-procedural analysis. + // FIXME: We can probably do better for const versus non-const methods. + if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion()) + RegionsToInvalidate.push_back(Callee); + + } else if (Call.isFunctionCall()) { + // Block calls invalidate all captured-by-reference values. + if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) { + if (isa<BlockDataRegion>(Callee)) + RegionsToInvalidate.push_back(Callee); + } + } + + for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { + SVal V = Call.getArgSVal(idx); + + // If we are passing a location wrapped as an integer, unwrap it and + // invalidate the values referred by the location. + if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V)) + V = Wrapped->getLoc(); + else if (!isa<Loc>(V)) + continue; + + if (const MemRegion *R = V.getAsRegion()) { + // Invalidate the value of the variable passed by reference. + + // Are we dealing with an ElementRegion? If the element type is + // a basic integer type (e.g., char, int) and the underying region + // is a variable region then strip off the ElementRegion. + // FIXME: We really need to think about this for the general case + // as sometimes we are reasoning about arrays and other times + // about (char*), etc., is just a form of passing raw bytes. + // e.g., void *p = alloca(); foo((char*)p); + if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { + // Checking for 'integral type' is probably too promiscuous, but + // we'll leave it in for now until we have a systematic way of + // handling all of these cases. Eventually we need to come up + // with an interface to StoreManager so that this logic can be + // approriately delegated to the respective StoreManagers while + // still allowing us to do checker-specific logic (e.g., + // invalidating reference counts), probably via callbacks. + if (ER->getElementType()->isIntegralOrEnumerationType()) { + const MemRegion *superReg = ER->getSuperRegion(); + if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || + isa<ObjCIvarRegion>(superReg)) + R = cast<TypedRegion>(superReg); + } + // FIXME: What about layers of ElementRegions? + } + + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. + RegionsToInvalidate.push_back(R); + } else { + // Nuke all other arguments passed by reference. + // FIXME: is this necessary or correct? This handles the non-Region + // cases. Is it ever valid to store to these? + State = State->unbindLoc(cast<Loc>(V)); + } + } + + // Invalidate designated regions using the batch invalidation API. + + // FIXME: We can have collisions on the conjured symbol if the + // expression *I also creates conjured symbols. We probably want + // to identify conjured symbols by an expression pair: the enclosing + // expression (the context) and the expression itself. This should + // disambiguate conjured symbols. + assert(Builder && "Invalidating arguments outside of a statement context"); + unsigned Count = Builder->getCurrentBlockCount(); + StoreManager::InvalidatedSymbols IS; + + // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate + // global variables. + return State->invalidateRegions(RegionsToInvalidate, + Call.getOriginExpr(), Count, + &IS, doesInvalidateGlobals(Call)); + +} + +void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, + ExplodedNodeSet &dst) { + // Perform the previsit of the CallExpr. + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); + + // Now evaluate the call itself. + class DefaultEval : public GraphExpander { + ExprEngine &Eng; + const CallExpr *CE; + public: + + DefaultEval(ExprEngine &eng, const CallExpr *ce) + : Eng(eng), CE(ce) {} + virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { + // Should we inline the call? + if (Eng.getAnalysisManager().shouldInlineCall() && + Eng.InlineCall(Dst, CE, Pred)) { + return; + } + + // First handle the return value. + StmtNodeBuilder &Builder = Eng.getBuilder(); + assert(&Builder && "StmtNodeBuilder must be defined."); + + // Get the callee. + const Expr *Callee = CE->getCallee()->IgnoreParens(); + const ProgramState *state = Pred->getState(); + SVal L = state->getSVal(Callee); + + // Figure out the result type. We do this dance to handle references. + QualType ResultTy; + if (const FunctionDecl *FD = L.getAsFunctionDecl()) + ResultTy = FD->getResultType(); + else + ResultTy = CE->getType(); + + if (CE->isLValue()) + ResultTy = Eng.getContext().getPointerType(ResultTy); + + // Conjure a symbol value to use as the result. + SValBuilder &SVB = Eng.getSValBuilder(); + unsigned Count = Builder.getCurrentBlockCount(); + SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); + + // Generate a new state with the return value set. + state = state->BindExpr(CE, RetVal); + + // Invalidate the arguments. + const LocationContext *LC = Pred->getLocationContext(); + state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC); + + // And make the result node. + Eng.MakeNode(Dst, CE, Pred, state); + } + }; + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. + ExplodedNodeSet dstCallEvaluated; + DefaultEval defEval(*this, CE); + getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, + dstPreVisit, + CE, *this, &defEval); + + // Finally, perform the post-condition check of the CallExpr and store + // the created nodes in 'Dst'. + getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, + *this); +} + +void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Src; + if (const Expr *RetE = RS->getRetValue()) { + // Record the returned expression in the state. It will be used in + // processCallExit to bind the return value to the call expr. + { + static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); + const ProgramState *state = Pred->getState(); + state = state->set<ReturnExpr>(RetE); + Pred = Builder->generateNode(RetE, state, Pred, &tag); + } + // We may get a NULL Pred because we generated a cached node. + if (Pred) + Visit(RetE, Pred, Src); + } + else { + Src.Add(Pred); + } + + getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp new file mode 100644 index 0000000..e0560fd --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -0,0 +1,279 @@ +//=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ExprEngine's support for Objective-C expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/Analysis/Support/SaveAndRestore.h" + +using namespace clang; +using namespace ento; + +void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + const ProgramState *state = Pred->getState(); + SVal baseVal = state->getSVal(Ex->getBase()); + SVal location = state->getLValue(Ex->getDecl(), baseVal); + + ExplodedNodeSet dstIvar; + MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location)); + + // Perform the post-condition check of the ObjCIvarRefExpr and store + // the created nodes in 'Dst'. + getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); +} + +void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this); +} + +void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + // ObjCForCollectionStmts are processed in two places. This method + // handles the case where an ObjCForCollectionStmt* occurs as one of the + // statements within a basic block. This transfer function does two things: + // + // (1) binds the next container value to 'element'. This creates a new + // node in the ExplodedGraph. + // + // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating + // whether or not the container has any more elements. This value + // will be tested in ProcessBranch. We need to explicitly bind + // this value because a container can contain nil elements. + // + // FIXME: Eventually this logic should actually do dispatches to + // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). + // This will require simulating a temporary NSFastEnumerationState, either + // through an SVal or through the use of MemRegions. This value can + // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop + // terminates we reclaim the temporary (it goes out of scope) and we + // we can test if the SVal is 0 or if the MemRegion is null (depending + // on what approach we take). + // + // For now: simulate (1) by assigning either a symbol or nil if the + // container is empty. Thus this transfer function will by default + // result in state splitting. + + const Stmt *elem = S->getElement(); + const ProgramState *state = Pred->getState(); + SVal elementV; + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { + const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); + assert(elemD->getInit() == 0); + elementV = state->getLValue(elemD, Pred->getLocationContext()); + } + else { + elementV = state->getSVal(elem); + } + + ExplodedNodeSet dstLocation; + evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false); + + if (dstLocation.empty()) + return; + + for (ExplodedNodeSet::iterator NI = dstLocation.begin(), + NE = dstLocation.end(); NI!=NE; ++NI) { + Pred = *NI; + const ProgramState *state = Pred->getState(); + + // Handle the case where the container still has elements. + SVal TrueV = svalBuilder.makeTruthVal(1); + const ProgramState *hasElems = state->BindExpr(S, TrueV); + + // Handle the case where the container has no elements. + SVal FalseV = svalBuilder.makeTruthVal(0); + const ProgramState *noElems = state->BindExpr(S, FalseV); + + if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV)) + if (const TypedValueRegion *R = + dyn_cast<TypedValueRegion>(MV->getRegion())) { + // FIXME: The proper thing to do is to really iterate over the + // container. We will do this with dispatch logic to the store. + // For now, just 'conjure' up a symbolic value. + QualType T = R->getValueType(); + assert(Loc::isLocType(T)); + unsigned Count = Builder->getCurrentBlockCount(); + SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); + SVal V = svalBuilder.makeLoc(Sym); + hasElems = hasElems->bindLoc(elementV, V); + + // Bind the location to 'nil' on the false branch. + SVal nilV = svalBuilder.makeIntVal(0, T); + noElems = noElems->bindLoc(elementV, nilV); + } + + // Create the new nodes. + MakeNode(Dst, S, Pred, hasElems); + MakeNode(Dst, S, Pred, noElems); + } +} + +void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + // Handle the previsits checks. + ExplodedNodeSet dstPrevisit; + getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, + msg, *this); + + // Proceed with evaluate the message expression. + ExplodedNodeSet dstEval; + + for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(), + DE = dstPrevisit.end(); DI != DE; ++DI) { + + ExplodedNode *Pred = *DI; + bool RaisesException = false; + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->hasGeneratedNode); + + if (const Expr *Receiver = msg.getInstanceReceiver()) { + const ProgramState *state = Pred->getState(); + SVal recVal = state->getSVal(Receiver); + if (!recVal.isUndef()) { + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); + + const ProgramState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We ignore must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + dstEval.insert(Pred); + continue; + } + + // Check if the "raise" message was sent. + assert(notNilState); + if (msg.getSelector() == RaiseSel) + RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + evalObjCMessage(dstEval, msg, Pred, notNilState); + } + } + else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { + IdentifierInfo* ClsName = Iface->getIdentifier(); + Selector S = msg.getSelector(); + + // Check for special instance methods. + if (!NSExceptionII) { + ASTContext &Ctx = getContext(); + NSExceptionII = &Ctx.Idents.get("NSException"); + } + + if (ClsName == NSExceptionII) { + enum { NUM_RAISE_SELECTORS = 2 }; + + // Lazily create a cache of the selectors. + if (!NSExceptionInstanceRaiseSelectors) { + ASTContext &Ctx = getContext(); + NSExceptionInstanceRaiseSelectors = + new Selector[NUM_RAISE_SELECTORS]; + SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; + unsigned idx = 0; + + // raise:format: + II.push_back(&Ctx.Idents.get("raise")); + II.push_back(&Ctx.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + + // raise:format::arguments: + II.push_back(&Ctx.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + } + + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) + if (S == NSExceptionInstanceRaiseSelectors[i]) { + RaisesException = true; + break; + } + } + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + evalObjCMessage(dstEval, msg, Pred, Pred->getState()); + } + + assert(Builder->BuildSinks || Builder->hasGeneratedNode); + } + + // Finally, perform the post-condition check of the ObjCMessageExpr and store + // the created nodes in 'Dst'. + getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); +} + +void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, + ExplodedNode *Pred, + const ProgramState *state) { + assert (Builder && "StmtNodeBuilder must be defined."); + + // First handle the return value. + SVal ReturnValue = UnknownVal(); + + // Some method families have known return values. + switch (msg.getMethodFamily()) { + default: + break; + case OMF_autorelease: + case OMF_retain: + case OMF_self: { + // These methods return their receivers. + const Expr *ReceiverE = msg.getInstanceReceiver(); + if (ReceiverE) + ReturnValue = state->getSVal(ReceiverE); + break; + } + } + + // If we failed to figure out the return value, use a conjured value instead. + if (ReturnValue.isUnknown()) { + SValBuilder &SVB = getSValBuilder(); + QualType ResultTy = msg.getResultType(getContext()); + unsigned Count = Builder->getCurrentBlockCount(); + const Expr *CurrentE = cast<Expr>(currentStmt); + ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count); + } + + // Bind the return value. + state = state->BindExpr(currentStmt, ReturnValue); + + // Invalidate the arguments (and the receiver) + const LocationContext *LC = Pred->getLocationContext(); + state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC); + + // And create the new node. + MakeNode(Dst, msg.getOriginExpr(), Pred, state); +} + diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp deleted file mode 100644 index ca867ae..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "llvm/ADT/ImmutableIntervalMap.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace clang; -using namespace ento; -using llvm::Interval; - -// The actual store type. -typedef llvm::ImmutableIntervalMap<SVal> BindingVal; -typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings; - -namespace { -class FlatStoreManager : public StoreManager { - RegionBindings::Factory RBFactory; - BindingVal::Factory BVFactory; - -public: - FlatStoreManager(GRStateManager &mgr) - : StoreManager(mgr), - RBFactory(mgr.getAllocator()), - BVFactory(mgr.getAllocator()) {} - - SVal Retrieve(Store store, Loc L, QualType T); - StoreRef Bind(Store store, Loc L, SVal val); - StoreRef Remove(Store St, Loc L); - StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl, - const LocationContext *LC, SVal v); - - StoreRef getInitialStore(const LocationContext *InitLoc) { - return StoreRef(RBFactory.getEmptyMap().getRoot(), *this); - } - - SubRegionMap *getSubRegionMap(Store store) { - return 0; - } - - SVal ArrayToPointer(Loc Array); - StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){ - return StoreRef(store, *this); - } - - StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal); - - StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR); - - typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; - - StoreRef invalidateRegions(Store store, const MemRegion * const *I, - const MemRegion * const *E, const Expr *Ex, - unsigned Count, InvalidatedSymbols &IS, - bool invalidateGlobals, - InvalidatedRegions *Regions); - - void print(Store store, llvm::raw_ostream& Out, const char* nl, - const char *sep); - void iterBindings(Store store, BindingsHandler& f); - -private: - static RegionBindings getRegionBindings(Store store) { - return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store)); - } - - class RegionInterval { - public: - const MemRegion *R; - Interval I; - RegionInterval(const MemRegion *r, int64_t s, int64_t e) : R(r), I(s, e){} - }; - - RegionInterval RegionToInterval(const MemRegion *R); - - SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T); -}; -} // end anonymous namespace - -StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) { - return new FlatStoreManager(StMgr); -} - -SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) { - // For access to concrete addresses, return UnknownVal. Checks - // for null dereferences (and similar errors) are done by checkers, not - // the Store. - // FIXME: We can consider lazily symbolicating such memory, but we really - // should defer this when we can reason easily about symbolicating arrays - // of bytes. - if (isa<loc::ConcreteInt>(L)) { - return UnknownVal(); - } - if (!isa<loc::MemRegionVal>(L)) { - return UnknownVal(); - } - - const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); - RegionInterval RI = RegionToInterval(R); - // FIXME: FlatStore should handle regions with unknown intervals. - if (!RI.R) - return UnknownVal(); - - RegionBindings B = getRegionBindings(store); - const BindingVal *BV = B.lookup(RI.R); - if (BV) { - const SVal *V = BVFactory.lookup(*BV, RI.I); - if (V) - return *V; - else - return RetrieveRegionWithNoBinding(R, T); - } - return RetrieveRegionWithNoBinding(R, T); -} - -SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R, - QualType T) { - if (R->hasStackNonParametersStorage()) - return UndefinedVal(); - else - return svalBuilder.getRegionValueSymbolVal(cast<TypedRegion>(R)); -} - -StoreRef FlatStoreManager::Bind(Store store, Loc L, SVal val) { - const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); - RegionBindings B = getRegionBindings(store); - const BindingVal *V = B.lookup(R); - - BindingVal BV = BVFactory.getEmptyMap(); - if (V) - BV = *V; - - RegionInterval RI = RegionToInterval(R); - // FIXME: FlatStore should handle regions with unknown intervals. - if (!RI.R) - return StoreRef(B.getRoot(), *this); - BV = BVFactory.add(BV, RI.I, val); - B = RBFactory.add(B, RI.R, BV); - return StoreRef(B.getRoot(), *this); -} - -StoreRef FlatStoreManager::Remove(Store store, Loc L) { - return StoreRef(store, *this); -} - -StoreRef FlatStoreManager::BindCompoundLiteral(Store store, - const CompoundLiteralExpr* cl, - const LocationContext *LC, - SVal v) { - return StoreRef(store, *this); -} - -SVal FlatStoreManager::ArrayToPointer(Loc Array) { - return Array; -} - -StoreRef FlatStoreManager::BindDecl(Store store, const VarRegion *VR, - SVal initVal) { - return Bind(store, svalBuilder.makeLoc(VR), initVal); -} - -StoreRef FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR){ - return StoreRef(store, *this); -} - -StoreRef FlatStoreManager::invalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *E, - const Expr *Ex, unsigned Count, - InvalidatedSymbols &IS, - bool invalidateGlobals, - InvalidatedRegions *Regions) { - assert(false && "Not implemented"); - return StoreRef(store, *this); -} - -void FlatStoreManager::print(Store store, llvm::raw_ostream& Out, - const char* nl, const char *sep) { -} - -void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) { -} - -FlatStoreManager::RegionInterval -FlatStoreManager::RegionToInterval(const MemRegion *R) { - switch (R->getKind()) { - case MemRegion::VarRegionKind: { - QualType T = cast<VarRegion>(R)->getValueType(); - int64_t Size = Ctx.getTypeSize(T); - return RegionInterval(R, 0, Size-1); - } - - case MemRegion::ElementRegionKind: - case MemRegion::FieldRegionKind: { - RegionOffset Offset = R->getAsOffset(); - // We cannot compute offset for all regions, for example, elements - // with symbolic offsets. - if (!Offset.getRegion()) - return RegionInterval(0, 0, 0); - int64_t Start = Offset.getOffset(); - int64_t Size = Ctx.getTypeSize(cast<TypedRegion>(R)->getValueType()); - return RegionInterval(Offset.getRegion(), Start, Start+Size); - } - - default: - llvm_unreachable("Region kind unhandled."); - return RegionInterval(0, 0, 0); - } -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 1ebc28c..0c4e427 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -35,7 +35,7 @@ using namespace ento; namespace { -class HTMLDiagnostics : public PathDiagnosticClient { +class HTMLDiagnostics : public PathDiagnosticConsumer { llvm::sys::Path Directory, FilePrefix; bool createdDir, noDir; const Preprocessor &PP; @@ -45,15 +45,15 @@ public: virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } - virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); + virtual void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); - virtual void HandlePathDiagnostic(const PathDiagnostic* D); + virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D); - virtual llvm::StringRef getName() const { + virtual StringRef getName() const { return "HTMLDiagnostics"; } - unsigned ProcessMacroPiece(llvm::raw_ostream& os, + unsigned ProcessMacroPiece(raw_ostream &os, const PathDiagnosticMacroPiece& P, unsigned num); @@ -65,7 +65,7 @@ public: const char *HighlightEnd = "</span>"); void ReportDiag(const PathDiagnostic& D, - llvm::SmallVectorImpl<std::string> *FilesMade); + SmallVectorImpl<std::string> *FilesMade); }; } // end anonymous namespace @@ -78,8 +78,8 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, FilePrefix.appendComponent("report"); } -PathDiagnosticClient* -ento::createHTMLDiagnosticClient(const std::string& prefix, +PathDiagnosticConsumer* +ento::createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP) { return new HTMLDiagnostics(prefix, PP); } @@ -88,7 +88,7 @@ ento::createHTMLDiagnosticClient(const std::string& prefix, // Report processing. //===----------------------------------------------------------------------===// -void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { +void HTMLDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { if (!D) return; @@ -102,7 +102,7 @@ void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { } void -HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) +HTMLDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { while (!BatchedDiags.empty()) { const PathDiagnostic* D = BatchedDiags.back(); @@ -115,7 +115,7 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, - llvm::SmallVectorImpl<std::string> *FilesMade){ + SmallVectorImpl<std::string> *FilesMade){ // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; @@ -143,7 +143,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Verify that the entire path is from the same FileID. for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) { - FullSourceLoc L = I->getLocation().asLocation().getInstantiationLoc(); + FullSourceLoc L = I->getLocation().asLocation().getExpansionLoc(); if (FID.isInvalid()) { FID = SMgr.getFileID(L); @@ -154,12 +154,12 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(), RE=I->ranges_end(); RI!=RE; ++RI) { - SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin()); + SourceLocation L = SMgr.getExpansionLoc(RI->getBegin()); if (!L.isFileID() || SMgr.getFileID(L) != FID) return; // FIXME: Emit a warning? - L = SMgr.getInstantiationLoc(RI->getEnd()); + L = SMgr.getExpansionLoc(RI->getEnd()); if (!L.isFileID() || SMgr.getFileID(L) != FID) return; // FIXME: Emit a warning? @@ -221,9 +221,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, << html::EscapeText(Entry->getName()) << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" "<a href=\"#EndPath\">line " - << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber() + << (*D.rbegin()).getLocation().asLocation().getExpansionLineNumber() << ", column " - << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber() + << (*D.rbegin()).getLocation().asLocation().getExpansionColumnNumber() << "</a></td></tr>\n" "<tr><td class=\"rowname\">Description:</td><td>" << D.getDescription() << "</td></tr>\n"; @@ -261,7 +261,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; os << "\n<!-- BUGLINE " - << D.back()->getLocation().asLocation().getInstantiationLineNumber() + << D.back()->getLocation().asLocation().getExpansionLineNumber() << " -->\n"; os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n"; @@ -324,7 +324,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, SourceManager &SM = R.getSourceMgr(); assert(&Pos.getManager() == &SM && "SourceManagers are different!"); - std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos); + std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos); if (LPosInfo.first != BugFileID) return; @@ -335,7 +335,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Compute the column number. Rewind from the current position to the start // of the line. unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second); - const char *TokInstantiationPtr =Pos.getInstantiationLoc().getCharacterData(); + const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData(); const char *LineStart = TokInstantiationPtr-ColNo; // Compute LineEnd. @@ -441,9 +441,9 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Get the name of the macro by relexing it. { - FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc(); + FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc(); assert(L.isFileID()); - llvm::StringRef BufferInfo = L.getBufferData(); + StringRef BufferInfo = L.getBufferData(); const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data(); Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(), MacroName, BufferInfo.end()); @@ -474,7 +474,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, // Insert the new html. unsigned DisplayPos = LineEnd - FileStart; SourceLocation Loc = - SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos); + SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos); R.InsertTextBefore(Loc, os.str()); @@ -504,7 +504,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, #endif } -static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) { +static void EmitAlphaCounter(raw_ostream &os, unsigned n) { unsigned x = n % ('z' - 'a'); n /= 'z' - 'a'; @@ -514,7 +514,7 @@ static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) { os << char('a' + x); } -unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os, +unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os, const PathDiagnosticMacroPiece& P, unsigned num) { @@ -549,11 +549,11 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, SourceManager &SM = R.getSourceMgr(); const LangOptions &LangOpts = R.getLangOpts(); - SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin()); - unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart); + SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin()); + unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart); - SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd()); - unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd); + SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd()); + unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd); if (EndLineNo < StartLineNo) return; @@ -563,7 +563,7 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, return; // Compute the column number of the end. - unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd); + unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd); unsigned OldEndColNo = EndColNo; if (EndColNo) { @@ -575,7 +575,7 @@ void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, // selected range. SourceLocation E = - InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo); + InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo); html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Makefile b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Makefile deleted file mode 100644 index 4aebc16..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- clang/lib/StaticAnalyzer/Core/Makefile --------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements analyses built on top of source-level CFGs. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangStaticAnalyzerCore - -include $(CLANG_LEVEL)/Makefile diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index d9e884a..6f92da8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -38,7 +38,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1) { llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, superRegion); - void* InsertPos; + void *InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); @@ -56,7 +56,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const MemRegion *superRegion) { llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, superRegion); - void* InsertPos; + void *InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); @@ -77,7 +77,7 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, a2, superRegion); - void* InsertPos; + void *InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); @@ -96,7 +96,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, a2, superRegion); - void* InsertPos; + void *InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); @@ -115,7 +115,7 @@ RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3, llvm::FoldingSetNodeID ID; RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion); - void* InsertPos; + void *InsertPos; RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos)); @@ -178,7 +178,7 @@ const StackFrameContext *VarRegion::getStackFrame() const { //===----------------------------------------------------------------------===// DefinedOrUnknownSVal DeclRegion::getExtent(SValBuilder &svalBuilder) const { - ASTContext& Ctx = svalBuilder.getContext(); + ASTContext &Ctx = svalBuilder.getContext(); QualType T = getDesugaredValueType(Ctx); if (isa<VariableArrayType>(T)) @@ -250,7 +250,7 @@ void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, } void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const Expr* Ex, unsigned cnt, + const Expr *Ex, unsigned cnt, const MemRegion *) { ID.AddInteger((unsigned) AllocaRegionKind); ID.AddPointer(Ex); @@ -266,7 +266,7 @@ void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const CompoundLiteralExpr* CL, + const CompoundLiteralExpr *CL, const MemRegion* superRegion) { ID.AddInteger((unsigned) CompoundLiteralRegionKind); ID.AddPointer(CL); @@ -285,7 +285,7 @@ void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const { CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion); } -void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, +void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, const MemRegion* superRegion, Kind k) { ID.AddInteger((unsigned) k); ID.AddPointer(D); @@ -398,81 +398,82 @@ std::string MemRegion::getString() const { return os.str(); } -void MemRegion::dumpToStream(llvm::raw_ostream& os) const { +void MemRegion::dumpToStream(raw_ostream &os) const { os << "<Unknown Region>"; } -void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const { +void AllocaRegion::dumpToStream(raw_ostream &os) const { os << "alloca{" << (void*) Ex << ',' << Cnt << '}'; } -void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const { +void FunctionTextRegion::dumpToStream(raw_ostream &os) const { os << "code{" << getDecl()->getDeclName().getAsString() << '}'; } -void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const { +void BlockTextRegion::dumpToStream(raw_ostream &os) const { os << "block_code{" << (void*) this << '}'; } -void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const { +void BlockDataRegion::dumpToStream(raw_ostream &os) const { os << "block_data{" << BC << '}'; } -void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { +void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const { // FIXME: More elaborate pretty-printing. os << "{ " << (void*) CL << " }"; } -void CXXTempObjectRegion::dumpToStream(llvm::raw_ostream &os) const { - os << "temp_object"; +void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const { + os << "temp_object{" << getValueType().getAsString() << ',' + << (void*) Ex << '}'; } -void CXXBaseObjectRegion::dumpToStream(llvm::raw_ostream &os) const { +void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { os << "base " << decl->getName(); } -void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const { +void CXXThisRegion::dumpToStream(raw_ostream &os) const { os << "this"; } -void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { +void ElementRegion::dumpToStream(raw_ostream &os) const { os << "element{" << superRegion << ',' << Index << ',' << getElementType().getAsString() << '}'; } -void FieldRegion::dumpToStream(llvm::raw_ostream& os) const { - os << superRegion << "->" << getDecl(); +void FieldRegion::dumpToStream(raw_ostream &os) const { + os << superRegion << "->" << *getDecl(); } -void NonStaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const { +void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { os << "NonStaticGlobalSpaceRegion"; } -void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << "ivar{" << superRegion << ',' << getDecl() << '}'; +void ObjCIvarRegion::dumpToStream(raw_ostream &os) const { + os << "ivar{" << superRegion << ',' << *getDecl() << '}'; } -void StringRegion::dumpToStream(llvm::raw_ostream& os) const { +void StringRegion::dumpToStream(raw_ostream &os) const { Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions())); } -void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const { +void SymbolicRegion::dumpToStream(raw_ostream &os) const { os << "SymRegion{" << sym << '}'; } -void VarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << cast<VarDecl>(D); +void VarRegion::dumpToStream(raw_ostream &os) const { + os << *cast<VarDecl>(D); } void RegionRawOffset::dump() const { dumpToStream(llvm::errs()); } -void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const { +void RegionRawOffset::dumpToStream(raw_ostream &os) const { os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}'; } -void StaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const { +void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { os << "StaticGlobalsMemSpace{" << CR << '}'; } @@ -631,7 +632,7 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, } const CompoundLiteralRegion* -MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL, +MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const LocationContext *LC) { const MemRegion *sReg = 0; @@ -650,14 +651,14 @@ MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL, const ElementRegion* MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, const MemRegion* superRegion, - ASTContext& Ctx){ + ASTContext &Ctx){ QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType(); llvm::FoldingSetNodeID ID; ElementRegion::ProfileRegion(ID, T, Idx, superRegion); - void* InsertPos; + void *InsertPos; MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos); ElementRegion* R = cast_or_null<ElementRegion>(data); @@ -688,13 +689,13 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { } const FieldRegion* -MemRegionManager::getFieldRegion(const FieldDecl* d, +MemRegionManager::getFieldRegion(const FieldDecl *d, const MemRegion* superRegion){ return getSubRegion<FieldRegion>(d, superRegion); } const ObjCIvarRegion* -MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, +MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d, const MemRegion* superRegion) { return getSubRegion<ObjCIvarRegion>(d, superRegion); } @@ -724,7 +725,7 @@ MemRegionManager::getCXXThisRegion(QualType thisPointerTy, } const AllocaRegion* -MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt, +MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt, const LocationContext *LC) { const StackFrameContext *STC = LC->getCurrentStackFrame(); assert(STC); @@ -896,7 +897,7 @@ RegionOffset MemRegion::getAsOffset() const { case FieldRegionKind: { const FieldRegion *FR = cast<FieldRegion>(R); const RecordDecl *RD = FR->getDecl()->getParent(); - if (!RD->isDefinition()) + if (!RD->isCompleteDefinition()) // We cannot compute offset for incomplete type. return RegionOffset(0); // Get the field number. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp index c000600..0974fe8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -112,18 +112,22 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { QualType resultTy; bool isLVal = false; - if (CallE) { - isLVal = CallE->isLValue(); - const Expr *Callee = CallE->getCallee(); - if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) - resultTy = FD->getResultType(); - else - resultTy = CallE->getType(); - } - else { + if (isObjCMessage()) { isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) && Msg.getOriginExpr()->isLValue(); resultTy = Msg.getResultType(ctx); + } else if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) { + resultTy = Ctor->getType(); + } else { + const CallExpr *FunctionCall = CallE.get<const CallExpr *>(); + + isLVal = FunctionCall->isLValue(); + const Expr *Callee = FunctionCall->getCallee(); + if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) + resultTy = FD->getResultType(); + else + resultTy = FunctionCall->getType(); } if (isLVal) @@ -132,25 +136,29 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { return resultTy; } -SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { - assert(i < getNumArgs()); - if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i)); - QualType argT = Msg.getArgType(i); - if (Loc::isLocType(argT) || argT->isIntegerType()) - return Msg.getArgSVal(i, State); - return UnknownVal(); -} - SVal CallOrObjCMessage::getFunctionCallee() const { assert(isFunctionCall()); assert(!isCXXCall()); - const Expr *callee = CallE->getCallee()->IgnoreParenCasts(); - return State->getSVal(callee); + const Expr *Fun = CallE.get<const CallExpr *>()->getCallee()->IgnoreParens(); + return State->getSVal(Fun); } SVal CallOrObjCMessage::getCXXCallee() const { assert(isCXXCall()); + const CallExpr *ActualCall = CallE.get<const CallExpr *>(); const Expr *callee = - cast<CXXMemberCallExpr>(CallE)->getImplicitObjectArgument(); - return State->getSVal(callee); + cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument(); + + // FIXME: Will eventually need to cope with member pointers. This is + // a limitation in getImplicitObjectArgument(). + if (!callee) + return UnknownVal(); + + return State->getSVal(callee); +} + +SVal +CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const { + assert(isObjCMessage()); + return Msg.getInstanceReceiverSVal(State, LC); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 872bbfe..3a87903 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -12,17 +12,16 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/Casting.h" using namespace clang; using namespace ento; -using llvm::dyn_cast; -using llvm::isa; bool PathDiagnosticMacroPiece::containsEvent() const { for (const_iterator I = begin(), E = end(); I!=E; ++I) { @@ -37,14 +36,14 @@ bool PathDiagnosticMacroPiece::containsEvent() const { return false; } -static llvm::StringRef StripTrailingDots(llvm::StringRef s) { - for (llvm::StringRef::size_type i = s.size(); i != 0; --i) +static StringRef StripTrailingDots(StringRef s) { + for (StringRef::size_type i = s.size(); i != 0; --i) if (s[i - 1] != '.') return s.substr(0, i); return ""; } -PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s, +PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint) : str(StripTrailingDots(s)), kind(k), Hint(hint) {} @@ -76,55 +75,161 @@ void PathDiagnostic::resetPath(bool deletePieces) { } -PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, - llvm::StringRef category) +PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc, + StringRef category) : Size(0), BugType(StripTrailingDots(bugtype)), Desc(StripTrailingDots(desc)), Category(StripTrailingDots(category)) {} -void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { - // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(DiagLevel, Info); +void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) { + // For now this simply forwards to HandlePathDiagnosticImpl. In the future + // we can use this indirection to control for multi-threaded access to + // the PathDiagnosticConsumer from multiple bug reporters. + HandlePathDiagnosticImpl(D); +} + +//===----------------------------------------------------------------------===// +// PathDiagnosticLocation methods. +//===----------------------------------------------------------------------===// + +static SourceLocation getValidSourceLocation(const Stmt* S, + LocationOrAnalysisContext LAC) { + SourceLocation L = S->getLocStart(); + assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should " + "be passed to PathDiagnosticLocation upon creation."); + + // S might be a temporary statement that does not have a location in the + // source code, so find an enclosing statement and use it's location. + if (!L.isValid()) { + + ParentMap *PM = 0; + if (LAC.is<const LocationContext*>()) + PM = &LAC.get<const LocationContext*>()->getParentMap(); + else + PM = &LAC.get<AnalysisContext*>()->getParentMap(); + + while (!L.isValid()) { + S = PM->getParent(S); + L = S->getLocStart(); + } + } + + return L; +} - // Create a PathDiagnostic with a single piece. +PathDiagnosticLocation + PathDiagnosticLocation::createBegin(const Decl *D, + const SourceManager &SM) { + return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); +} - PathDiagnostic* D = new PathDiagnostic(); +PathDiagnosticLocation + PathDiagnosticLocation::createBegin(const Stmt *S, + const SourceManager &SM, + LocationOrAnalysisContext LAC) { + return PathDiagnosticLocation(getValidSourceLocation(S, LAC), + SM, SingleLocK); +} - const char *LevelStr; - switch (DiagLevel) { - default: - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: LevelStr = "note: "; break; - case Diagnostic::Warning: LevelStr = "warning: "; break; - case Diagnostic::Error: LevelStr = "error: "; break; - case Diagnostic::Fatal: LevelStr = "fatal error: "; break; +PathDiagnosticLocation + PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, + const SourceManager &SM) { + return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); +} + +PathDiagnosticLocation + PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, + const SourceManager &SM) { + return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); +} + +PathDiagnosticLocation + PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, + const SourceManager &SM) { + SourceLocation L = CS->getLBracLoc(); + return PathDiagnosticLocation(L, SM, SingleLocK); +} + +PathDiagnosticLocation + PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, + const SourceManager &SM) { + SourceLocation L = CS->getRBracLoc(); + return PathDiagnosticLocation(L, SM, SingleLocK); +} + +PathDiagnosticLocation + PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, + const SourceManager &SM) { + // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. + if (const CompoundStmt *CS = + dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) + if (!CS->body_empty()) { + SourceLocation Loc = (*CS->body_begin())->getLocStart(); + return PathDiagnosticLocation(Loc, SM, SingleLocK); + } + + return PathDiagnosticLocation(); +} + +PathDiagnosticLocation + PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, + const SourceManager &SM) { + SourceLocation L = LC->getDecl()->getBodyRBrace(); + return PathDiagnosticLocation(L, SM, SingleLocK); +} + +PathDiagnosticLocation + PathDiagnosticLocation::create(const ProgramPoint& P, + const SourceManager &SMng) { + + const Stmt* S = 0; + if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + const CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { + S = PS->getStmt(); } - llvm::SmallString<100> StrC; - StrC += LevelStr; - Info.FormatDiagnostic(StrC); + return PathDiagnosticLocation(S, SMng, P.getLocationContext()); - PathDiagnosticPiece *P = - new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(), - Info.getSourceManager()), - StrC.str()); + if (!S) + return PathDiagnosticLocation(); +} - for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) - P->addRange(Info.getRange(i).getAsRange()); - for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) - P->addFixItHint(Info.getFixItHint(i)); - D->push_front(P); +PathDiagnosticLocation + PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, + const SourceManager &SM) { + assert(N && "Cannot create a location with a null node."); + + const ExplodedNode *NI = N; + + while (NI) { + ProgramPoint P = NI->getLocation(); + const LocationContext *LC = P.getLocationContext(); + if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) + return PathDiagnosticLocation(PS->getStmt(), SM, LC); + else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + const Stmt *Term = BE->getSrc()->getTerminator(); + assert(Term); + return PathDiagnosticLocation(Term, SM, LC); + } + NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); + } - HandlePathDiagnostic(D); + return createDeclEnd(N->getLocationContext(), SM); } -//===----------------------------------------------------------------------===// -// PathDiagnosticLocation methods. -//===----------------------------------------------------------------------===// +PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( + const PathDiagnosticLocation &PDL) { + FullSourceLoc L = PDL.asLocation(); + return PathDiagnosticLocation(L, L.getManager(), SingleLocK); +} -FullSourceLoc PathDiagnosticLocation::asLocation() const { +FullSourceLoc + PathDiagnosticLocation::genLocation(SourceLocation L, + LocationOrAnalysisContext LAC) const { assert(isValid()); // Note that we want a 'switch' here so that the compiler can warn us in // case we add more cases. @@ -133,21 +238,23 @@ FullSourceLoc PathDiagnosticLocation::asLocation() const { case RangeK: break; case StmtK: - return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM)); + return FullSourceLoc(getValidSourceLocation(S, LAC), + const_cast<SourceManager&>(*SM)); case DeclK: return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); } - return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM)); + return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); } -PathDiagnosticRange PathDiagnosticLocation::asRange() const { +PathDiagnosticRange + PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const { assert(isValid()); // Note that we want a 'switch' here so that the compiler can warn us in // case we add more cases. switch (K) { case SingleLocK: - return PathDiagnosticRange(R, true); + return PathDiagnosticRange(SourceRange(Loc,Loc), true); case RangeK: break; case StmtK: { @@ -176,12 +283,14 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: case Stmt::ObjCForCollectionStmtClass: { - SourceLocation L = S->getLocStart(); + SourceLocation L = getValidSourceLocation(S, LAC); return SourceRange(L, L); } } - - return S->getSourceRange(); + SourceRange R = S->getSourceRange(); + if (R.isValid()) + return R; + break; } case DeclK: if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) @@ -196,19 +305,16 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { } } - return R; + return SourceRange(Loc,Loc); } void PathDiagnosticLocation::flatten() { if (K == StmtK) { - R = asRange(); K = RangeK; S = 0; D = 0; } else if (K == DeclK) { - SourceLocation L = D->getLocation(); - R = SourceRange(L, L); K = SingleLocK; S = 0; D = 0; @@ -220,22 +326,9 @@ void PathDiagnosticLocation::flatten() { //===----------------------------------------------------------------------===// void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger((unsigned) K); - switch (K) { - case RangeK: - ID.AddInteger(R.getBegin().getRawEncoding()); - ID.AddInteger(R.getEnd().getRawEncoding()); - break; - case SingleLocK: - ID.AddInteger(R.getBegin().getRawEncoding()); - break; - case StmtK: - ID.Add(S); - break; - case DeclK: - ID.Add(D); - break; - } + ID.AddInteger(Range.getBegin().getRawEncoding()); + ID.AddInteger(Range.getEnd().getRawEncoding()); + ID.AddInteger(Loc.getRawEncoding()); return; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index fbbbd46..5ae95c6 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" @@ -22,14 +22,9 @@ #include "llvm/ADT/SmallVector.h" using namespace clang; using namespace ento; -using llvm::cast; typedef llvm::DenseMap<FileID, unsigned> FIDMap; -namespace clang { - class Preprocessor; -} - namespace { struct CompareDiagnostics { // Compare if 'X' is "<" than 'Y'. @@ -43,16 +38,16 @@ struct CompareDiagnostics { return false; // Next, compare by bug type. - llvm::StringRef XBugType = X->getBugType(); - llvm::StringRef YBugType = Y->getBugType(); + StringRef XBugType = X->getBugType(); + StringRef YBugType = Y->getBugType(); if (XBugType < YBugType) return true; if (XBugType != YBugType) return false; // Next, compare by bug description. - llvm::StringRef XDesc = X->getDescription(); - llvm::StringRef YDesc = Y->getDescription(); + StringRef XDesc = X->getDescription(); + StringRef YDesc = Y->getDescription(); if (XDesc < YDesc) return true; if (XDesc != YDesc) @@ -65,23 +60,23 @@ struct CompareDiagnostics { } namespace { - class PlistDiagnostics : public PathDiagnosticClient { + class PlistDiagnostics : public PathDiagnosticConsumer { std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; const LangOptions &LangOpts; - llvm::OwningPtr<PathDiagnosticClient> SubPD; + llvm::OwningPtr<PathDiagnosticConsumer> SubPD; bool flushed; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, - PathDiagnosticClient *subPD); + PathDiagnosticConsumer *subPD); ~PlistDiagnostics() { FlushDiagnostics(NULL); } - void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); + void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); - void HandlePathDiagnostic(const PathDiagnostic* D); + void HandlePathDiagnosticImpl(const PathDiagnostic* D); - virtual llvm::StringRef getName() const { + virtual StringRef getName() const { return "PlistDiagnostics"; } @@ -94,27 +89,27 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, - PathDiagnosticClient *subPD) + PathDiagnosticConsumer *subPD) : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} -PathDiagnosticClient* -ento::createPlistDiagnosticClient(const std::string& s, const Preprocessor &PP, - PathDiagnosticClient *subPD) { +PathDiagnosticConsumer* +ento::createPlistDiagnosticConsumer(const std::string& s, const Preprocessor &PP, + PathDiagnosticConsumer *subPD) { return new PlistDiagnostics(s, PP.getLangOptions(), subPD); } -PathDiagnosticClient::PathGenerationScheme +PathDiagnosticConsumer::PathGenerationScheme PlistDiagnostics::getGenerationScheme() const { - if (const PathDiagnosticClient *PD = SubPD.get()) + if (const PathDiagnosticConsumer *PD = SubPD.get()) return PD->getGenerationScheme(); return Extensive; } -static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V, +static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, const SourceManager* SM, SourceLocation L) { - FileID FID = SM->getFileID(SM->getInstantiationLoc(L)); + FileID FID = SM->getFileID(SM->getExpansionLoc(L)); FIDMap::iterator I = FIDs.find(FID); if (I != FIDs.end()) return; FIDs[FID] = V.size(); @@ -123,23 +118,23 @@ static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V, static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, SourceLocation L) { - FileID FID = SM.getFileID(SM.getInstantiationLoc(L)); + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); FIDMap::const_iterator I = FIDs.find(FID); assert(I != FIDs.end()); return I->second; } -static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) { +static raw_ostream &Indent(raw_ostream &o, const unsigned indent) { for (unsigned i = 0; i < indent; ++i) o << ' '; return o; } -static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, +static void EmitLocation(raw_ostream &o, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation L, const FIDMap &FM, unsigned indent, bool extend = false) { - FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<SourceManager&>(SM)); + FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); // Add in the length of the token, so that we cover multi-char tokens. unsigned offset = @@ -147,22 +142,22 @@ static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, Indent(o, indent) << "<dict>\n"; Indent(o, indent) << " <key>line</key><integer>" - << Loc.getInstantiationLineNumber() << "</integer>\n"; + << Loc.getExpansionLineNumber() << "</integer>\n"; Indent(o, indent) << " <key>col</key><integer>" - << Loc.getInstantiationColumnNumber() + offset << "</integer>\n"; + << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; Indent(o, indent) << " <key>file</key><integer>" << GetFID(FM, SM, Loc) << "</integer>\n"; Indent(o, indent) << "</dict>\n"; } -static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, +static void EmitLocation(raw_ostream &o, const SourceManager &SM, const LangOptions &LangOpts, const PathDiagnosticLocation &L, const FIDMap& FM, unsigned indent, bool extend = false) { EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); } -static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM, +static void EmitRange(raw_ostream &o, const SourceManager &SM, const LangOptions &LangOpts, PathDiagnosticRange R, const FIDMap &FM, unsigned indent) { @@ -172,7 +167,7 @@ static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM, Indent(o, indent) << "</array>\n"; } -static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, +static raw_ostream &EmitString(raw_ostream &o, const std::string& s) { o << "<string>"; for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { @@ -190,7 +185,7 @@ static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, return o; } -static void ReportControlFlow(llvm::raw_ostream& o, +static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece& P, const FIDMap& FM, const SourceManager &SM, @@ -233,7 +228,7 @@ static void ReportControlFlow(llvm::raw_ostream& o, Indent(o, indent) << "</dict>\n"; } -static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, +static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, @@ -280,7 +275,7 @@ static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, Indent(o, indent); o << "</dict>\n"; } -static void ReportMacro(llvm::raw_ostream& o, +static void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, @@ -304,7 +299,7 @@ static void ReportMacro(llvm::raw_ostream& o, } } -static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, +static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts) { @@ -326,7 +321,7 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, } } -void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { +void PlistDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { if (!D) return; @@ -342,7 +337,7 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { BatchedDiags.push_back(D); } -void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> +void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { if (flushed) @@ -358,7 +353,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. FIDMap FM; - llvm::SmallVector<FileID, 10> Fids; + SmallVector<FileID, 10> Fids; const SourceManager* SM = 0; if (!BatchedDiags.empty()) @@ -401,7 +396,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> " <key>files</key>\n" " <array>\n"; - for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); + for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); I!=E; ++I) { o << " "; EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; @@ -444,7 +439,7 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> // Output the diagnostic to the sub-diagnostic client, if any. if (SubPD) { SubPD->HandlePathDiagnostic(OwnedD.take()); - llvm::SmallVector<std::string, 1> SubFilesMade; + SmallVector<std::string, 1> SubFilesMade; SubPD->FlushDiagnostics(SubFilesMade); if (!SubFilesMade.empty()) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 0f6ff1e..73788cc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/GRState.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -1,4 +1,4 @@ -//= GRState.cpp - Path-Sensitive "State" for tracking values -----*- C++ -*--=// +//= ProgramState.cpp - Path-Sensitive "State" for tracking values --*- C++ -*--= // // The LLVM Compiler Infrastructure // @@ -7,15 +7,14 @@ // //===----------------------------------------------------------------------===// // -// This file implements GRState and GRStateManager. +// This file implements ProgramState and ProgramStateManager. // //===----------------------------------------------------------------------===// #include "clang/Analysis/CFG.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -25,7 +24,7 @@ using namespace ento; // FIXME: Move this elsewhere. ConstraintManager::~ConstraintManager() {} -GRState::GRState(GRStateManager *mgr, const Environment& env, +ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env, StoreRef st, GenericDataMap gdm) : stateMgr(mgr), Env(env), @@ -35,7 +34,7 @@ GRState::GRState(GRStateManager *mgr, const Environment& env, stateMgr->getStoreManager().incrementReferenceCount(store); } -GRState::GRState(const GRState& RHS) +ProgramState::ProgramState(const ProgramState &RHS) : llvm::FoldingSetNode(), stateMgr(RHS.stateMgr), Env(RHS.Env), @@ -45,23 +44,19 @@ GRState::GRState(const GRState& RHS) stateMgr->getStoreManager().incrementReferenceCount(store); } -GRState::~GRState() { +ProgramState::~ProgramState() { if (store) stateMgr->getStoreManager().decrementReferenceCount(store); } -GRStateManager::~GRStateManager() { - for (std::vector<GRState::Printer*>::iterator I=Printers.begin(), - E=Printers.end(); I!=E; ++I) - delete *I; - +ProgramStateManager::~ProgramStateManager() { for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end(); I!=E; ++I) I->second.second(I->second.first); } -const GRState* -GRStateManager::removeDeadBindings(const GRState* state, +const ProgramState* +ProgramStateManager::removeDeadBindings(const ProgramState *state, const StackFrameContext *LCtx, SymbolReaper& SymReaper) { @@ -71,23 +66,23 @@ GRStateManager::removeDeadBindings(const GRState* state, // those around. This code more than likely can be made faster, and the // frequency of which this method is called should be experimented with // for optimum performance. - llvm::SmallVector<const MemRegion*, 10> RegionRoots; - GRState NewState = *state; + ProgramState NewState = *state; - NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, - state, RegionRoots); + NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state); // Clean up the store. - NewState.setStore(StoreMgr->removeDeadBindings(NewState.getStore(), LCtx, - SymReaper, RegionRoots)); - state = getPersistentState(NewState); - return ConstraintMgr->removeDeadBindings(state, SymReaper); + StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx, + SymReaper); + NewState.setStore(newStore); + SymReaper.setReapedStore(newStore); + + return getPersistentState(NewState); } -const GRState *GRStateManager::MarshalState(const GRState *state, +const ProgramState *ProgramStateManager::MarshalState(const ProgramState *state, const StackFrameContext *InitLoc) { // make up an empty state for now. - GRState State(this, + ProgramState State(this, EnvMgr.getInitialEnvironment(), StoreMgr->getInitialStore(InitLoc), GDMFactory.getEmptyMap()); @@ -95,7 +90,7 @@ const GRState *GRStateManager::MarshalState(const GRState *state, return getPersistentState(State); } -const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, +const ProgramState *ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL, const LocationContext *LC, SVal V) const { const StoreRef &newStore = @@ -103,21 +98,21 @@ const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, return makeWithStore(newStore); } -const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { +const ProgramState *ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const { const StoreRef &newStore = getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal); return makeWithStore(newStore); } -const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const { +const ProgramState *ProgramState::bindDeclWithNoInit(const VarRegion* VR) const { const StoreRef &newStore = getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR); return makeWithStore(newStore); } -const GRState *GRState::bindLoc(Loc LV, SVal V) const { - GRStateManager &Mgr = getStateManager(); - const GRState *newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), +const ProgramState *ProgramState::bindLoc(Loc LV, SVal V) const { + ProgramStateManager &Mgr = getStateManager(); + const ProgramState *newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), LV, V)); const MemRegion *MR = LV.getAsRegion(); if (MR && Mgr.getOwningEngine()) @@ -126,56 +121,53 @@ const GRState *GRState::bindLoc(Loc LV, SVal V) const { return newState; } -const GRState *GRState::bindDefault(SVal loc, SVal V) const { - GRStateManager &Mgr = getStateManager(); +const ProgramState *ProgramState::bindDefault(SVal loc, SVal V) const { + ProgramStateManager &Mgr = getStateManager(); const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion(); const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V); - const GRState *new_state = makeWithStore(newStore); + const ProgramState *new_state = makeWithStore(newStore); return Mgr.getOwningEngine() ? Mgr.getOwningEngine()->processRegionChange(new_state, R) : new_state; } -const GRState *GRState::invalidateRegions(const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - StoreManager::InvalidatedSymbols *IS, - bool invalidateGlobals) const { +const ProgramState * +ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols *IS, + bool invalidateGlobals) const { if (!IS) { StoreManager::InvalidatedSymbols invalidated; - return invalidateRegionsImpl(Begin, End, E, Count, - invalidated, invalidateGlobals); + return invalidateRegionsImpl(Regions, E, Count, + invalidated, invalidateGlobals); } - return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals); + return invalidateRegionsImpl(Regions, E, Count, *IS, invalidateGlobals); } -const GRState * -GRState::invalidateRegionsImpl(const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - StoreManager::InvalidatedSymbols &IS, - bool invalidateGlobals) const { - GRStateManager &Mgr = getStateManager(); +const ProgramState * +ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols &IS, + bool invalidateGlobals) const { + ProgramStateManager &Mgr = getStateManager(); SubEngine* Eng = Mgr.getOwningEngine(); if (Eng && Eng->wantsRegionChangeUpdate(this)) { - StoreManager::InvalidatedRegions Regions; + StoreManager::InvalidatedRegions Invalidated; const StoreRef &newStore - = Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS, - invalidateGlobals, &Regions); - const GRState *newState = makeWithStore(newStore); - return Eng->processRegionChanges(newState, &IS, - &Regions.front(), - &Regions.back()+1); + = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, + invalidateGlobals, &Invalidated); + const ProgramState *newState = makeWithStore(newStore); + return Eng->processRegionChanges(newState, &IS, Regions, Invalidated); } const StoreRef &newStore = - Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS, + Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS, invalidateGlobals, NULL); return makeWithStore(newStore); } -const GRState *GRState::unbindLoc(Loc LV) const { +const ProgramState *ProgramState::unbindLoc(Loc LV) const { assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead."); Store OldStore = getStore(); @@ -187,20 +179,20 @@ const GRState *GRState::unbindLoc(Loc LV) const { return makeWithStore(newStore); } -const GRState *GRState::enterStackFrame(const StackFrameContext *frame) const { +const ProgramState *ProgramState::enterStackFrame(const StackFrameContext *frame) const { const StoreRef &new_store = getStateManager().StoreMgr->enterStackFrame(this, frame); return makeWithStore(new_store); } -SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { +SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const { // We only want to do fetches from regions that we can actually bind // values. For example, SymbolicRegions of type 'id<...>' cannot // have direct bindings (but their can be bindings on their subregions). if (!R->isBoundable()) return UnknownVal(); - if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { QualType T = TR->getValueType(); if (Loc::isLocType(T) || T->isIntegerType()) return getSVal(R); @@ -209,7 +201,7 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { return UnknownVal(); } -SVal GRState::getSVal(Loc location, QualType T) const { +SVal ProgramState::getSVal(Loc location, QualType T) const { SVal V = getRawSVal(cast<Loc>(location), T); // If 'V' is a symbolic value that is *perfectly* constrained to @@ -246,18 +238,18 @@ SVal GRState::getSVal(Loc location, QualType T) const { return V; } -const GRState *GRState::BindExpr(const Stmt* S, SVal V, bool Invalidate) const{ +const ProgramState *ProgramState::BindExpr(const Stmt *S, SVal V, bool Invalidate) const{ Environment NewEnv = getStateManager().EnvMgr.bindExpr(Env, S, V, Invalidate); if (NewEnv == Env) return this; - GRState NewSt = *this; + ProgramState NewSt = *this; NewSt.Env = NewEnv; return getStateManager().getPersistentState(NewSt); } -const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location, +const ProgramState *ProgramState::bindExprAndLocation(const Stmt *S, SVal location, SVal V) const { Environment NewEnv = getStateManager().EnvMgr.bindExprAndLocation(Env, S, location, V); @@ -265,12 +257,12 @@ const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location, if (NewEnv == Env) return this; - GRState NewSt = *this; + ProgramState NewSt = *this; NewSt.Env = NewEnv; return getStateManager().getPersistentState(NewSt); } -const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx, +const ProgramState *ProgramState::assumeInBound(DefinedOrUnknownSVal Idx, DefinedOrUnknownSVal UpperBound, bool Assumption) const { if (Idx.isUnknown() || UpperBound.isUnknown()) @@ -279,7 +271,7 @@ const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx, // Build an expression for 0 <= Idx < UpperBound. // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed. // FIXME: This should probably be part of SValBuilder. - GRStateManager &SM = getStateManager(); + ProgramStateManager &SM = getStateManager(); SValBuilder &svalBuilder = SM.getSValBuilder(); ASTContext &Ctx = svalBuilder.getContext(); @@ -315,8 +307,8 @@ const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx, return CM.assume(this, cast<DefinedSVal>(inBound), Assumption); } -const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) { - GRState State(this, +const ProgramState *ProgramStateManager::getInitialState(const LocationContext *InitLoc) { + ProgramState State(this, EnvMgr.getInitialEnvironment(), StoreMgr->getInitialStore(InitLoc), GDMFactory.getEmptyMap()); @@ -324,49 +316,57 @@ const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) { return getPersistentState(State); } -void GRStateManager::recycleUnusedStates() { - for (std::vector<GRState*>::iterator i = recentlyAllocatedStates.begin(), +void ProgramStateManager::recycleUnusedStates() { + for (std::vector<ProgramState*>::iterator i = recentlyAllocatedStates.begin(), e = recentlyAllocatedStates.end(); i != e; ++i) { - GRState *state = *i; + ProgramState *state = *i; if (state->referencedByExplodedNode()) continue; StateSet.RemoveNode(state); freeStates.push_back(state); - state->~GRState(); + state->~ProgramState(); } recentlyAllocatedStates.clear(); } -const GRState* GRStateManager::getPersistentState(GRState& State) { +const ProgramState *ProgramStateManager::getPersistentStateWithGDM( + const ProgramState *FromState, + const ProgramState *GDMState) { + ProgramState NewState = *FromState; + NewState.GDM = GDMState->GDM; + return getPersistentState(NewState); +} + +const ProgramState *ProgramStateManager::getPersistentState(ProgramState &State) { llvm::FoldingSetNodeID ID; State.Profile(ID); - void* InsertPos; + void *InsertPos; - if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) + if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) return I; - GRState *newState = 0; + ProgramState *newState = 0; if (!freeStates.empty()) { newState = freeStates.back(); freeStates.pop_back(); } else { - newState = (GRState*) Alloc.Allocate<GRState>(); + newState = (ProgramState*) Alloc.Allocate<ProgramState>(); } - new (newState) GRState(State); + new (newState) ProgramState(State); StateSet.InsertNode(newState, InsertPos); recentlyAllocatedStates.push_back(newState); return newState; } -const GRState* GRState::makeWithStore(const StoreRef &store) const { - GRState NewSt = *this; +const ProgramState *ProgramState::makeWithStore(const StoreRef &store) const { + ProgramState NewSt = *this; NewSt.setStore(store); return getStateManager().getPersistentState(NewSt); } -void GRState::setStore(const StoreRef &newStore) { +void ProgramState::setStore(const StoreRef &newStore) { Store newStoreStore = newStore.getStore(); if (newStoreStore) stateMgr->getStoreManager().incrementReferenceCount(newStoreStore); @@ -384,11 +384,11 @@ static bool IsEnvLoc(const Stmt *S) { return (bool) (((uintptr_t) S) & 0x1); } -void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, - const char* sep) const { +void ProgramState::print(raw_ostream &Out, CFG &C, + const char *NL, const char *Sep) const { // Print the store. - GRStateManager &Mgr = getStateManager(); - Mgr.getStoreManager().print(getStore(), Out, nl, sep); + ProgramStateManager &Mgr = getStateManager(); + Mgr.getStoreManager().print(getStore(), Out, NL, Sep); // Print Subexpression bindings. bool isFirst = true; @@ -399,10 +399,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, continue; if (isFirst) { - Out << nl << nl << "Sub-Expressions:" << nl; + Out << NL << NL << "Sub-Expressions:" << NL; isFirst = false; + } else { + Out << NL; } - else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. @@ -418,10 +419,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, continue; if (isFirst) { - Out << nl << nl << "Block-level Expressions:" << nl; + Out << NL << NL << "Block-level Expressions:" << NL; isFirst = false; + } else { + Out << NL; } - else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. @@ -437,10 +439,11 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, continue; if (isFirst) { - Out << nl << nl << "Load/store locations:" << nl; + Out << NL << NL << "Load/store locations:" << NL; isFirst = false; + } else { + Out << NL; } - else { Out << nl; } const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1)); @@ -450,20 +453,17 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, Out << " : " << I.getData(); } - Mgr.getConstraintManager().print(this, Out, nl, sep); + Mgr.getConstraintManager().print(this, Out, NL, Sep); // Print checker-specific data. - for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(), - E = Mgr.Printers.end(); I != E; ++I) { - (*I)->Print(Out, this, nl, sep); - } + Mgr.getOwningEngine()->printState(Out, this, NL, Sep); } -void GRState::printDOT(llvm::raw_ostream& Out, CFG &C) const { +void ProgramState::printDOT(raw_ostream &Out, CFG &C) const { print(Out, C, "\\l", "\\|"); } -void GRState::printStdErr(CFG &C) const { +void ProgramState::printStdErr(CFG &C) const { print(llvm::errs(), C); } @@ -471,13 +471,13 @@ void GRState::printStdErr(CFG &C) const { // Generic Data Map. //===----------------------------------------------------------------------===// -void* const* GRState::FindGDM(void* K) const { +void *const* ProgramState::FindGDM(void *K) const { return GDM.lookup(K); } void* -GRStateManager::FindGDMContext(void* K, - void* (*CreateContext)(llvm::BumpPtrAllocator&), +ProgramStateManager::FindGDMContext(void *K, + void *(*CreateContext)(llvm::BumpPtrAllocator&), void (*DeleteContext)(void*)) { std::pair<void*, void (*)(void*)>& p = GDMContexts[K]; @@ -489,58 +489,30 @@ GRStateManager::FindGDMContext(void* K, return p.first; } -const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ - GRState::GenericDataMap M1 = St->getGDM(); - GRState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data); +const ProgramState *ProgramStateManager::addGDM(const ProgramState *St, void *Key, void *Data){ + ProgramState::GenericDataMap M1 = St->getGDM(); + ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data); if (M1 == M2) return St; - GRState NewSt = *St; + ProgramState NewSt = *St; NewSt.GDM = M2; return getPersistentState(NewSt); } -const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) { - GRState::GenericDataMap OldM = state->getGDM(); - GRState::GenericDataMap NewM = GDMFactory.remove(OldM, Key); +const ProgramState *ProgramStateManager::removeGDM(const ProgramState *state, void *Key) { + ProgramState::GenericDataMap OldM = state->getGDM(); + ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key); if (NewM == OldM) return state; - GRState NewState = *state; + ProgramState NewState = *state; NewState.GDM = NewM; return getPersistentState(NewState); } -//===----------------------------------------------------------------------===// -// Utility. -//===----------------------------------------------------------------------===// - -namespace { -class ScanReachableSymbols : public SubRegionMap::Visitor { - typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy; - - VisitedRegionsTy visited; - const GRState *state; - SymbolVisitor &visitor; - llvm::OwningPtr<SubRegionMap> SRM; -public: - - ScanReachableSymbols(const GRState *st, SymbolVisitor& v) - : state(st), visitor(v) {} - - bool scan(nonloc::CompoundVal val); - bool scan(SVal val); - bool scan(const MemRegion *R); - - // From SubRegionMap::Visitor. - bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) { - return scan(SubRegion); - } -}; -} - bool ScanReachableSymbols::scan(nonloc::CompoundVal val) { for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I) if (!scan(*I)) @@ -549,6 +521,33 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) { return true; } +bool ScanReachableSymbols::scan(const SymExpr *sym) { + unsigned &isVisited = visited[sym]; + if (isVisited) + return true; + isVisited = 1; + + if (const SymbolData *sData = dyn_cast<SymbolData>(sym)) + if (!visitor.VisitSymbol(sData)) + return false; + + switch (sym->getKind()) { + case SymExpr::RegionValueKind: + case SymExpr::ConjuredKind: + case SymExpr::DerivedKind: + case SymExpr::ExtentKind: + case SymExpr::MetadataKind: + break; + case SymExpr::SymIntKind: + return scan(cast<SymIntExpr>(sym)->getLHS()); + case SymExpr::SymSymKind: { + const SymSymExpr *x = cast<SymSymExpr>(sym); + return scan(x->getLHS()) && scan(x->getRHS()); + } + } + return true; +} + bool ScanReachableSymbols::scan(SVal val) { if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val)) return scan(X->getRegion()); @@ -557,7 +556,10 @@ bool ScanReachableSymbols::scan(SVal val) { return scan(X->getLoc()); if (SymbolRef Sym = val.getAsSymbol()) - return visitor.VisitSymbol(Sym); + return scan(Sym); + + if (const SymExpr *Sym = val.getAsSymbolicExpression()) + return scan(Sym); if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val)) return scan(*X); @@ -566,10 +568,13 @@ bool ScanReachableSymbols::scan(SVal val) { } bool ScanReachableSymbols::scan(const MemRegion *R) { - if (isa<MemSpaceRegion>(R) || visited.count(R)) + if (isa<MemSpaceRegion>(R)) return true; - - visited.insert(R); + + unsigned &isVisited = visited[R]; + if (isVisited) + return true; + isVisited = 1; // If this is a symbolic region, visit the symbol for the region. if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) @@ -593,12 +598,12 @@ bool ScanReachableSymbols::scan(const MemRegion *R) { return SRM->iterSubRegions(R, *this); } -bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const { +bool ProgramState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const { ScanReachableSymbols S(this, visitor); return S.scan(val); } -bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, +bool ProgramState::scanReachableSymbols(const SVal *I, const SVal *E, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); for ( ; I != E; ++I) { @@ -608,7 +613,7 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, return true; } -bool GRState::scanReachableSymbols(const MemRegion * const *I, +bool ProgramState::scanReachableSymbols(const MemRegion * const *I, const MemRegion * const *E, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 389fff5..9337788 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -8,14 +8,13 @@ //===----------------------------------------------------------------------===// // // This file defines RangeConstraintManager, a class that tracks simple -// equality and inequality constraints on symbolic values of GRState. +// equality and inequality constraints on symbolic values of ProgramState. // //===----------------------------------------------------------------------===// #include "SimpleConstraintManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableSet.h" @@ -170,7 +169,7 @@ public: return newRanges; } - void print(llvm::raw_ostream &os) const { + void print(raw_ostream &os) const { bool isFirst = true; os << "{ "; for (iterator i = begin(), e = end(); i != e; ++i) { @@ -196,55 +195,55 @@ typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy; namespace clang { namespace ento { template<> -struct GRStateTrait<ConstraintRange> - : public GRStatePartialTrait<ConstraintRangeTy> { - static inline void* GDMIndex() { return &ConstraintRangeIndex; } +struct ProgramStateTrait<ConstraintRange> + : public ProgramStatePartialTrait<ConstraintRangeTy> { + static inline void *GDMIndex() { return &ConstraintRangeIndex; } }; } } namespace { class RangeConstraintManager : public SimpleConstraintManager{ - RangeSet GetRange(const GRState *state, SymbolRef sym); + RangeSet GetRange(const ProgramState *state, SymbolRef sym); public: RangeConstraintManager(SubEngine &subengine) : SimpleConstraintManager(subengine) {} - const GRState *assumeSymNE(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const GRState *assumeSymEQ(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const GRState *assumeSymLT(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const GRState *assumeSymGT(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const GRState *assumeSymGE(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const GRState *assumeSymLE(const GRState* state, SymbolRef sym, + const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment); - const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const; + const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) const; // FIXME: Refactor into SimpleConstraintManager? - bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const { + bool isEqual(const ProgramState *St, SymbolRef sym, const llvm::APSInt& V) const { const llvm::APSInt *i = getSymVal(St, sym); return i ? *i == V : false; } - const GRState* removeDeadBindings(const GRState* St, SymbolReaper& SymReaper); + const ProgramState *removeDeadBindings(const ProgramState *St, SymbolReaper& SymReaper); - void print(const GRState* St, llvm::raw_ostream& Out, + void print(const ProgramState *St, raw_ostream &Out, const char* nl, const char *sep); private: @@ -253,12 +252,12 @@ private: } // end anonymous namespace -ConstraintManager* ento::CreateRangeConstraintManager(GRStateManager&, +ConstraintManager* ento::CreateRangeConstraintManager(ProgramStateManager&, SubEngine &subeng) { return new RangeConstraintManager(subeng); } -const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St, +const llvm::APSInt* RangeConstraintManager::getSymVal(const ProgramState *St, SymbolRef sym) const { const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym); return T ? T->getConcreteValue() : NULL; @@ -266,8 +265,8 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St, /// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. -const GRState* -RangeConstraintManager::removeDeadBindings(const GRState* state, +const ProgramState* +RangeConstraintManager::removeDeadBindings(const ProgramState *state, SymbolReaper& SymReaper) { ConstraintRangeTy CR = state->get<ConstraintRange>(); @@ -283,7 +282,7 @@ RangeConstraintManager::removeDeadBindings(const GRState* state, } RangeSet -RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) { +RangeConstraintManager::GetRange(const ProgramState *state, SymbolRef sym) { if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym)) return *V; @@ -306,8 +305,8 @@ RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) { // As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1, // UINT_MAX, 0, 1, and 2. -const GRState* -RangeConstraintManager::assumeSymNE(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymNE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { BasicValueFactory &BV = state->getBasicVals(); @@ -323,8 +322,8 @@ RangeConstraintManager::assumeSymNE(const GRState* state, SymbolRef sym, return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New); } -const GRState* -RangeConstraintManager::assumeSymEQ(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymEQ(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { // [Int-Adjustment, Int-Adjustment] @@ -334,8 +333,8 @@ RangeConstraintManager::assumeSymEQ(const GRState* state, SymbolRef sym, return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New); } -const GRState* -RangeConstraintManager::assumeSymLT(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymLT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { BasicValueFactory &BV = state->getBasicVals(); @@ -355,8 +354,8 @@ RangeConstraintManager::assumeSymLT(const GRState* state, SymbolRef sym, return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New); } -const GRState* -RangeConstraintManager::assumeSymGT(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymGT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { BasicValueFactory &BV = state->getBasicVals(); @@ -376,8 +375,8 @@ RangeConstraintManager::assumeSymGT(const GRState* state, SymbolRef sym, return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New); } -const GRState* -RangeConstraintManager::assumeSymGE(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymGE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { BasicValueFactory &BV = state->getBasicVals(); @@ -398,8 +397,8 @@ RangeConstraintManager::assumeSymGE(const GRState* state, SymbolRef sym, return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New); } -const GRState* -RangeConstraintManager::assumeSymLE(const GRState* state, SymbolRef sym, +const ProgramState* +RangeConstraintManager::assumeSymLE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& Int, const llvm::APSInt& Adjustment) { BasicValueFactory &BV = state->getBasicVals(); @@ -424,7 +423,7 @@ RangeConstraintManager::assumeSymLE(const GRState* state, SymbolRef sym, // Pretty-printing. //===------------------------------------------------------------------------===/ -void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out, +void RangeConstraintManager::print(const ProgramState *St, raw_ostream &Out, const char* nl, const char *sep) { ConstraintRangeTy Ranges = St->get<ConstraintRange>(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 23dd641..4b76cf1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -20,8 +20,8 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableMap.h" @@ -94,7 +94,7 @@ BindingKey BindingKey::Make(const MemRegion *R, Kind k) { namespace llvm { static inline - llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) { + raw_ostream &operator<<(raw_ostream &os, BindingKey K) { os << '(' << K.getRegion() << ',' << K.getOffset() << ',' << (K.isDirect() ? "direct" : "default") << ')'; @@ -157,7 +157,7 @@ public: return false; } - void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R); + void process(SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R); ~RegionStoreSubRegionMap() {} @@ -183,7 +183,7 @@ public: }; void -RegionStoreSubRegionMap::process(llvm::SmallVectorImpl<const SubRegion*> &WL, +RegionStoreSubRegionMap::process(SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R) { const MemRegion *superR = R->getSuperRegion(); if (add(superR, R)) @@ -196,7 +196,7 @@ class RegionStoreManager : public StoreManager { RegionBindings::Factory RBFactory; public: - RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f) + RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f) : StoreManager(mgr), Features(f), RBFactory(mgr.getAllocator()) {} @@ -236,13 +236,11 @@ public: // Binding values to regions. //===-------------------------------------------------------------------===// - StoreRef invalidateRegions(Store store, - const MemRegion * const *Begin, - const MemRegion * const *End, + StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions, const Expr *E, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, - InvalidatedRegions *Regions); + InvalidatedRegions *Invalidated); public: // Made public for helper classes. @@ -278,7 +276,7 @@ public: // Part of public interface to class. return StoreRef(addBinding(B, R, BindingKey::Default, V).getRootWithoutRetain(), *this); } - StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL, + StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL, const LocationContext *LC, SVal V); StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal); @@ -288,9 +286,9 @@ public: // Part of public interface to class. } /// BindStruct - Bind a compound value to a structure. - StoreRef BindStruct(Store store, const TypedRegion* R, SVal V); + StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V); - StoreRef BindArray(Store store, const TypedRegion* R, SVal V); + StoreRef BindArray(Store store, const TypedValueRegion* R, SVal V); /// KillStruct - Set the entire struct to unknown. StoreRef KillStruct(Store store, const TypedRegion* R, SVal DefaultVal); @@ -307,6 +305,8 @@ public: // Part of public interface to class. void decrementReferenceCount(Store store) { GetRegionBindings(store).manualRelease(); } + + bool includedInBindings(Store store, const MemRegion *region) const; //===------------------------------------------------------------------===// // Loading values from regions. @@ -333,9 +333,9 @@ public: // Part of public interface to class. SVal RetrieveVar(Store store, const VarRegion *R); - SVal RetrieveLazySymbol(const TypedRegion *R); + SVal RetrieveLazySymbol(const TypedValueRegion *R); - SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R, + SVal RetrieveFieldOrElementCommon(Store store, const TypedValueRegion *R, QualType Ty, const MemRegion *superR); SVal RetrieveLazyBinding(const MemRegion *lazyBindingRegion, @@ -346,15 +346,16 @@ public: // Part of public interface to class. /// struct s x, y; /// x = y; /// y's value is retrieved by this method. - SVal RetrieveStruct(Store store, const TypedRegion* R); + SVal RetrieveStruct(Store store, const TypedValueRegion* R); - SVal RetrieveArray(Store store, const TypedRegion* R); + SVal RetrieveArray(Store store, const TypedValueRegion* R); /// Used to lazily generate derived symbols for bindings that are defined /// implicitly by default bindings in a super region. Optional<SVal> RetrieveDerivedDefaultValue(RegionBindings B, const MemRegion *superR, - const TypedRegion *R, QualType Ty); + const TypedValueRegion *R, + QualType Ty); /// Get the state and region whose binding this region R corresponds to. std::pair<Store, const MemRegion*> @@ -371,17 +372,17 @@ public: // Part of public interface to class. /// removeDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); + SymbolReaper& SymReaper); - StoreRef enterStackFrame(const GRState *state, const StackFrameContext *frame); + StoreRef enterStackFrame(const ProgramState *state, + const StackFrameContext *frame); //===------------------------------------------------------------------===// // Region "extents". //===------------------------------------------------------------------===// // FIXME: This method will soon be eliminated; see the note in Store.h. - DefinedOrUnknownSVal getSizeInElements(const GRState *state, + DefinedOrUnknownSVal getSizeInElements(const ProgramState *state, const MemRegion* R, QualType EleTy); //===------------------------------------------------------------------===// @@ -392,7 +393,7 @@ public: // Part of public interface to class. return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store)); } - void print(Store store, llvm::raw_ostream& Out, const char* nl, + void print(Store store, raw_ostream &Out, const char* nl, const char *sep); void iterBindings(Store store, BindingsHandler& f) { @@ -416,12 +417,12 @@ public: // Part of public interface to class. // RegionStore creation. //===----------------------------------------------------------------------===// -StoreManager *ento::CreateRegionStoreManager(GRStateManager& StMgr) { +StoreManager *ento::CreateRegionStoreManager(ProgramStateManager& StMgr) { RegionStoreFeatures F = maximal_features_tag(); return new RegionStoreManager(StMgr, F); } -StoreManager *ento::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) { +StoreManager *ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) { RegionStoreFeatures F = minimal_features_tag(); F.enableFields(true); return new RegionStoreManager(StMgr, F); @@ -433,7 +434,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) { RegionBindings B = GetRegionBindings(store); RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap(); - llvm::SmallVector<const SubRegion*, 10> WL; + SmallVector<const SubRegion*, 10> WL; for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion())) @@ -461,7 +462,7 @@ protected: typedef BumpVector<BindingKey> RegionCluster; typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap; llvm::DenseMap<const RegionCluster*, unsigned> Visited; - typedef llvm::SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10> + typedef SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10> WorkList; BumpVectorContext BVC; @@ -477,7 +478,7 @@ protected: const bool includeGlobals; public: - ClusterAnalysis(RegionStoreManager &rm, GRStateManager &StateMgr, + ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr, RegionBindings b, const bool includeGlobals) : RM(rm), Ctx(StateMgr.getContext()), svalBuilder(StateMgr.getSValBuilder()), @@ -590,7 +591,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> StoreManager::InvalidatedRegions *Regions; public: invalidateRegionsWorker(RegionStoreManager &rm, - GRStateManager &stateMgr, + ProgramStateManager &stateMgr, RegionBindings b, const Expr *ex, unsigned count, StoreManager::InvalidatedSymbols &is, @@ -681,7 +682,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { if (!baseR->isBoundable()) return; - const TypedRegion *TR = cast<TypedRegion>(baseR); + const TypedValueRegion *TR = cast<TypedValueRegion>(baseR); QualType T = TR->getValueType(); // Invalidate the binding. @@ -718,21 +719,21 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { } StoreRef RegionStoreManager::invalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *E, + ArrayRef<const MemRegion *> Regions, const Expr *Ex, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, - InvalidatedRegions *Regions) { + InvalidatedRegions *Invalidated) { invalidateRegionsWorker W(*this, StateMgr, RegionStoreManager::GetRegionBindings(store), - Ex, Count, IS, Regions, invalidateGlobals); + Ex, Count, IS, Invalidated, invalidateGlobals); // Scan the bindings and generate the clusters. W.GenerateClusters(); - // Add I .. E to the worklist. - for ( ; I != E; ++I) + // Add the regions to the worklist. + for (ArrayRef<const MemRegion *>::iterator + I = Regions.begin(), E = Regions.end(); I != E; ++I) W.AddToWorkList(*I); W.RunWorkList(); @@ -752,8 +753,8 @@ StoreRef RegionStoreManager::invalidateRegions(Store store, // Even if there are no bindings in the global scope, we still need to // record that we touched it. - if (Regions) - Regions->push_back(GS); + if (Invalidated) + Invalidated->push_back(GS); } return StoreRef(B.getRootWithoutRetain(), *this); @@ -763,7 +764,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store, // Extents for regions. //===----------------------------------------------------------------------===// -DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, +DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const ProgramState *state, const MemRegion *R, QualType EleTy) { SVal Size = cast<SubRegion>(R)->getExtent(svalBuilder); @@ -803,7 +804,7 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { return UnknownVal(); const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion(); - const TypedRegion* ArrayR = dyn_cast<TypedRegion>(R); + const TypedValueRegion* ArrayR = dyn_cast<TypedValueRegion>(R); if (!ArrayR) return UnknownVal(); @@ -852,7 +853,7 @@ Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B, Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, const MemRegion *R) { if (R->isBoundable()) - if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) if (TR->getValueType()->isUnionType()) return UnknownVal(); @@ -890,13 +891,12 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } if (isa<CodeTextRegion>(MR)) { - assert(0 && "Why load from a code text region?"); - return UnknownVal(); + llvm_unreachable("Why load from a code text region?"); } // FIXME: Perhaps this method should just take a 'const MemRegion*' argument // instead of 'Loc', and have the other Loc cases handled at a higher level. - const TypedRegion *R = cast<TypedRegion>(MR); + const TypedValueRegion *R = cast<TypedValueRegion>(MR); QualType RTy = R->getValueType(); // FIXME: We should eventually handle funny addressing. e.g.: @@ -1042,6 +1042,10 @@ SVal RegionStoreManager::RetrieveElement(Store store, SVal Idx = R->getIndex(); if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) { int64_t i = CI->getValue().getSExtValue(); + // Abort on string underrun. This can be possible by arbitrary + // clients of RetrieveElement(). + if (i < 0) + return UndefinedVal(); int64_t byteLength = Str->getByteLength(); // Technically, only i == byteLength is guaranteed to be null. // However, such overflows should be caught before reaching this point; @@ -1068,7 +1072,8 @@ SVal RegionStoreManager::RetrieveElement(Store store, if (!O.getRegion()) return UnknownVal(); - if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) { + if (const TypedValueRegion *baseR = + dyn_cast_or_null<TypedValueRegion>(O.getRegion())) { QualType baseT = baseR->getValueType(); if (baseT->isScalarType()) { QualType elemT = R->getElementType(); @@ -1106,7 +1111,7 @@ SVal RegionStoreManager::RetrieveField(Store store, Optional<SVal> RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B, const MemRegion *superR, - const TypedRegion *R, + const TypedValueRegion *R, QualType Ty) { if (const Optional<SVal> &D = getDefaultBinding(B, superR)) { @@ -1124,7 +1129,7 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B, if (isa<nonloc::LazyCompoundVal>(val)) return Optional<SVal>(); - assert(0 && "Unknown default value"); + llvm_unreachable("Unknown default value"); } return Optional<SVal>(); @@ -1140,7 +1145,7 @@ SVal RegionStoreManager::RetrieveLazyBinding(const MemRegion *lazyBindingRegion, } SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, - const TypedRegion *R, + const TypedValueRegion *R, QualType Ty, const MemRegion *superR) { @@ -1175,7 +1180,8 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. - if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) { + if (const TypedValueRegion *typedSuperR = + dyn_cast<TypedValueRegion>(superR)) { if (typedSuperR->getValueType()->isVectorType()) return UnknownVal(); } @@ -1264,22 +1270,41 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { return UndefinedVal(); } -SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { +SVal RegionStoreManager::RetrieveLazySymbol(const TypedValueRegion *R) { // All other values are symbolic. return svalBuilder.getRegionValueSymbolVal(R); } -SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { +SVal RegionStoreManager::RetrieveStruct(Store store, + const TypedValueRegion* R) { QualType T = R->getValueType(); assert(T->isStructureOrClassType()); return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); } -SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) { +SVal RegionStoreManager::RetrieveArray(Store store, + const TypedValueRegion * R) { assert(Ctx.getAsConstantArrayType(R->getValueType())); return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); } +bool RegionStoreManager::includedInBindings(Store store, + const MemRegion *region) const { + RegionBindings B = GetRegionBindings(store); + region = region->getBaseRegion(); + + for (RegionBindings::iterator it = B.begin(), ei = B.end(); it != ei; ++it) { + const BindingKey &K = it.getKey(); + if (region == K.getRegion()) + return true; + const SVal &D = it.getData(); + if (const MemRegion *r = D.getAsRegion()) + if (r == region) + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // Binding values to regions. //===----------------------------------------------------------------------===// @@ -1302,14 +1327,14 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) { const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); // Check if the region is a struct region. - if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) + if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) if (TR->getValueType()->isStructureOrClassType()) return BindStruct(store, TR, V); if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { if (ER->getIndex().isZeroConstant()) { - if (const TypedRegion *superR = - dyn_cast<TypedRegion>(ER->getSuperRegion())) { + if (const TypedValueRegion *superR = + dyn_cast<TypedValueRegion>(ER->getSuperRegion())) { QualType superTy = superR->getValueType(); // For now, just invalidate the fields of the struct/union/class. // This is for test rdar_test_7185607 in misc-ps-region-store.m. @@ -1389,7 +1414,7 @@ StoreRef RegionStoreManager::setImplicitDefaultValue(Store store, V).getRootWithoutRetain(), *this); } -StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R, +StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R, SVal Init) { const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType())); @@ -1448,7 +1473,7 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R, return newStore; } -StoreRef RegionStoreManager::BindStruct(Store store, const TypedRegion* R, +StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R, SVal V) { if (!Features.supportsFields()) @@ -1458,9 +1483,9 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedRegion* R, assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs<RecordType>(); - RecordDecl* RD = RT->getDecl(); + RecordDecl *RD = RT->getDecl(); - if (!RD->isDefinition()) + if (!RD->isCompleteDefinition()) return StoreRef(store, *this); // Handle lazy compound values. @@ -1611,12 +1636,12 @@ RegionBindings RegionStoreManager::removeBinding(RegionBindings B, namespace { class removeDeadBindingsWorker : public ClusterAnalysis<removeDeadBindingsWorker> { - llvm::SmallVector<const SymbolicRegion*, 12> Postponed; + SmallVector<const SymbolicRegion*, 12> Postponed; SymbolReaper &SymReaper; const StackFrameContext *CurrentLCtx; public: - removeDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr, + removeDeadBindingsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, RegionBindings b, SymbolReaper &symReaper, const StackFrameContext *LCtx) : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, @@ -1736,7 +1761,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() { // having done a scan. bool changed = false; - for (llvm::SmallVectorImpl<const SymbolicRegion*>::iterator + for (SmallVectorImpl<const SymbolicRegion*>::iterator I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) { if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) { if (SymReaper.isLive(SR->getSymbol())) { @@ -1751,17 +1776,16 @@ bool removeDeadBindingsWorker::UpdatePostponed() { StoreRef RegionStoreManager::removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) -{ + SymbolReaper& SymReaper) { RegionBindings B = GetRegionBindings(store); removeDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx); W.GenerateClusters(); // Enqueue the region roots onto the worklist. - for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(), - E=RegionRoots.end(); I!=E; ++I) + for (SymbolReaper::region_iterator I = SymReaper.region_begin(), + E = SymReaper.region_end(); I != E; ++I) { W.AddToWorkList(*I); + } do W.RunWorkList(); while (W.UpdatePostponed()); @@ -1792,7 +1816,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, } -StoreRef RegionStoreManager::enterStackFrame(const GRState *state, +StoreRef RegionStoreManager::enterStackFrame(const ProgramState *state, const StackFrameContext *frame) { FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl()); FunctionDecl::param_const_iterator PI = FD->param_begin(), @@ -1831,7 +1855,7 @@ StoreRef RegionStoreManager::enterStackFrame(const GRState *state, // Utility methods. //===----------------------------------------------------------------------===// -void RegionStoreManager::print(Store store, llvm::raw_ostream& OS, +void RegionStoreManager::print(Store store, raw_ostream &OS, const char* nl, const char *sep) { RegionBindings B = GetRegionBindings(store); OS << "Store (direct and default bindings):" << nl; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index 71f2b4a..ebf7ae2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -15,7 +15,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" using namespace clang; @@ -70,7 +70,7 @@ SVal SValBuilder::convertToArrayIndex(SVal val) { } DefinedOrUnknownSVal -SValBuilder::getRegionValueSymbolVal(const TypedRegion* region) { +SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { QualType T = region->getValueType(); if (!SymbolManager::canSymbolicate(T)) @@ -133,7 +133,7 @@ DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag, DefinedOrUnknownSVal SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, - const TypedRegion *region) { + const TypedValueRegion *region) { QualType T = region->getValueType(); if (!SymbolManager::canSymbolicate(T)) @@ -147,7 +147,7 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* func) { +DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) { return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func)); } @@ -162,7 +162,7 @@ DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block, //===----------------------------------------------------------------------===// -SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op, +SVal SValBuilder::evalBinOp(const ProgramState *state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type) { if (lhs.isUndef() || rhs.isUndef()) @@ -190,7 +190,7 @@ SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op, return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type); } -DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *state, +DefinedOrUnknownSVal SValBuilder::evalEQ(const ProgramState *state, DefinedOrUnknownSVal lhs, DefinedOrUnknownSVal rhs) { return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs, @@ -213,8 +213,13 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { return UnknownVal(); // Check for casts from integers to integers. - if (castTy->isIntegerType() && originalTy->isIntegerType()) - return evalCastFromNonLoc(cast<NonLoc>(val), castTy); + if (castTy->isIntegerType() && originalTy->isIntegerType()) { + if (isa<Loc>(val)) + // This can be a cast to ObjC property of type int. + return evalCastFromLoc(cast<Loc>(val), castTy); + else + return evalCastFromNonLoc(cast<NonLoc>(val), castTy); + } // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::isLocType(originalTy)) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp index 4614e34..b5980b9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -12,14 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/IdentifierTable.h" - using namespace clang; using namespace ento; -using llvm::dyn_cast; -using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// @@ -146,7 +143,7 @@ SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) { while (!isa<SymbolData>(itr.back())) expand(); } -SVal::symbol_iterator& SVal::symbol_iterator::operator++() { +SVal::symbol_iterator &SVal::symbol_iterator::operator++() { assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); assert(isa<SymbolData>(itr.back())); itr.pop_back(); @@ -174,7 +171,7 @@ void SVal::symbol_iterator::expand() { return; } - assert(false && "unhandled expansion case"); + llvm_unreachable("unhandled expansion case"); } const void *nonloc::LazyCompoundVal::getStore() const { @@ -270,7 +267,7 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals, void SVal::dump() const { dumpToStream(llvm::errs()); } -void SVal::dumpToStream(llvm::raw_ostream& os) const { +void SVal::dumpToStream(raw_ostream &os) const { switch (getBaseKind()) { case UnknownKind: os << "Unknown"; @@ -289,7 +286,7 @@ void SVal::dumpToStream(llvm::raw_ostream& os) const { } } -void NonLoc::dumpToStream(llvm::raw_ostream& os) const { +void NonLoc::dumpToStream(raw_ostream &os) const { switch (getSubKind()) { case nonloc::ConcreteIntKind: { const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this); @@ -344,7 +341,7 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const { } } -void Loc::dumpToStream(llvm::raw_ostream& os) const { +void Loc::dumpToStream(raw_ostream &os) const { switch (getSubKind()) { case loc::ConcreteIntKind: os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)"; @@ -372,7 +369,6 @@ void Loc::dumpToStream(llvm::raw_ostream& os) const { break; } default: - assert(false && "Pretty-printing not implemented for this Loc."); - break; + llvm_unreachable("Pretty-printing not implemented for this Loc."); } } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 20762e0..79d8b8b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -14,7 +14,7 @@ #include "SimpleConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" namespace clang { @@ -56,7 +56,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const { return true; } -const GRState *SimpleConstraintManager::assume(const GRState *state, +const ProgramState *SimpleConstraintManager::assume(const ProgramState *state, DefinedSVal Cond, bool Assumption) { if (isa<NonLoc>(Cond)) @@ -65,13 +65,13 @@ const GRState *SimpleConstraintManager::assume(const GRState *state, return assume(state, cast<Loc>(Cond), Assumption); } -const GRState *SimpleConstraintManager::assume(const GRState *state, Loc cond, +const ProgramState *SimpleConstraintManager::assume(const ProgramState *state, Loc cond, bool assumption) { state = assumeAux(state, cond, assumption); return SU.processAssume(state, cond, assumption); } -const GRState *SimpleConstraintManager::assumeAux(const GRState *state, +const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state, Loc Cond, bool Assumption) { BasicValueFactory &BasicVals = state->getBasicVals(); @@ -113,7 +113,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state, } // end switch } -const GRState *SimpleConstraintManager::assume(const GRState *state, +const ProgramState *SimpleConstraintManager::assume(const ProgramState *state, NonLoc cond, bool assumption) { state = assumeAux(state, cond, assumption); @@ -125,7 +125,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { // the only place it's used. (This code was copied from SimpleSValBuilder.cpp.) switch (op) { default: - assert(false && "Invalid opcode."); + llvm_unreachable("Invalid opcode."); case BO_LT: return BO_GE; case BO_GT: return BO_LE; case BO_LE: return BO_GT; @@ -135,7 +135,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { } } -const GRState *SimpleConstraintManager::assumeAux(const GRState *state, +const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state, NonLoc Cond, bool Assumption) { @@ -152,7 +152,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state, switch (Cond.getSubKind()) { default: - assert(false && "'Assume' not implemented for this NonLoc"); + llvm_unreachable("'Assume' not implemented for this NonLoc"); case nonloc::SymbolValKind: { nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond); @@ -202,7 +202,7 @@ const GRState *SimpleConstraintManager::assumeAux(const GRState *state, } // end switch } -const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state, +const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *state, const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt& Int) { @@ -256,7 +256,7 @@ const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state, // be of the same type as the symbol, which is not always correct. Really the // comparisons should be performed using the Int's type, then mapped back to // the symbol's range of values. - GRStateManager &StateMgr = state->getStateManager(); + ProgramStateManager &StateMgr = state->getStateManager(); ASTContext &Ctx = StateMgr.getContext(); QualType T = Sym->getType(Ctx); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h index a2952af..d4295d4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" namespace clang { @@ -33,14 +33,14 @@ public: bool canReasonAbout(SVal X) const; - const GRState *assume(const GRState *state, DefinedSVal Cond, + const ProgramState *assume(const ProgramState *state, DefinedSVal Cond, bool Assumption); - const GRState *assume(const GRState *state, Loc Cond, bool Assumption); + const ProgramState *assume(const ProgramState *state, Loc Cond, bool Assumption); - const GRState *assume(const GRState *state, NonLoc Cond, bool Assumption); + const ProgramState *assume(const ProgramState *state, NonLoc Cond, bool Assumption); - const GRState *assumeSymRel(const GRState *state, + const ProgramState *assumeSymRel(const ProgramState *state, const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt& Int); @@ -53,27 +53,27 @@ protected: // Each of these is of the form "$sym+Adj <> V", where "<>" is the comparison // operation for the method being invoked. - virtual const GRState *assumeSymNE(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; - virtual const GRState *assumeSymEQ(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; - virtual const GRState *assumeSymLT(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; - virtual const GRState *assumeSymGT(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; - virtual const GRState *assumeSymLE(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; - virtual const GRState *assumeSymGE(const GRState *state, SymbolRef sym, + virtual const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym, const llvm::APSInt& V, const llvm::APSInt& Adjustment) = 0; @@ -81,9 +81,9 @@ protected: // Internal implementation. //===------------------------------------------------------------------===// - const GRState *assumeAux(const GRState *state, Loc Cond,bool Assumption); + const ProgramState *assumeAux(const ProgramState *state, Loc Cond,bool Assumption); - const GRState *assumeAux(const GRState *state, NonLoc Cond, bool Assumption); + const ProgramState *assumeAux(const ProgramState *state, NonLoc Cond, bool Assumption); }; } // end GR namespace diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 80c18a3..bd63ecf 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" using namespace clang; using namespace ento; @@ -25,22 +25,22 @@ protected: public: SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, - GRStateManager &stateMgr) + ProgramStateManager &stateMgr) : SValBuilder(alloc, context, stateMgr) {} virtual ~SimpleSValBuilder() {} virtual SVal evalMinus(NonLoc val); virtual SVal evalComplement(NonLoc val); - virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op, + virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy); - virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op, + virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy); - virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op, + virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy); /// getKnownValue - evaluates a given SVal. If the SVal has only one possible /// (integer) value, that value is returned. Otherwise, returns NULL. - virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V); + virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal V); SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &RHS, QualType resultTy); @@ -49,7 +49,7 @@ public: SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, - GRStateManager &stateMgr) { + ProgramStateManager &stateMgr) { return new SimpleSValBuilder(alloc, context, stateMgr); } @@ -171,7 +171,7 @@ SVal SimpleSValBuilder::evalComplement(NonLoc X) { static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { switch (op) { default: - assert(false && "Invalid opcode."); + llvm_unreachable("Invalid opcode."); case BO_LT: return BO_GE; case BO_GT: return BO_LE; case BO_LE: return BO_GT; @@ -184,7 +184,7 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) { switch (op) { default: - assert(false && "Invalid opcode."); + llvm_unreachable("Invalid opcode."); case BO_LT: return BO_GT; case BO_GT: return BO_LT; case BO_LE: return BO_GE; @@ -270,7 +270,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, return makeNonLoc(LHS, op, RHS, resultTy); } -SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, +SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy) { @@ -347,8 +347,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, break; case BO_LAnd: case BO_LOr: - assert(false && "Logical operators handled by branching logic."); - return UnknownVal(); + llvm_unreachable("Logical operators handled by branching logic."); case BO_Assign: case BO_MulAssign: case BO_DivAssign: @@ -361,12 +360,10 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, case BO_XorAssign: case BO_OrAssign: case BO_Comma: - assert(false && "'=' and ',' operators handled by ExprEngine."); - return UnknownVal(); + llvm_unreachable("'=' and ',' operators handled by ExprEngine."); case BO_PtrMemD: case BO_PtrMemI: - assert(false && "Pointer arithmetic not handled here."); - return UnknownVal(); + llvm_unreachable("Pointer arithmetic not handled here."); case BO_LT: case BO_GT: case BO_LE: @@ -539,7 +536,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, } // FIXME: all this logic will change if/when we have MemRegion::getLocation(). -SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, +SVal SimpleSValBuilder::evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy) { @@ -556,8 +553,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, if (lhs == rhs) { switch (op) { default: - assert(false && "Unimplemented operation for two identical values"); - return UnknownVal(); + llvm_unreachable("Unimplemented operation for two identical values"); case BO_Sub: return makeZeroVal(resultTy); case BO_EQ: @@ -573,8 +569,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, switch (lhs.getSubKind()) { default: - assert(false && "Ordering not implemented for this Loc."); - return UnknownVal(); + llvm_unreachable("Ordering not implemented for this Loc."); case loc::GotoLabelKind: // The only thing we know about labels is that they're non-null. @@ -827,7 +822,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, return makeTruthVal(!leftFirst, resultTy); } - assert(false && "Fields not found in parent record's definition"); + llvm_unreachable("Fields not found in parent record's definition"); } // If we get here, we have no way of comparing the regions. @@ -836,7 +831,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, } } -SVal SimpleSValBuilder::evalBinOpLN(const GRState *state, +SVal SimpleSValBuilder::evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy) { @@ -930,7 +925,7 @@ SVal SimpleSValBuilder::evalBinOpLN(const GRState *state, return UnknownVal(); } -const llvm::APSInt *SimpleSValBuilder::getKnownValue(const GRState *state, +const llvm::APSInt *SimpleSValBuilder::getKnownValue(const ProgramState *state, SVal V) { if (V.isUnknownOrUndef()) return NULL; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp index b936738..48a6f4f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -12,17 +12,17 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/CharUnits.h" using namespace clang; using namespace ento; -StoreManager::StoreManager(GRStateManager &stateMgr) +StoreManager::StoreManager(ProgramStateManager &stateMgr) : svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr), MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {} -StoreRef StoreManager::enterStackFrame(const GRState *state, +StoreRef StoreManager::enterStackFrame(const ProgramState *state, const StackFrameContext *frame) { return StoreRef(state->getStore(), *this); } @@ -57,7 +57,7 @@ const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) { - ASTContext& Ctx = StateMgr.getContext(); + ASTContext &Ctx = StateMgr.getContext(); // Handle casts to Objective-C objects. if (CastToTy->isObjCObjectPointerType()) @@ -87,7 +87,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Handle casts from compatible types. if (R->isBoundable()) - if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) { + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); if (CanonPointeeTy == ObjTy) return R; @@ -103,8 +103,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) case MemRegion::UnknownSpaceRegionKind: case MemRegion::NonStaticGlobalSpaceRegionKind: case MemRegion::StaticGlobalSpaceRegionKind: { - assert(0 && "Invalid region cast"); - break; + llvm_unreachable("Invalid region cast"); } case MemRegion::FunctionTextRegionKind: @@ -157,7 +156,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base // region. If so, just return the base region. - if (const TypedRegion *TR = dyn_cast<TypedRegion>(baseR)) { + if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(baseR)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); if (CanonPointeeTy == ObjTy) @@ -203,15 +202,14 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) } } - assert(0 && "unreachable"); - return 0; + llvm_unreachable("unreachable"); } /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. -SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, +SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, QualType castTy, bool performTestOnly) { if (castTy.isNull()) @@ -237,7 +235,7 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, return V; } -SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) { +SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { if (Base.isUnknownOrUndef()) return Base; @@ -261,8 +259,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) { return Base; default: - assert(0 && "Unhandled Base."); - return Base; + llvm_unreachable("Unhandled Base."); } // NOTE: We must have this check first because ObjCIvarDecl is a subclass @@ -336,3 +333,6 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR, Ctx)); } + +StoreManager::BindingsHandler::~BindingsHandler() {} + diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index c1ca1cf..b843ab1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -15,6 +15,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -24,11 +25,10 @@ void SymExpr::dump() const { dumpToStream(llvm::errs()); } -static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { +static void print(raw_ostream &os, BinaryOperator::Opcode Op) { switch (Op) { default: - assert(false && "operator printing not implemented"); - break; + llvm_unreachable("operator printing not implemented"); case BO_Mul: os << '*' ; break; case BO_Div: os << '/' ; break; case BO_Rem: os << '%' ; break; @@ -48,7 +48,7 @@ static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { } } -void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const { +void SymIntExpr::dumpToStream(raw_ostream &os) const { os << '('; getLHS()->dumpToStream(os); os << ") "; @@ -57,7 +57,7 @@ void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const { if (getRHS().isUnsigned()) os << 'U'; } -void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const { +void SymSymExpr::dumpToStream(raw_ostream &os) const { os << '('; getLHS()->dumpToStream(os); os << ") "; @@ -66,33 +66,33 @@ void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const { os << ')'; } -void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const { +void SymbolConjured::dumpToStream(raw_ostream &os) const { os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}'; } -void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const { +void SymbolDerived::dumpToStream(raw_ostream &os) const { os << "derived_$" << getSymbolID() << '{' << getParentSymbol() << ',' << getRegion() << '}'; } -void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const { +void SymbolExtent::dumpToStream(raw_ostream &os) const { os << "extent_$" << getSymbolID() << '{' << getRegion() << '}'; } -void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const { +void SymbolMetadata::dumpToStream(raw_ostream &os) const { os << "meta_$" << getSymbolID() << '{' << getRegion() << ',' << T.getAsString() << '}'; } -void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const { +void SymbolRegionValue::dumpToStream(raw_ostream &os) const { os << "reg_$" << getSymbolID() << "<" << R << ">"; } const SymbolRegionValue* -SymbolManager::getRegionValueSymbol(const TypedRegion* R) { +SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { llvm::FoldingSetNodeID profile; SymbolRegionValue::Profile(profile, R); - void* InsertPos; + void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>(); @@ -105,12 +105,12 @@ SymbolManager::getRegionValueSymbol(const TypedRegion* R) { } const SymbolConjured* -SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count, - const void* SymbolTag) { +SymbolManager::getConjuredSymbol(const Stmt *E, QualType T, unsigned Count, + const void *SymbolTag) { llvm::FoldingSetNodeID profile; SymbolConjured::Profile(profile, E, T, Count, SymbolTag); - void* InsertPos; + void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>(); @@ -124,11 +124,11 @@ SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count, const SymbolDerived* SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, - const TypedRegion *R) { + const TypedValueRegion *R) { llvm::FoldingSetNodeID profile; SymbolDerived::Profile(profile, parentSymbol, R); - void* InsertPos; + void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>(); @@ -144,7 +144,7 @@ const SymbolExtent* SymbolManager::getExtentSymbol(const SubRegion *R) { llvm::FoldingSetNodeID profile; SymbolExtent::Profile(profile, R); - void* InsertPos; + void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>(); @@ -157,12 +157,12 @@ SymbolManager::getExtentSymbol(const SubRegion *R) { } const SymbolMetadata* -SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt* S, QualType T, - unsigned Count, const void* SymbolTag) { +SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T, + unsigned Count, const void *SymbolTag) { llvm::FoldingSetNodeID profile; SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag); - void* InsertPos; + void *InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>(); @@ -214,11 +214,11 @@ QualType SymbolConjured::getType(ASTContext&) const { return T; } -QualType SymbolDerived::getType(ASTContext& Ctx) const { +QualType SymbolDerived::getType(ASTContext &Ctx) const { return R->getValueType(); } -QualType SymbolExtent::getType(ASTContext& Ctx) const { +QualType SymbolExtent::getType(ASTContext &Ctx) const { return Ctx.getSizeType(); } @@ -226,11 +226,17 @@ QualType SymbolMetadata::getType(ASTContext&) const { return T; } -QualType SymbolRegionValue::getType(ASTContext& C) const { +QualType SymbolRegionValue::getType(ASTContext &C) const { return R->getValueType(); } -SymbolManager::~SymbolManager() {} +SymbolManager::~SymbolManager() { + for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(), + E = SymbolDependencies.end(); I != E; ++I) { + delete I->second; + } + +} bool SymbolManager::canSymbolicate(QualType T) { T = T.getCanonicalType(); @@ -247,9 +253,53 @@ bool SymbolManager::canSymbolicate(QualType T) { return false; } +void SymbolManager::addSymbolDependency(const SymbolRef Primary, + const SymbolRef Dependent) { + SymbolDependTy::iterator I = SymbolDependencies.find(Primary); + SymbolRefSmallVectorTy *dependencies = 0; + if (I == SymbolDependencies.end()) { + dependencies = new SymbolRefSmallVectorTy(); + SymbolDependencies[Primary] = dependencies; + } else { + dependencies = I->second; + } + dependencies->push_back(Dependent); +} + +const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( + const SymbolRef Primary) { + SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); + if (I == SymbolDependencies.end()) + return 0; + return I->second; +} + +void SymbolReaper::markDependentsLive(SymbolRef sym) { + // Do not mark dependents more then once. + SymbolMapTy::iterator LI = TheLiving.find(sym); + assert(LI != TheLiving.end() && "The primary symbol is not live."); + if (LI->second == HaveMarkedDependents) + return; + LI->second = HaveMarkedDependents; + + if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) { + for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(), + E = Deps->end(); I != E; ++I) { + if (TheLiving.find(*I) != TheLiving.end()) + continue; + markLive(*I); + } + } +} + void SymbolReaper::markLive(SymbolRef sym) { - TheLiving.insert(sym); + TheLiving[sym] = NotProcessed; TheDead.erase(sym); + markDependentsLive(sym); +} + +void SymbolReaper::markLive(const MemRegion *region) { + RegionRoots.insert(region); } void SymbolReaper::markInUse(SymbolRef sym) { @@ -265,14 +315,17 @@ bool SymbolReaper::maybeDead(SymbolRef sym) { return true; } -static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) { +bool SymbolReaper::isLiveRegion(const MemRegion *MR) { + if (RegionRoots.count(MR)) + return true; + MR = MR->getBaseRegion(); if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) - return Reaper.isLive(SR->getSymbol()); + return isLive(SR->getSymbol()); if (const VarRegion *VR = dyn_cast<VarRegion>(MR)) - return Reaper.isLive(VR); + return isLive(VR, true); // FIXME: This is a gross over-approximation. What we really need is a way to // tell if anything still refers to this region. Unlike SymbolicRegions, @@ -291,8 +344,10 @@ static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) { } bool SymbolReaper::isLive(SymbolRef sym) { - if (TheLiving.count(sym)) + if (TheLiving.count(sym)) { + markDependentsLive(sym); return true; + } if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) { if (isLive(derived->getParentSymbol())) { @@ -303,7 +358,7 @@ bool SymbolReaper::isLive(SymbolRef sym) { } if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) { - if (IsLiveRegion(*this, extent->getRegion())) { + if (isLiveRegion(extent->getRegion())) { markLive(sym); return true; } @@ -312,7 +367,7 @@ bool SymbolReaper::isLive(SymbolRef sym) { if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) { if (MetadataInUse.count(sym)) { - if (IsLiveRegion(*this, metadata->getRegion())) { + if (isLiveRegion(metadata->getRegion())) { markLive(sym); MetadataInUse.erase(sym); return true; @@ -326,18 +381,38 @@ bool SymbolReaper::isLive(SymbolRef sym) { return isa<SymbolRegionValue>(sym); } -bool SymbolReaper::isLive(const Stmt* ExprVal) const { - return LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> - isLive(Loc, ExprVal); +bool SymbolReaper::isLive(const Stmt *ExprVal) const { + return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal); } -bool SymbolReaper::isLive(const VarRegion *VR) const { +bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ const StackFrameContext *VarContext = VR->getStackFrame(); const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); - if (VarContext == CurrentContext) - return LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> - isLive(Loc, VR->getDecl()); + if (VarContext == CurrentContext) { + if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl())) + return true; + + if (!includeStoreBindings) + return false; + + unsigned &cachedQuery = + const_cast<SymbolReaper*>(this)->includedRegionCache[VR]; + + if (cachedQuery) { + return cachedQuery == 1; + } + + // Query the store to see if the region occurs in any live bindings. + if (Store store = reapedStore.getStore()) { + bool hasRegion = + reapedStore.getStoreManager().includedInBindings(store, VR); + cachedQuery = hasRegion ? 1 : 2; + return hasRegion; + } + + return false; + } return VarContext->isParentOf(CurrentContext); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp index 230b6a10..3543f7f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/raw_ostream.h" @@ -23,19 +23,19 @@ namespace { /// \brief Simple path diagnostic client used for outputting as diagnostic notes /// the sequence of events. -class TextPathDiagnostics : public PathDiagnosticClient { +class TextPathDiagnostics : public PathDiagnosticConsumer { const std::string OutputFile; - Diagnostic &Diag; + DiagnosticsEngine &Diag; public: - TextPathDiagnostics(const std::string& output, Diagnostic &diag) + TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag) : OutputFile(output), Diag(diag) {} - void HandlePathDiagnostic(const PathDiagnostic* D); + void HandlePathDiagnosticImpl(const PathDiagnostic* D); - void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) { } + void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { } - virtual llvm::StringRef getName() const { + virtual StringRef getName() const { return "TextPathDiagnostics"; } @@ -47,13 +47,13 @@ public: } // end anonymous namespace -PathDiagnosticClient* -ento::createTextPathDiagnosticClient(const std::string& out, +PathDiagnosticConsumer* +ento::createTextPathDiagnosticConsumer(const std::string& out, const Preprocessor &PP) { return new TextPathDiagnostics(out, PP.getDiagnostics()); } -void TextPathDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { +void TextPathDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { if (!D) return; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index b8dbb54..34a358f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -25,8 +25,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" -#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -43,15 +42,15 @@ using namespace ento; static ExplodedNode::Auditor* CreateUbiViz(); //===----------------------------------------------------------------------===// -// Special PathDiagnosticClients. +// Special PathDiagnosticConsumers. //===----------------------------------------------------------------------===// -static PathDiagnosticClient* -createPlistHTMLDiagnosticClient(const std::string& prefix, +static PathDiagnosticConsumer* +createPlistHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP) { - PathDiagnosticClient *PD = - createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP); - return createPlistDiagnosticClient(prefix, PP, PD); + PathDiagnosticConsumer *PD = + createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP); + return createPlistDiagnosticConsumer(prefix, PP, PD); } //===----------------------------------------------------------------------===// @@ -62,13 +61,14 @@ namespace { class AnalysisConsumer : public ASTConsumer { public: - ASTContext* Ctx; + ASTContext *Ctx; const Preprocessor &PP; const std::string OutDir; AnalyzerOptions Opts; + ArrayRef<std::string> Plugins; // PD is owned by AnalysisManager. - PathDiagnosticClient *PD; + PathDiagnosticConsumer *PD; StoreManagerCreator CreateStoreMgr; ConstraintManagerCreator CreateConstraintMgr; @@ -78,14 +78,14 @@ public: AnalysisConsumer(const Preprocessor& pp, const std::string& outdir, - const AnalyzerOptions& opts) - : Ctx(0), PP(pp), OutDir(outdir), - Opts(opts), PD(0) { + const AnalyzerOptions& opts, + ArrayRef<std::string> plugins) + : Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) { DigestAnalyzerOptions(); } void DigestAnalyzerOptions() { - // Create the PathDiagnosticClient. + // Create the PathDiagnosticConsumer. if (!OutDir.empty()) { switch (Opts.AnalysisDiagOpt) { default: @@ -96,13 +96,13 @@ public: } else if (Opts.AnalysisDiagOpt == PD_TEXT) { // Create the text client even without a specified output file since // it just uses diagnostic notes. - PD = createTextPathDiagnosticClient("", PP); + PD = createTextPathDiagnosticConsumer("", PP); } // Create the analyzer component creators. switch (Opts.AnalysisStoreOpt) { default: - assert(0 && "Unknown store manager."); + llvm_unreachable("Unknown store manager."); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ case NAME##Model: CreateStoreMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" @@ -110,7 +110,7 @@ public: switch (Opts.AnalysisConstraintsOpt) { default: - assert(0 && "Unknown store manager."); + llvm_unreachable("Unknown store manager."); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ case NAME##Model: CreateConstraintMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" @@ -128,7 +128,7 @@ public: if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { const NamedDecl *ND = cast<NamedDecl>(D); - llvm::errs() << ' ' << ND << '\n'; + llvm::errs() << ' ' << *ND << '\n'; } else if (isa<BlockDecl>(D)) { llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" @@ -143,8 +143,8 @@ public: virtual void Initialize(ASTContext &Context) { Ctx = &Context; - checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(), - PP.getDiagnostics())); + checkerMgr.reset(createCheckerManager(Opts, PP.getLangOptions(), Plugins, + PP.getDiagnostics())); Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, @@ -152,7 +152,7 @@ public: /* Indexer */ 0, Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, - Opts.PurgeDead, Opts.EagerlyAssume, + Opts.AnalysisPurgeOpt, Opts.EagerlyAssume, Opts.TrimGraph, Opts.InlineCall, Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, Opts.CFGAddInitializers, @@ -161,6 +161,7 @@ public: virtual void HandleTranslationUnit(ASTContext &C); void HandleDeclContext(ASTContext &C, DeclContext *dc); + void HandleDeclContextDecl(ASTContext &C, Decl *D); void HandleCode(Decl *D); }; @@ -171,61 +172,67 @@ public: //===----------------------------------------------------------------------===// void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { - BugReporter BR(*Mgr); for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end(); I != E; ++I) { - Decl *D = *I; + HandleDeclContextDecl(C, *I); + } +} + +void AnalysisConsumer::HandleDeclContextDecl(ASTContext &C, Decl *D) { + { // Handle callbacks for arbitrary decls. + BugReporter BR(*Mgr); checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR); + } - switch (D->getKind()) { - case Decl::Namespace: { - HandleDeclContext(C, cast<NamespaceDecl>(D)); - break; + switch (D->getKind()) { + case Decl::Namespace: { + HandleDeclContext(C, cast<NamespaceDecl>(D)); + break; + } + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: + case Decl::Function: { + FunctionDecl *FD = cast<FunctionDecl>(D); + // We skip function template definitions, as their semantics is + // only determined when they are instantiated. + if (FD->isThisDeclarationADefinition() && + !FD->isDependentContext()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) + break; + DisplayFunction(FD); + HandleCode(FD); } - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - case Decl::CXXMethod: - case Decl::Function: { - FunctionDecl* FD = cast<FunctionDecl>(D); - // We skip function template definitions, as their semantics is - // only determined when they are instantiated. - if (FD->isThisDeclarationADefinition() && - !FD->isDependentContext()) { + break; + } + + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: { + ObjCImplDecl *ID = cast<ObjCImplDecl>(D); + HandleCode(ID); + + for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(), + ME = ID->meth_end(); MI != ME; ++MI) { + BugReporter BR(*Mgr); + checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR); + + if ((*MI)->isThisDeclarationADefinition()) { if (!Opts.AnalyzeSpecificFunction.empty() && - FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) - break; - DisplayFunction(FD); - HandleCode(FD); + Opts.AnalyzeSpecificFunction != + (*MI)->getSelector().getAsString()) + continue; + DisplayFunction(*MI); + HandleCode(*MI); } - break; } - - case Decl::ObjCCategoryImpl: - case Decl::ObjCImplementation: { - ObjCImplDecl* ID = cast<ObjCImplDecl>(*I); - HandleCode(ID); - - for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(), - ME = ID->meth_end(); MI != ME; ++MI) { - checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR); - - if ((*MI)->isThisDeclarationADefinition()) { - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != - (*MI)->getSelector().getAsString()) - break; - DisplayFunction(*MI); - HandleCode(*MI); - } - } - break; - } - - default: - break; + break; } - } + + default: + break; + } } void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { @@ -237,14 +244,14 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // After all decls handled, run checkers on the entire TranslationUnit. checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); - // Explicitly destroy the PathDiagnosticClient. This will flush its output. + // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on - // side-effects in PathDiagnosticClient's destructor. This is required when + // side-effects in PathDiagnosticConsumer's destructor. This is required when // used with option -disable-free. Mgr.reset(NULL); } -static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { +static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) { if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) WL.push_back(BD); @@ -254,20 +261,20 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { FindBlocks(DC, WL); } -static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D); +static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D); void AnalysisConsumer::HandleCode(Decl *D) { // Don't run the actions if an error has occurred with parsing the file. - Diagnostic &Diags = PP.getDiagnostics(); + DiagnosticsEngine &Diags = PP.getDiagnostics(); if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; // Don't run the actions on declarations in header files unless // otherwise specified. SourceManager &SM = Ctx->getSourceManager(); - SourceLocation SL = SM.getInstantiationLoc(D->getLocation()); + SourceLocation SL = SM.getExpansionLoc(D->getLocation()); if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) return; @@ -275,19 +282,19 @@ void AnalysisConsumer::HandleCode(Decl *D) { Mgr->ClearContexts(); // Dispatch on the actions. - llvm::SmallVector<Decl*, 10> WL; + SmallVector<Decl*, 10> WL; WL.push_back(D); if (D->hasBody() && Opts.AnalyzeNestedBlocks) FindBlocks(cast<DeclContext>(D), WL); BugReporter BR(*Mgr); - for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); + for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); WI != WE; ++WI) if ((*WI)->hasBody()) { checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); if (checkerMgr->hasPathSensitiveCheckers()) - ActionObjCMemChecker(*this, *Mgr, *WI); + RunPathSensitiveChecks(*this, *Mgr, *WI); } } @@ -295,18 +302,13 @@ void AnalysisConsumer::HandleCode(Decl *D) { // Path-sensitive checking. //===----------------------------------------------------------------------===// -static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D, - TransferFuncs* tf) { - - llvm::OwningPtr<TransferFuncs> TF(tf); - - // Construct the analysis engine. We first query for the LiveVariables - // information to see if the CFG is valid. +static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D, bool ObjCGCEnabled) { + // Construct the analysis engine. First check if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. - if (!mgr.getLiveVariables(D)) + if (!mgr.getCFG(D)) return; - ExprEngine Eng(mgr, TF.take()); + ExprEngine Eng(mgr, ObjCGCEnabled); // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; @@ -330,35 +332,25 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Eng.getBugReporter().FlushReports(); } -static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D, bool GCEnabled) { - - TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), - GCEnabled, - mgr.getLangOptions()); - - ActionExprEngine(C, mgr, D, TF); -} - -static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D) { - - switch (mgr.getLangOptions().getGCMode()) { - default: - assert (false && "Invalid GC mode."); - case LangOptions::NonGC: - ActionObjCMemCheckerAux(C, mgr, D, false); - break; - - case LangOptions::GCOnly: - ActionObjCMemCheckerAux(C, mgr, D, true); - break; - - case LangOptions::HybridGC: - ActionObjCMemCheckerAux(C, mgr, D, false); - ActionObjCMemCheckerAux(C, mgr, D, true); - break; - } +static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { + + switch (mgr.getLangOptions().getGC()) { + default: + llvm_unreachable("Invalid GC mode."); + case LangOptions::NonGC: + ActionExprEngine(C, mgr, D, false); + break; + + case LangOptions::GCOnly: + ActionExprEngine(C, mgr, D, true); + break; + + case LangOptions::HybridGC: + ActionExprEngine(C, mgr, D, false); + ActionExprEngine(C, mgr, D, true); + break; + } } //===----------------------------------------------------------------------===// @@ -366,14 +358,13 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, //===----------------------------------------------------------------------===// ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, - const std::string& OutDir, - const AnalyzerOptions& Opts) { - llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); - - // Last, disable the effects of '-Werror' when using the AnalysisConsumer. + const std::string& outDir, + const AnalyzerOptions& opts, + ArrayRef<std::string> plugins) { + // Disable the effects of '-Werror' when using the AnalysisConsumer. pp.getDiagnostics().setWarningsAsErrors(false); - return C.take(); + return new AnalysisConsumer(pp, outDir, opts, plugins); } //===----------------------------------------------------------------------===// @@ -383,7 +374,7 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, namespace { class UbigraphViz : public ExplodedNode::Auditor { - llvm::OwningPtr<llvm::raw_ostream> Out; + llvm::OwningPtr<raw_ostream> Out; llvm::sys::Path Dir, Filename; unsigned Cntr; @@ -391,12 +382,12 @@ class UbigraphViz : public ExplodedNode::Auditor { VMap M; public: - UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, + UbigraphViz(raw_ostream *out, llvm::sys::Path& dir, llvm::sys::Path& filename); ~UbigraphViz(); - virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst); + virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst); }; } // end anonymous namespace @@ -426,7 +417,7 @@ static ExplodedNode::Auditor* CreateUbiViz() { return new UbigraphViz(Stream.take(), Dir, Filename); } -void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { +void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) { assert (Src != Dst && "Self-edges are not allowed."); @@ -460,7 +451,7 @@ void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { << ", ('arrow','true'), ('oriented', 'true'))\n"; } -UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, +UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir, llvm::sys::Path& filename) : Out(out), Dir(dir), Filename(filename), Cntr(0) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h index 646fe97..5a16bff 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H #define LLVM_CLANG_GR_ANALYSISCONSUMER_H +#include "clang/Basic/LLVM.h" #include <string> namespace clang { @@ -22,7 +23,7 @@ namespace clang { class AnalyzerOptions; class ASTConsumer; class Preprocessor; -class Diagnostic; +class DiagnosticsEngine; namespace ento { class CheckerManager; @@ -32,7 +33,8 @@ class CheckerManager; /// options.) ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp, const std::string &output, - const AnalyzerOptions& Opts); + const AnalyzerOptions& opts, + ArrayRef<std::string> plugins); } // end GR namespace diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt deleted file mode 100644 index cd9ac1b..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -set(LLVM_NO_RTTI 1) - -set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite) - -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../Checkers ) - -add_clang_library(clangStaticAnalyzerFrontend - AnalysisConsumer.cpp - CheckerRegistration.cpp - FrontendActions.cpp - ) - -add_dependencies(clangStaticAnalyzerFrontend - clangStaticAnalyzerCheckers - clangStaticAnalyzerCore - ClangAttrClasses - ClangAttrList - ClangDeclNodes - ClangStmtNode - ) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index d7edc7e..a59fcad 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -13,53 +13,121 @@ #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" -#include "../Checkers/ClangSACheckerProvider.h" +#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" +#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" +#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" #include "clang/Frontend/AnalyzerOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" using namespace clang; using namespace ento; +using llvm::sys::DynamicLibrary; -CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts, - const LangOptions &langOpts, - Diagnostic &diags) { +namespace { +class ClangCheckerRegistry : public CheckerRegistry { + typedef void (*RegisterCheckersFn)(CheckerRegistry &); + + static bool isCompatibleAPIVersion(const char *versionString); + static void warnIncompatible(DiagnosticsEngine *diags, StringRef pluginPath, + const char *pluginAPIVersion); + +public: + ClangCheckerRegistry(ArrayRef<std::string> plugins, + DiagnosticsEngine *diags = 0); +}; + +} // end anonymous namespace + +ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins, + DiagnosticsEngine *diags) { + registerBuiltinCheckers(*this); + + for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end(); + i != e; ++i) { + // Get access to the plugin. + DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str()); + + // See if it's compatible with this build of clang. + const char *pluginAPIVersion = + (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString"); + if (!isCompatibleAPIVersion(pluginAPIVersion)) { + warnIncompatible(diags, *i, pluginAPIVersion); + continue; + } + + // Register its checkers. + RegisterCheckersFn registerPluginCheckers = + (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol( + "clang_registerCheckers"); + if (registerPluginCheckers) + registerPluginCheckers(*this); + } +} + +bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) { + // If the version string is null, it's not an analyzer plugin. + if (versionString == 0) + return false; + + // For now, none of the static analyzer API is considered stable. + // Versions must match exactly. + if (strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0) + return true; + + return false; +} + +void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags, + StringRef pluginPath, + const char *pluginAPIVersion) { + if (!diags) + return; + if (!pluginAPIVersion) + return; + + diags->Report(diag::warn_incompatible_analyzer_plugin_api) + << llvm::sys::path::filename(pluginPath); + diags->Report(diag::note_incompatible_analyzer_plugin_api) + << CLANG_ANALYZER_API_VERSION_STRING + << pluginAPIVersion; +} + + +CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts, + const LangOptions &langOpts, + ArrayRef<std::string> plugins, + DiagnosticsEngine &diags) { llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts)); - llvm::SmallVector<CheckerOptInfo, 8> checkerOpts; + SmallVector<CheckerOptInfo, 8> checkerOpts; for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { const std::pair<std::string, bool> &opt = opts.CheckersControlList[i]; checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second)); } - llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider()); - provider->registerCheckers(*checkerMgr, - checkerOpts.data(), checkerOpts.size()); - - // FIXME: Load CheckerProviders from plugins. - + ClangCheckerRegistry allCheckers(plugins, &diags); + allCheckers.initializeManager(*checkerMgr, checkerOpts); checkerMgr->finishedCheckerRegistration(); for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { if (checkerOpts[i].isUnclaimed()) - diags.Report(diag::warn_unkwown_analyzer_checker) + diags.Report(diag::warn_unknown_analyzer_checker) << checkerOpts[i].getName(); } return checkerMgr.take(); } -void ento::printCheckerHelp(llvm::raw_ostream &OS) { - OS << "OVERVIEW: Clang Static Analyzer Checkers List\n"; - OS << '\n'; - - llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider()); - provider->printHelp(OS); +void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) { + out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; + out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n"; - // FIXME: Load CheckerProviders from plugins. + ClangCheckerRegistry(plugins).printHelp(out); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp index a59cc68..85a18ec 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp @@ -14,9 +14,10 @@ using namespace clang; using namespace ento; ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateAnalysisConsumer(CI.getPreprocessor(), CI.getFrontendOpts().OutputFile, - CI.getAnalyzerOpts()); + CI.getAnalyzerOpts(), + CI.getFrontendOpts().Plugins); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/Makefile b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/Makefile deleted file mode 100644 index 2698120..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -##===- clang/lib/StaticAnalyzer/Frontend/Makefile ----------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# Starting point into the static analyzer land for the driver. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangStaticAnalyzerFrontend - -CPP.Flags += -I${PROJ_OBJ_DIR}/../Checkers - -include $(CLANG_LEVEL)/Makefile diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Makefile b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Makefile deleted file mode 100644 index c166f06..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements analyses built on top of source-level CFGs. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../.. -DIRS := Checkers Frontend -PARALLEL_DIRS := Core - -include $(CLANG_LEVEL)/Makefile diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/README.txt b/contrib/llvm/tools/clang/lib/StaticAnalyzer/README.txt deleted file mode 100644 index 1406eca..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/README.txt +++ /dev/null @@ -1,139 +0,0 @@ -//===----------------------------------------------------------------------===// -// Clang Static Analyzer -//===----------------------------------------------------------------------===// - -= Library Structure = - -The analyzer library has two layers: a (low-level) static analysis -engine (GRExprEngine.cpp and friends), and some static checkers -(*Checker.cpp). The latter are built on top of the former via the -Checker and CheckerVisitor interfaces (Checker.h and -CheckerVisitor.h). The Checker interface is designed to be minimal -and simple for checker writers, and attempts to isolate them from much -of the gore of the internal analysis engine. - -= How It Works = - -The analyzer is inspired by several foundational research papers ([1], -[2]). (FIXME: kremenek to add more links) - -In a nutshell, the analyzer is basically a source code simulator that -traces out possible paths of execution. The state of the program -(values of variables and expressions) is encapsulated by the state -(GRState). A location in the program is called a program point -(ProgramPoint), and the combination of state and program point is a -node in an exploded graph (ExplodedGraph). The term "exploded" comes -from exploding the control-flow edges in the control-flow graph (CFG). - -Conceptually the analyzer does a reachability analysis through the -ExplodedGraph. We start at a root node, which has the entry program -point and initial state, and then simulate transitions by analyzing -individual expressions. The analysis of an expression can cause the -state to change, resulting in a new node in the ExplodedGraph with an -updated program point and an updated state. A bug is found by hitting -a node that satisfies some "bug condition" (basically a violation of a -checking invariant). - -The analyzer traces out multiple paths by reasoning about branches and -then bifurcating the state: on the true branch the conditions of the -branch are assumed to be true and on the false branch the conditions -of the branch are assumed to be false. Such "assumptions" create -constraints on the values of the program, and those constraints are -recorded in the GRState object (and are manipulated by the -ConstraintManager). If assuming the conditions of a branch would -cause the constraints to be unsatisfiable, the branch is considered -infeasible and that path is not taken. This is how we get -path-sensitivity. We reduce exponential blow-up by caching nodes. If -a new node with the same state and program point as an existing node -would get generated, the path "caches out" and we simply reuse the -existing node. Thus the ExplodedGraph is not a DAG; it can contain -cycles as paths loop back onto each other and cache out. - -GRState and ExplodedNodes are basically immutable once created. Once -one creates a GRState, you need to create a new one to get a new -GRState. This immutability is key since the ExplodedGraph represents -the behavior of the analyzed program from the entry point. To -represent these efficiently, we use functional data structures (e.g., -ImmutableMaps) which share data between instances. - -Finally, individual Checkers work by also manipulating the analysis -state. The analyzer engine talks to them via a visitor interface. -For example, the PreVisitCallExpr() method is called by GRExprEngine -to tell the Checker that we are about to analyze a CallExpr, and the -checker is asked to check for any preconditions that might not be -satisfied. The checker can do nothing, or it can generate a new -GRState and ExplodedNode which contains updated checker state. If it -finds a bug, it can tell the BugReporter object about the bug, -providing it an ExplodedNode which is the last node in the path that -triggered the problem. - -= Notes about C++ = - -Since now constructors are seen before the variable that is constructed -in the CFG, we create a temporary object as the destination region that -is constructed into. See ExprEngine::VisitCXXConstructExpr(). - -In ExprEngine::processCallExit(), we always bind the object region to the -evaluated CXXConstructExpr. Then in VisitDeclStmt(), we compute the -corresponding lazy compound value if the variable is not a reference, and -bind the variable region to the lazy compound value. If the variable -is a reference, just use the object region as the initilizer value. - -Before entering a C++ method (or ctor/dtor), the 'this' region is bound -to the object region. In ctors, we synthesize 'this' region with -CXXRecordDecl*, which means we do not use type qualifiers. In methods, we -synthesize 'this' region with CXXMethodDecl*, which has getThisType() -taking type qualifiers into account. It does not matter we use qualified -'this' region in one method and unqualified 'this' region in another -method, because we only need to ensure the 'this' region is consistent -when we synthesize it and create it directly from CXXThisExpr in a single -method call. - -= Working on the Analyzer = - -If you are interested in bringing up support for C++ expressions, the -best place to look is the visitation logic in GRExprEngine, which -handles the simulation of individual expressions. There are plenty of -examples there of how other expressions are handled. - -If you are interested in writing checkers, look at the Checker and -CheckerVisitor interfaces (Checker.h and CheckerVisitor.h). Also look -at the files named *Checker.cpp for examples on how you can implement -these interfaces. - -= Debugging the Analyzer = - -There are some useful command-line options for debugging. For example: - -$ clang -cc1 -help | grep analyze - -analyze-function <value> - -analyzer-display-progress - -analyzer-viz-egraph-graphviz - ... - -The first allows you to specify only analyzing a specific function. -The second prints to the console what function is being analyzed. The -third generates a graphviz dot file of the ExplodedGraph. This is -extremely useful when debugging the analyzer and viewing the -simulation results. - -Of course, viewing the CFG (Control-Flow Graph) is also useful: - -$ clang -cc1 -help | grep cfg - -cfg-add-implicit-dtors Add C++ implicit destructors to CFGs for all analyses - -cfg-add-initializers Add C++ initializers to CFGs for all analyses - -cfg-dump Display Control-Flow Graphs - -cfg-view View Control-Flow Graphs using GraphViz - -unoptimized-cfg Generate unoptimized CFGs for all analyses - --cfg-dump dumps a textual representation of the CFG to the console, -and -cfg-view creates a GraphViz representation. - -= References = - -[1] Precise interprocedural dataflow analysis via graph reachability, - T Reps, S Horwitz, and M Sagiv, POPL '95, - http://portal.acm.org/citation.cfm?id=199462 - -[2] A memory model for static analysis of C programs, Z Xu, T - Kremenek, and J Zhang, http://lcs.ios.ac.cn/~xzx/memmodel.pdf |