diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | 809500fc2c13c8173a16b052304d983864e4a1e1 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib | |
parent | be7c9ec198dcdb5bf73a35bfbb00b3333cb87909 (diff) | |
download | src-809500fc2c13c8173a16b052304d983864e4a1e1.tar.gz src-809500fc2c13c8173a16b052304d983864e4a1e1.zip |
Vendor import of clang trunk r178860:vendor/clang/clang-trunk-r178860
Notes
Notes:
svn path=/vendor/clang/dist/; revision=249261
svn path=/vendor/clang/clang-trunk-r178860/; revision=249262; tag=vendor/clang/clang-trunk-r178860
Diffstat (limited to 'lib')
468 files changed, 56083 insertions, 30139 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index b57d9964736f..72f35205ca8e 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -8,18 +8,19 @@ //===----------------------------------------------------------------------===// #include "Internals.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Basic/DiagnosticCategories.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" -#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Sema/SemaDiagnostic.h" -#include "clang/Basic/DiagnosticCategories.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/Support/MemoryBuffer.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/MemoryBuffer.h" using namespace clang; using namespace arcmt; @@ -39,8 +40,9 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; - while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) - ++I; + if (eraseS->getLevel() != DiagnosticsEngine::Note) + while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) + ++I; // Clear the diagnostic and any notes following it. I = List.erase(eraseS, I); continue; @@ -130,7 +132,8 @@ public: const Diagnostic &Info) { if (DiagnosticIDs::isARCDiagnostic(Info.getID()) || level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { - CapturedDiags.push_back(StoredDiagnostic(level, Info)); + if (Info.getLocation().isValid()) + CapturedDiags.push_back(StoredDiagnostic(level, Info)); return; } @@ -172,8 +175,24 @@ static CompilerInvocation * createInvocationForMigration(CompilerInvocation &origCI) { OwningPtr<CompilerInvocation> CInvok; CInvok.reset(new CompilerInvocation(origCI)); - CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); - CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string(); + PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); + if (!PPOpts.ImplicitPCHInclude.empty()) { + // We can't use a PCH because it was likely built in non-ARC mode and we + // want to parse in ARC. Include the original header. + FileManager FileMgr(origCI.getFileSystemOpts()); + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), + new IgnoringDiagConsumer())); + std::string OriginalFile = + ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude, + FileMgr, *Diags); + if (!OriginalFile.empty()) + PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile); + PPOpts.ImplicitPCHInclude.clear(); + } + // FIXME: Get the original header of a PTH as well. + CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear(); std::string define = getARCMTMacroName(); define += '='; CInvok->getPreprocessorOpts().addMacroDef(define); @@ -295,7 +314,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, std::vector<SourceLocation> ARCMTMacroLocs; TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); - MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs); + MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, + ARCMTMacroLocs); pass.setNSAllocReallocError(NoNSAllocReallocError); pass.setNoFinalizeRemoval(NoFinalizeRemoval); @@ -416,8 +436,8 @@ bool arcmt::getFileRemappingsFromFileList( bool hasErrorOccurred = false; llvm::StringMap<bool> Uniquer; - llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, new DiagnosticOptions, DiagClient, /*ShouldOwnClient=*/false)); @@ -461,7 +481,7 @@ public: ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) : ARCMTMacroLocs(ARCMTMacroLocs) { } - virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI, + virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, SourceRange Range) { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); @@ -598,7 +618,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), - Unit->getSema(), TA, ARCMTMacroLocs); + Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); trans(pass); diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt index 731bcb4fc7f9..da51d6db83b8 100644 --- a/lib/ARCMigrate/CMakeLists.txt +++ b/lib/ARCMigrate/CMakeLists.txt @@ -9,15 +9,16 @@ add_clang_library(clangARCMigrate TransAutoreleasePool.cpp TransBlockObjCVariable.cpp TransEmptyStatementsAndDealloc.cpp - TransformActions.cpp - Transforms.cpp TransGCAttrs.cpp TransGCCalls.cpp TransProperties.cpp + TransProtectedScope.cpp TransRetainReleaseDealloc.cpp TransUnbridgedCasts.cpp TransUnusedInitDelegate.cpp TransZeroOutPropsInDealloc.cpp + TransformActions.cpp + Transforms.cpp ) add_dependencies(clangARCMigrate diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp index 28ca9a56b20e..6a8686c4ff0f 100644 --- a/lib/ARCMigrate/FileRemapper.cpp +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -8,12 +8,12 @@ //===----------------------------------------------------------------------===// #include "clang/ARCMigrate/FileRemapper.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include <fstream> diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h index 1966a9823b92..3690c83d8457 100644 --- a/lib/ARCMigrate/Internals.h +++ b/lib/ARCMigrate/Internals.h @@ -146,16 +146,20 @@ public: MigratorOptions MigOptions; Sema &SemaRef; TransformActions &TA; + const CapturedDiagList &CapturedDiags; std::vector<SourceLocation> &ARCMTMacroLocs; - llvm::Optional<bool> EnableCFBridgeFns; + Optional<bool> EnableCFBridgeFns; MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, Sema &sema, TransformActions &TA, + const CapturedDiagList &capturedDiags, std::vector<SourceLocation> &ARCMTMacroLocs) : Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(), - SemaRef(sema), TA(TA), + SemaRef(sema), TA(TA), CapturedDiags(capturedDiags), ARCMTMacroLocs(ARCMTMacroLocs) { } + const CapturedDiagList &getDiags() const { return CapturedDiags; } + bool isGCMigration() const { return OrigGCMode != LangOptions::NonGC; } bool noNSAllocReallocError() const { return MigOptions.NoNSAllocReallocError; } void setNSAllocReallocError(bool val) { MigOptions.NoNSAllocReallocError = val; } diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index dfe14e2b5dd7..57fac0389fc3 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -8,19 +8,21 @@ //===----------------------------------------------------------------------===// #include "clang/ARCMigrate/ARCMTActions.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/NSAPI.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Edit/Rewriters.h" -#include "clang/Edit/EditedSource.h" +#include "clang/AST/ParentMap.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/FileManager.h" #include "clang/Edit/Commit.h" +#include "clang/Edit/EditedSource.h" #include "clang/Edit/EditsReceiver.h" -#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Edit/Rewriters.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/PPConditionalDirectiveRecord.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Basic/FileManager.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -35,11 +37,11 @@ public: std::string MigrateDir; bool MigrateLiterals; bool MigrateSubscripting; - llvm::OwningPtr<NSAPI> NSAPIObj; - llvm::OwningPtr<edit::EditedSource> Editor; + OwningPtr<NSAPI> NSAPIObj; + OwningPtr<edit::EditedSource> Editor; FileRemapper &Remapper; FileManager &FileMgr; - const PreprocessingRecord *PPRec; + const PPConditionalDirectiveRecord *PPRec; bool IsOutputFile; ObjCMigrateASTConsumer(StringRef migrateDir, @@ -47,7 +49,7 @@ public: bool migrateSubscripting, FileRemapper &remapper, FileManager &fileMgr, - const PreprocessingRecord *PPRec, + const PPConditionalDirectiveRecord *PPRec, bool isOutputFile = false) : MigrateDir(migrateDir), MigrateLiterals(migrateLiterals), @@ -93,6 +95,9 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + PPConditionalDirectiveRecord * + PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); + CompInst->getPreprocessor().addPPCallbacks(PPRec); ASTConsumer * WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, @@ -100,7 +105,7 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, MigrateSubscripting, Remapper, CompInst->getFileManager(), - CompInst->getPreprocessor().getPreprocessingRecord()); + PPRec); ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; return new MultiplexConsumer(Consumers); } @@ -110,17 +115,17 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { /*ignoreIfFilesChanges=*/true); CompInst = &CI; CI.getDiagnostics().setIgnoreAllWarnings(true); - CI.getPreprocessorOpts().DetailedRecord = true; - CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; return true; } namespace { class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { ObjCMigrateASTConsumer &Consumer; + ParentMap &PMap; public: - ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } + ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap) + : Consumer(consumer), PMap(PMap) { } bool shouldVisitTemplateInstantiations() const { return false; } bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -128,7 +133,7 @@ public: bool VisitObjCMessageExpr(ObjCMessageExpr *E) { if (Consumer.MigrateLiterals) { edit::Commit commit(*Consumer.Editor); - edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit); + edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap); Consumer.Editor->commit(commit); } @@ -151,6 +156,23 @@ public: return WalkUpFromObjCMessageExpr(E); } }; + +class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> { + ObjCMigrateASTConsumer &Consumer; + OwningPtr<ParentMap> PMap; + +public: + BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } + + bool shouldVisitTemplateInstantiations() const { return false; } + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseStmt(Stmt *S) { + PMap.reset(new ParentMap(S)); + ObjCMigrator(Consumer, *PMap).TraverseStmt(S); + return true; + } +}; } void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { @@ -159,7 +181,7 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { if (isa<ObjCMethodDecl>(D)) return; // Wait for the ObjC container declaration. - ObjCMigrator(*this).TraverseDecl(D); + BodyMigrator(*this).TraverseDecl(D); } namespace { @@ -191,13 +213,13 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { RewriteBuffer &buf = I->second; const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); assert(file); - llvm::SmallString<512> newText; + SmallString<512> newText; llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); vecOS.flush(); llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( StringRef(newText.data(), newText.size()), file->getName()); - llvm::SmallString<64> filePath(file->getName()); + SmallString<64> filePath(file->getName()); FileMgr.FixupRelativePath(filePath); Remapper.remap(filePath.str(), memBuf); } @@ -211,18 +233,19 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { CI.getDiagnostics().setIgnoreAllWarnings(true); - CI.getPreprocessorOpts().DetailedRecord = true; - CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; return true; } ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + PPConditionalDirectiveRecord * + PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); + CI.getPreprocessor().addPPCallbacks(PPRec); return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, /*MigrateLiterals=*/true, /*MigrateSubscripting=*/true, Remapper, CI.getFileManager(), - CI.getPreprocessor().getPreprocessingRecord(), + PPRec, /*isOutputFile=*/true); } diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp index d1bc90fdbe16..144ba2e398ad 100644 --- a/lib/ARCMigrate/PlistReporter.cpp +++ b/lib/ARCMigrate/PlistReporter.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "Internals.h" -#include "clang/Lex/Lexer.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" using namespace clang; using namespace arcmt; diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 5336f859052f..2305b6defd9c 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -1,4 +1,4 @@ -//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===// +//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp index b83f85a1fac2..80bfd22d6258 100644 --- a/lib/ARCMigrate/TransARCAssign.cpp +++ b/lib/ARCMigrate/TransARCAssign.cpp @@ -1,4 +1,4 @@ -//===--- TransARCAssign.cpp - Tranformations to ARC mode ------------------===// +//===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp index 5205ce4a70a9..a2990e7226ab 100644 --- a/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -1,4 +1,4 @@ -//===--- TransAutoreleasePool.cpp - Tranformations to ARC mode ------------===// +//===--- TransAutoreleasePool.cpp - Transformations to ARC mode -----------===// // // The LLVM Compiler Infrastructure // @@ -30,8 +30,8 @@ #include "Transforms.h" #include "Internals.h" #include "clang/AST/ASTContext.h" -#include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/SourceManager.h" +#include "clang/Sema/SemaDiagnostic.h" #include <map> using namespace clang; diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp index 2a79c9aeff20..97c4e3480c15 100644 --- a/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -1,4 +1,4 @@ -//===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===// +//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===// // // The LLVM Compiler Infrastructure // @@ -28,6 +28,7 @@ #include "Transforms.h" #include "Internals.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/Basic/SourceManager.h" using namespace clang; diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp index 552cb2fa631c..ffb638f8a306 100644 --- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp +++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -1,4 +1,4 @@ -//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===// +//===--- TransEmptyStatements.cpp - Transformations to ARC mode -----------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp index eec7306ba74a..d8be1ae746ab 100644 --- a/lib/ARCMigrate/TransGCAttrs.cpp +++ b/lib/ARCMigrate/TransGCAttrs.cpp @@ -63,19 +63,18 @@ public: return; TypeLoc TL = TInfo->getTypeLoc(); while (TL) { - if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) { - TL = QL->getUnqualifiedLoc(); - } else if (const AttributedTypeLoc * - Attr = dyn_cast<AttributedTypeLoc>(&TL)) { - if (handleAttr(*Attr, D)) + if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) { + TL = QL.getUnqualifiedLoc(); + } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) { + if (handleAttr(Attr, D)) break; - TL = Attr->getModifiedLoc(); - } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) { - TL = Arr->getElementLoc(); - } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) { - TL = PT->getPointeeLoc(); - } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL)) - TL = RT->getPointeeLoc(); + TL = Attr.getModifiedLoc(); + } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) { + TL = Arr.getElementLoc(); + } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) { + TL = PT.getPointeeLoc(); + } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>()) + TL = RT.getPointeeLoc(); else break; } @@ -249,8 +248,9 @@ static void checkAllAtProps(MigrationContext &MigrateCtx, if (!TInfo) return; TypeLoc TL = TInfo->getTypeLoc(); - if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) { - ATLs.push_back(std::make_pair(*ATL, PD)); + if (AttributedTypeLoc ATL = + TL.getAs<AttributedTypeLoc>()) { + ATLs.push_back(std::make_pair(ATL, PD)); if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { hasWeak = true; } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp index 2ec480c0af64..249f20f01b22 100644 --- a/lib/ARCMigrate/TransGCCalls.cpp +++ b/lib/ARCMigrate/TransGCCalls.cpp @@ -1,4 +1,4 @@ -//===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===// +//===--- TransGCCalls.cpp - Transformations to ARC mode -------------------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp index fdd6e8863b59..b6ddc43dd69f 100644 --- a/lib/ARCMigrate/TransProperties.cpp +++ b/lib/ARCMigrate/TransProperties.cpp @@ -1,4 +1,4 @@ -//===--- TransProperties.cpp - Tranformations to ARC mode -----------------===// +//===--- TransProperties.cpp - Transformations to ARC mode ----------------===// // // The LLVM Compiler Infrastructure // @@ -32,9 +32,9 @@ #include "Transforms.h" #include "Internals.h" -#include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaDiagnostic.h" #include <map> using namespace clang; @@ -141,10 +141,12 @@ public: AtPropDeclsTy AtExtProps; // Look through extensions. - for (ObjCCategoryDecl *Cat = iface->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory()) - if (Cat->IsClassExtension()) - collectProperties(Cat, AtExtProps, &AtProps); + for (ObjCInterfaceDecl::visible_extensions_iterator + ext = iface->visible_extensions_begin(), + extEnd = iface->visible_extensions_end(); + ext != extEnd; ++ext) { + collectProperties(*ext, AtExtProps, &AtProps); + } for (AtPropDeclsTy::iterator I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) { @@ -226,8 +228,10 @@ private: 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_strong_property_ownership, + diag::err_arc_assign_property_ownership, + diag::err_arc_inconsistent_property_ownership, + I->IvarD->getLocation()); } } @@ -253,8 +257,10 @@ private: } } if (I->ImplD) - Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, - I->ImplD->getLocation()); + Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership, + diag::err_arc_assign_property_ownership, + diag::err_arc_inconsistent_property_ownership, + I->IvarD->getLocation()); } } @@ -276,8 +282,10 @@ private: canUseWeak ? "__weak " : "__unsafe_unretained "); } if (I->ImplD) { - Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, - I->ImplD->getLocation()); + Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership, + diag::err_arc_assign_property_ownership, + diag::err_arc_inconsistent_property_ownership, + I->IvarD->getLocation()); Pass.TA.clearDiagnostic( diag::err_arc_objc_property_default_assign_on_object, I->ImplD->getLocation()); diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp new file mode 100644 index 000000000000..237aa42877e6 --- /dev/null +++ b/lib/ARCMigrate/TransProtectedScope.cpp @@ -0,0 +1,202 @@ +//===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Adds brackets in case statements that "contain" initialization of retaining +// variable, thus emitting the "switch case is in protected scope" error. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/AST/ASTContext.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +namespace { + +class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> { + SmallVectorImpl<DeclRefExpr *> &Refs; + +public: + LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs) + : Refs(refs) { } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (ValueDecl *D = E->getDecl()) + if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod()) + Refs.push_back(E); + return true; + } +}; + +struct CaseInfo { + SwitchCase *SC; + SourceRange Range; + enum { + St_Unchecked, + St_CannotFix, + St_Fixed + } State; + + CaseInfo() : SC(0), State(St_Unchecked) {} + CaseInfo(SwitchCase *S, SourceRange Range) + : SC(S), Range(Range), State(St_Unchecked) {} +}; + +class CaseCollector : public RecursiveASTVisitor<CaseCollector> { + ParentMap &PMap; + SmallVectorImpl<CaseInfo> &Cases; + +public: + CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases) + : PMap(PMap), Cases(Cases) { } + + bool VisitSwitchStmt(SwitchStmt *S) { + SwitchCase *Curr = S->getSwitchCaseList(); + if (!Curr) + return true; + Stmt *Parent = getCaseParent(Curr); + Curr = Curr->getNextSwitchCase(); + // Make sure all case statements are in the same scope. + while (Curr) { + if (getCaseParent(Curr) != Parent) + return true; + Curr = Curr->getNextSwitchCase(); + } + + SourceLocation NextLoc = S->getLocEnd(); + Curr = S->getSwitchCaseList(); + // We iterate over case statements in reverse source-order. + while (Curr) { + Cases.push_back(CaseInfo(Curr,SourceRange(Curr->getLocStart(), NextLoc))); + NextLoc = Curr->getLocStart(); + Curr = Curr->getNextSwitchCase(); + } + return true; + } + + Stmt *getCaseParent(SwitchCase *S) { + Stmt *Parent = PMap.getParent(S); + while (Parent && (isa<SwitchCase>(Parent) || isa<LabelStmt>(Parent))) + Parent = PMap.getParent(Parent); + return Parent; + } +}; + +class ProtectedScopeFixer { + MigrationPass &Pass; + SourceManager &SM; + SmallVector<CaseInfo, 16> Cases; + SmallVector<DeclRefExpr *, 16> LocalRefs; + +public: + ProtectedScopeFixer(BodyContext &BodyCtx) + : Pass(BodyCtx.getMigrationContext().Pass), + SM(Pass.Ctx.getSourceManager()) { + + CaseCollector(BodyCtx.getParentMap(), Cases) + .TraverseStmt(BodyCtx.getTopStmt()); + LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt()); + + SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange(); + const CapturedDiagList &DiagList = Pass.getDiags(); + // Copy the diagnostics so we don't have to worry about invaliding iterators + // from the diagnostic list. + SmallVector<StoredDiagnostic, 16> StoredDiags; + StoredDiags.append(DiagList.begin(), DiagList.end()); + SmallVectorImpl<StoredDiagnostic>::iterator + I = StoredDiags.begin(), E = StoredDiags.end(); + while (I != E) { + if (I->getID() == diag::err_switch_into_protected_scope && + isInRange(I->getLocation(), BodyRange)) { + handleProtectedScopeError(I, E); + continue; + } + ++I; + } + } + + void handleProtectedScopeError( + SmallVectorImpl<StoredDiagnostic>::iterator &DiagI, + SmallVectorImpl<StoredDiagnostic>::iterator DiagE){ + Transaction Trans(Pass.TA); + assert(DiagI->getID() == diag::err_switch_into_protected_scope); + SourceLocation ErrLoc = DiagI->getLocation(); + bool handledAllNotes = true; + ++DiagI; + for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note; + ++DiagI) { + if (!handleProtectedNote(*DiagI)) + handledAllNotes = false; + } + + if (handledAllNotes) + Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc); + } + + bool handleProtectedNote(const StoredDiagnostic &Diag) { + assert(Diag.getLevel() == DiagnosticsEngine::Note); + + for (unsigned i = 0; i != Cases.size(); i++) { + CaseInfo &info = Cases[i]; + if (isInRange(Diag.getLocation(), info.Range)) { + + if (info.State == CaseInfo::St_Unchecked) + tryFixing(info); + assert(info.State != CaseInfo::St_Unchecked); + + if (info.State == CaseInfo::St_Fixed) { + Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation()); + return true; + } + return false; + } + } + + return false; + } + + void tryFixing(CaseInfo &info) { + assert(info.State == CaseInfo::St_Unchecked); + if (hasVarReferencedOutside(info)) { + info.State = CaseInfo::St_CannotFix; + return; + } + + Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {"); + Pass.TA.insert(info.Range.getEnd(), "}\n"); + info.State = CaseInfo::St_Fixed; + } + + bool hasVarReferencedOutside(CaseInfo &info) { + for (unsigned i = 0, e = LocalRefs.size(); i != e; ++i) { + DeclRefExpr *DRE = LocalRefs[i]; + if (isInRange(DRE->getDecl()->getLocation(), info.Range) && + !isInRange(DRE->getLocation(), info.Range)) + return true; + } + return false; + } + + bool isInRange(SourceLocation Loc, SourceRange R) { + if (Loc.isInvalid()) + return false; + return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) && + SM.isBeforeInTranslationUnit(Loc, R.getEnd()); + } +}; + +} // anonymous namespace + +void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) { + ProtectedScopeFixer Fix(BodyCtx); +} diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index 91d2b399e3f1..0c8d15544610 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -1,4 +1,4 @@ -//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===// +//===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===// // // The LLVM Compiler Infrastructure // @@ -24,6 +24,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; using namespace arcmt; @@ -161,13 +162,47 @@ public: private: /// \brief Checks for idioms where an unused -autorelease is common. /// - /// Currently only returns true for this idiom which is common in property + /// Returns true for this idiom which is common in property /// setters: /// /// [backingValue autorelease]; /// backingValue = [newValue retain]; // in general a +1 assign /// + /// For these as well: + /// + /// [[var retain] autorelease]; + /// return var; + /// bool isCommonUnusedAutorelease(ObjCMessageExpr *E) { + if (isPlusOneAssignBeforeOrAfterAutorelease(E)) + return true; + if (isReturnedAfterAutorelease(E)) + return true; + return false; + } + + bool isReturnedAfterAutorelease(ObjCMessageExpr *E) { + Expr *Rec = E->getInstanceReceiver(); + if (!Rec) + return false; + + Decl *RefD = getReferencedDecl(Rec); + if (!RefD) + return false; + + Stmt *nextStmt = getNextStmt(E); + if (!nextStmt) + return false; + + // Check for "return <variable>;". + + if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt)) + return RefD == getReferencedDecl(RetS->getRetValue()); + + return false; + } + + bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) { Expr *Rec = E->getInstanceReceiver(); if (!Rec) return false; @@ -176,6 +211,47 @@ private: if (!RefD) return false; + Stmt *prevStmt, *nextStmt; + llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E); + + return isPlusOneAssignToVar(prevStmt, RefD) || + isPlusOneAssignToVar(nextStmt, RefD); + } + + bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) { + if (!S) + return false; + + // Check for "RefD = [+1 retained object];". + + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) { + if (RefD != getReferencedDecl(Bop->getLHS())) + return false; + if (isPlusOneAssign(Bop)) + return true; + return false; + } + + if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) { + if (VarDecl *VD = dyn_cast<VarDecl>(RefD)) + return isPlusOne(VD->getInit()); + } + return false; + } + + return false; + } + + Stmt *getNextStmt(Expr *E) { + return getPreviousAndNextStmt(E).second; + } + + std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) { + Stmt *prevStmt = 0, *nextStmt = 0; + if (!E) + return std::make_pair(prevStmt, nextStmt); + Stmt *OuterS = E, *InnerS; do { InnerS = OuterS; @@ -186,36 +262,34 @@ private: isa<ExprWithCleanups>(OuterS))); if (!OuterS) - return false; - - // Find next statement after the -autorelease. + return std::make_pair(prevStmt, nextStmt); Stmt::child_iterator currChildS = OuterS->child_begin(); Stmt::child_iterator childE = OuterS->child_end(); + Stmt::child_iterator prevChildS = childE; for (; currChildS != childE; ++currChildS) { if (*currChildS == InnerS) break; + prevChildS = currChildS; } + + if (prevChildS != childE) { + prevStmt = *prevChildS; + if (prevStmt) + prevStmt = prevStmt->IgnoreImplicit(); + } + if (currChildS == childE) - return false; + return std::make_pair(prevStmt, nextStmt); ++currChildS; if (currChildS == childE) - return false; + return std::make_pair(prevStmt, nextStmt); - Stmt *nextStmt = *currChildS; - if (!nextStmt) - return false; - nextStmt = nextStmt->IgnoreImplicit(); + nextStmt = *currChildS; + if (nextStmt) + nextStmt = nextStmt->IgnoreImplicit(); - // Check for "RefD = [+1 retained object];". - - if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) { - if (RefD != getReferencedDecl(Bop->getLHS())) - return false; - if (isPlusOneAssign(Bop)) - return true; - } - return false; + return std::make_pair(prevStmt, nextStmt); } Decl *getReferencedDecl(Expr *E) { @@ -223,6 +297,17 @@ private: return 0; E = E->IgnoreParenCasts(); + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { + switch (ME->getMethodFamily()) { + case OMF_copy: + case OMF_autorelease: + case OMF_release: + case OMF_retain: + return getReferencedDecl(ME->getInstanceReceiver()); + default: + return 0; + } + } if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return DRE->getDecl(); if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index ac18b5d6e739..fc4a75fdb838 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -1,4 +1,4 @@ -//===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===// +//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===// // // The LLVM Compiler Infrastructure // @@ -30,13 +30,22 @@ // ----> // CFStringRef str = (__bridge CFStringRef)self; // +// Uses of Block_copy/Block_release macros are rewritten: +// +// c = Block_copy(b); +// Block_release(c); +// ----> +// c = [b copy]; +// <removed> +// //===----------------------------------------------------------------------===// #include "Transforms.h" #include "Internals.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/ParentMap.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Sema/SemaDiagnostic.h" @@ -53,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ IdentifierInfo *SelfII; OwningPtr<ParentMap> StmtMap; Decl *ParentD; + Stmt *Body; + mutable OwningPtr<ExprSet> Removables; public: - UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) { + UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) { SelfII = &Pass.Ctx.Idents.get("self"); } void transformBody(Stmt *body, Decl *ParentD) { this->ParentD = ParentD; + Body = body; StmtMap.reset(new ParentMap(body)); TraverseStmt(body); } bool VisitCastExpr(CastExpr *E) { - if (E->getCastKind() != CK_CPointerToObjCPointerCast - && E->getCastKind() != CK_BitCast) + if (E->getCastKind() != CK_CPointerToObjCPointerCast && + E->getCastKind() != CK_BitCast && + E->getCastKind() != CK_AnyPointerToBlockPointerCast) return true; QualType castType = E->getType(); Expr *castExpr = E->getSubExpr(); QualType castExprType = castExpr->getType(); - if (castType->isObjCObjectPointerType() && - castExprType->isObjCObjectPointerType()) - return true; - if (!castType->isObjCObjectPointerType() && - !castExprType->isObjCObjectPointerType()) + if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType()) return true; bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); @@ -93,7 +102,7 @@ public: if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) return true; - if (castType->isObjCObjectPointerType()) + if (castType->isObjCRetainableType()) transformNonObjCToObjCCast(E); else transformObjCToNonObjCCast(E); @@ -139,7 +148,7 @@ private: if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->getLinkage() == ExternalLinkage) { + FD->hasExternalLinkage()) { Expr *Arg = callE->getArg(0); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { const Expr *sub = ICE->getSubExpr(); @@ -262,7 +271,78 @@ private: rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); } + void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) { + SourceManager &SM = Pass.Ctx.getSourceManager(); + SourceLocation Loc = E->getExprLoc(); + assert(Loc.isMacroID()); + SourceLocation MacroBegin, MacroEnd; + llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc); + SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange(); + SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin()); + SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd()); + + Outer = SourceRange(MacroBegin, MacroEnd); + Inner = SourceRange(InnerBegin, InnerEnd); + } + + void rewriteBlockCopyMacro(CastExpr *E) { + SourceRange OuterRange, InnerRange; + getBlockMacroRanges(E, OuterRange, InnerRange); + + Transaction Trans(Pass.TA); + Pass.TA.replace(OuterRange, InnerRange); + Pass.TA.insert(InnerRange.getBegin(), "["); + Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]"); + Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, + diag::err_arc_cast_requires_bridge, + OuterRange); + } + + void removeBlockReleaseMacro(CastExpr *E) { + SourceRange OuterRange, InnerRange; + getBlockMacroRanges(E, OuterRange, InnerRange); + + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, + diag::err_arc_cast_requires_bridge, + OuterRange); + if (!hasSideEffects(E, Pass.Ctx)) { + if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E)))) + return; + } + Pass.TA.replace(OuterRange, InnerRange); + } + + bool tryRemoving(Expr *E) const { + if (!Removables) { + Removables.reset(new ExprSet); + collectRemovables(Body, *Removables); + } + + if (Removables->count(E)) { + Pass.TA.removeStmt(E); + return true; + } + + return false; + } + void transformObjCToNonObjCCast(CastExpr *E) { + SourceLocation CastLoc = E->getExprLoc(); + if (CastLoc.isMacroID()) { + StringRef MacroName = Lexer::getImmediateMacroName(CastLoc, + Pass.Ctx.getSourceManager(), + Pass.Ctx.getLangOpts()); + if (MacroName == "Block_copy") { + rewriteBlockCopyMacro(E); + return; + } + if (MacroName == "Block_release") { + removeBlockReleaseMacro(E); + return; + } + } + if (isSelf(E->getSubExpr())) return rewriteToBridgedCast(E, OBC_Bridge); @@ -333,7 +413,7 @@ private: FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->getLinkage() == ExternalLinkage) + FD->hasExternalLinkage()) return true; return false; @@ -350,7 +430,7 @@ private: if (arg == E || arg->IgnoreParenImpCasts() == E) break; } - if (i < callE->getNumArgs()) { + if (i < callE->getNumArgs() && i < FD->getNumParams()) { ParmVarDecl *PD = FD->getParamDecl(i); if (PD->getAttr<CFConsumedAttr>()) { isConsumed = true; diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 3057e391d0a8..e316c73fc3cd 100644 --- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -1,4 +1,4 @@ -//===--- TransUnusedInitDelegate.cpp - Tranformations to ARC mode ---------===// +//===--- TransUnusedInitDelegate.cpp - Transformations to ARC mode --------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp index a07596d0cb0c..4d088e05bfab 100644 --- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp +++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -1,4 +1,4 @@ -//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===// +//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===// // // The LLVM Compiler Infrastructure // diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp index 783db1c8f3aa..2fd0619df9f8 100644 --- a/lib/ARCMigrate/TransformActions.cpp +++ b/lib/ARCMigrate/TransformActions.cpp @@ -10,8 +10,8 @@ #include "Internals.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/DenseSet.h" #include <map> using namespace clang; diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 805a67d9d188..087219535a18 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -1,4 +1,4 @@ -//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===// +//===--- Transforms.cpp - Transformations to ARC mode ---------------------===// // // The LLVM Compiler Infrastructure // @@ -9,16 +9,17 @@ #include "Transforms.h" #include "Internals.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringSwitch.h" #include <map> using namespace clang; @@ -70,13 +71,22 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) { if (E->getOpcode() != BO_Assign) return false; + return isPlusOne(E->getRHS()); +} + +bool trans::isPlusOne(const Expr *E) { + if (!E) + return false; + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) + E = EWC->getSubExpr(); + if (const ObjCMessageExpr * - ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts())) + ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts())) if (ME->getMethodFamily() == OMF_retain) return true; if (const CallExpr * - callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) { + callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) { if (const FunctionDecl *FD = callE->getDirectCallee()) { if (FD->getAttr<CFReturnsRetainedAttr>()) return true; @@ -84,7 +94,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) { if (FD->isGlobal() && FD->getIdentifier() && FD->getParent()->isTranslationUnit() && - FD->getLinkage() == ExternalLinkage && + FD->hasExternalLinkage() && ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); @@ -97,7 +107,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) { } } - const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS()); + const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E); while (implCE && implCE->getCastKind() == CK_BitCast) implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr()); @@ -188,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return DRE->getDecl()->getDeclContext()->isFileContext() && - DRE->getDecl()->getLinkage() == ExternalLinkage; + DRE->getDecl()->hasExternalLinkage(); if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); @@ -563,6 +573,7 @@ static void traverseAST(MigrationPass &pass) { } MigrateCtx.addTraverser(new PropertyRewriteTraverser()); MigrateCtx.addTraverser(new BlockObjCVariableTraverser()); + MigrateCtx.addTraverser(new ProtectedScopeTraverser()); MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl()); } diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index 5d4ac9446045..cb7d1535c628 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -1,4 +1,4 @@ -//===-- Transforms.h - Tranformations to ARC mode ---------------*- C++ -*-===// +//===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,8 +10,8 @@ #ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H #define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/SaveAndRestore.h" @@ -135,6 +135,11 @@ public: virtual void traverseBody(BodyContext &BodyCtx); }; +class ProtectedScopeTraverser : public ASTTraverser { +public: + virtual void traverseBody(BodyContext &BodyCtx); +}; + // GC transformations class GCAttrsTraverser : public ASTTraverser { @@ -156,6 +161,7 @@ bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass = false); bool isPlusOneAssign(const BinaryOperator *E); +bool isPlusOne(const Expr *E); /// \brief 'Loc' is the end of a statement range. This returns the location /// immediately after the semicolon following the statement. diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 2d7c9bd7864a..98e825b3bafb 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -19,8 +19,8 @@ #include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; namespace { @@ -348,6 +348,8 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ bool IsReference = Ty->isReferenceType(); QualType InnerTy = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); + if (InnerTy.isNull()) + InnerTy = Ty; if (!hasLValuePath()) { // No lvalue path: just print the offset. diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index a4e17c03e4e3..55033b238c66 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" -#include "clang/AST/DeclGroup.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclGroup.h" using namespace clang; bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 74c68ae627ce..7245c0316082 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -12,28 +12,29 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "CXXABI.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" -#include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/ASTMutationListener.h" -#include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" -#include "clang/AST/Comment.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Capacity.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Capacity.h" -#include "CXXABI.h" #include <map> using namespace clang; @@ -84,6 +85,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return NULL; } + if (const ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(D)) { + TemplateSpecializationKind TSK = CTSD->getSpecializationKind(); + if (TSK == TSK_ImplicitInstantiation || + TSK == TSK_Undeclared) + return NULL; + } + if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; @@ -364,10 +373,12 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, if (!ID) return; // Add redeclared method here. - for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension(); - ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = ID->known_extensions_begin(), + ExtEnd = ID->known_extensions_end(); + Ext != ExtEnd; ++Ext) { if (ObjCMethodDecl *RedeclaredMethod = - ClsExtDecl->getMethod(ObjCMethod->getSelector(), + Ext->getMethod(ObjCMethod->getSelector(), ObjCMethod->isInstanceMethod())) Redeclared.push_back(RedeclaredMethod); } @@ -412,15 +423,26 @@ comments::FullComment *ASTContext::getCommentForDecl( if (!RC) { if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { SmallVector<const NamedDecl*, 8> Overridden; - if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D); + if (OMD && OMD->isPropertyAccessor()) + if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl()) + if (comments::FullComment *FC = getCommentForDecl(PDecl, PP)) + return cloneFullComment(FC, D); + if (OMD) addRedeclaredMethods(OMD, Overridden); getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden); - for (unsigned i = 0, e = Overridden.size(); i < e; i++) { - if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) { - comments::FullComment *CFC = cloneFullComment(FC, D); - return CFC; - } - } + for (unsigned i = 0, e = Overridden.size(); i < e; i++) + if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) + return cloneFullComment(FC, D); + } + else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + // Attach any tag type's documentation to its typedef if latter + // does not have one of its own. + QualType QT = TD->getUnderlyingType(); + if (const TagType *TT = QT->getAs<TagType>()) + if (const Decl *TD = TT->getDecl()) + if (comments::FullComment *FC = getCommentForDecl(TD, PP)) + return cloneFullComment(FC, D); } return NULL; } @@ -571,12 +593,14 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { if (!LangOpts.CPlusPlus) return 0; - switch (T.getCXXABI()) { - case CXXABI_ARM: + switch (T.getCXXABI().getKind()) { + case TargetCXXABI::GenericARM: + case TargetCXXABI::iOS: return CreateARMCXXABI(*this); - case CXXABI_Itanium: + case TargetCXXABI::GenericAArch64: // Same as Itanium at this level + case TargetCXXABI::GenericItanium: return CreateItaniumCXXABI(*this); - case CXXABI_Microsoft: + case TargetCXXABI::Microsoft: return CreateMicrosoftCXXABI(*this); } llvm_unreachable("Invalid CXXABI type!"); @@ -630,9 +654,9 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, DeclarationNames(*this), ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), - CommentCommandTraits(BumpAlloc), + CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(0, 0), - UniqueBlockByRefTypeID(0) + UniqueBlockByRefTypeID(0) { if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); @@ -873,12 +897,26 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); + + if (LangOpts.OpenCL) { + InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d); + InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray); + InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer); + InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d); + InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray); + InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d); + + InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler); + InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent); + } // Builtin type for __objc_yes and __objc_no ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? SignedCharTy : BoolTy); ObjCConstantStringType = QualType(); + + ObjCSuperType = QualType(); // void * type VoidPtrTy = getPointerType(VoidTy); @@ -1411,6 +1449,22 @@ ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; + case BuiltinType::OCLSampler: + // Samplers are modeled as integers. + Width = Target->getIntWidth(); + Align = Target->getIntAlign(); + break; + case BuiltinType::OCLEvent: + case BuiltinType::OCLImage1d: + case BuiltinType::OCLImage1dArray: + case BuiltinType::OCLImage1dBuffer: + case BuiltinType::OCLImage2d: + case BuiltinType::OCLImage2dArray: + case BuiltinType::OCLImage3d: + // Currently these types are pointers to opaque types. + Width = Target->getPointerWidth(0); + Align = Target->getPointerAlign(0); + break; } break; case Type::ObjCObjectPointer: @@ -1442,10 +1496,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::MemberPointer: { const MemberPointerType *MPT = cast<MemberPointerType>(T); - std::pair<uint64_t, unsigned> PtrDiffInfo = - getTypeInfo(getPointerDiffType()); - Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT); - Align = PtrDiffInfo.second; + llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT); break; } case Type::Complex: { @@ -1548,18 +1599,21 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::Atomic: { + // Start with the base type information. 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.) + + // If the size of the type doesn't exceed the platform's max + // atomic promotion width, make the size and alignment more + // favorable to atomic operations: + if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) { + // Round the size up to a power of 2. + if (!llvm::isPowerOf2_64(Width)) + Width = llvm::NextPowerOf2(Width); + + // Set the alignment equal to the size. Align = static_cast<unsigned>(Width); } } @@ -1658,9 +1712,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } // Categories of this Interface. - for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); - CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) - CollectInheritedProtocols(CDeclChain, Protocols); + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = OI->visible_categories_begin(), + CatEnd = OI->visible_categories_end(); + Cat != CatEnd; ++Cat) { + CollectInheritedProtocols(*Cat, Protocols); + } + if (ObjCInterfaceDecl *SD = OI->getSuperClass()) while (SD) { CollectInheritedProtocols(SD, Protocols); @@ -1690,10 +1748,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { unsigned count = 0; // Count ivars declared in class extension. - for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) - count += CDecl->ivar_size(); - + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = OI->known_extensions_begin(), + ExtEnd = OI->known_extensions_end(); + Ext != ExtEnd; ++Ext) { + count += Ext->ivar_size(); + } + // Count ivar defined in this class's implementation. This // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) @@ -1750,12 +1811,16 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCImpls[CatD] = ImplD; } -ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const { - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext())) +const ObjCInterfaceDecl *ASTContext::getObjContainingInterface( + const NamedDecl *ND) const { + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext())) return ID; - if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext())) + if (const ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(ND->getDeclContext())) return CD->getClassInterface(); - if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext())) + if (const ObjCImplDecl *IMD = + dyn_cast<ObjCImplDecl>(ND->getDeclContext())) return IMD->getClassInterface(); return 0; @@ -1906,8 +1971,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, const FunctionProtoType *FPT = cast<FunctionProtoType>(T); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = Info; - Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), - FPT->getNumArgs(), EPI); + Result = getFunctionType(FPT->getResultType(), + ArrayRef<QualType>(FPT->arg_type_begin(), + FPT->getNumArgs()), + EPI); } return cast<FunctionType>(Result.getTypePtr()); @@ -2562,16 +2629,25 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, return QualType(New, 0); } +/// \brief Determine whether \p T is canonical as the result type of a function. +static bool isCanonicalResultType(QualType T) { + return T.isCanonical() && + (T.getObjCLifetime() == Qualifiers::OCL_None || + T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone); +} + /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. QualType -ASTContext::getFunctionType(QualType ResultTy, - const QualType *ArgArray, unsigned NumArgs, +ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, const FunctionProtoType::ExtProtoInfo &EPI) const { + size_t NumArgs = ArgArray.size(); + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this); + FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI, + *this); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -2580,7 +2656,7 @@ ASTContext::getFunctionType(QualType ResultTy, // Determine whether the type being created is already canonical or not. bool isCanonical = - EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() && + EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn; for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) @@ -2606,9 +2682,15 @@ ASTContext::getFunctionType(QualType ResultTy, CanonicalEPI.ExtInfo = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); - Canonical = getFunctionType(getCanonicalType(ResultTy), - CanonicalArgs.data(), NumArgs, - CanonicalEPI); + // Result types do not have ARC lifetime qualifiers. + QualType CanResultTy = getCanonicalType(ResultTy); + if (ResultTy.getQualifiers().hasObjCLifetime()) { + Qualifiers Qs = CanResultTy.getQualifiers(); + Qs.removeObjCLifetime(); + CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); + } + + Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -2641,7 +2723,7 @@ ASTContext::getFunctionType(QualType ResultTy, FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); - new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI); + new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -2877,8 +2959,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType TST = getTemplateSpecializationType(Name, Args, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); - TemplateSpecializationTypeLoc TL - = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); + TemplateSpecializationTypeLoc TL = + DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); TL.setTemplateKeywordLoc(SourceLocation()); TL.setTemplateNameLoc(NameLoc); TL.setLAngleLoc(Args.getLAngleLoc()); @@ -3154,7 +3236,7 @@ ASTContext::getDependentTemplateSpecializationType( } QualType ASTContext::getPackExpansionType(QualType Pattern, - llvm::Optional<unsigned> NumExpansions) { + Optional<unsigned> NumExpansions) { llvm::FoldingSetNodeID ID; PackExpansionType::Profile(ID, Pattern, NumExpansions); @@ -3528,6 +3610,14 @@ QualType ASTContext::getUnsignedWCharType() const { return UnsignedIntTy; } +QualType ASTContext::getIntPtrType() const { + return getFromTargetType(Target->getIntPtrType()); +} + +QualType ASTContext::getUIntPtrType() const { + return getCorrespondingUnsignedType(getIntPtrType()); +} + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType ASTContext::getPointerDiffType() const { @@ -3993,7 +4083,8 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { uint64_t ElementCount = 1; do { ElementCount *= CA->getSize().getZExtValue(); - CA = dyn_cast<ConstantArrayType>(CA->getElementType()); + CA = dyn_cast_or_null<ConstantArrayType>( + CA->getElementType()->getAsArrayTypeUnsafe()); } while (CA); return ElementCount; } @@ -4032,7 +4123,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, assert(Domain->isRealFloatingType() && "Unknown domain!"); switch (EltRank) { - case HalfRank: llvm_unreachable("Half ranks are not valid here"); + case HalfRank: return HalfTy; case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; @@ -4159,8 +4250,8 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { // At this point, we should have a signed or unsigned integer type. if (Promotable->isSignedIntegerType()) return IntTy; - uint64_t PromotableSize = getTypeSize(Promotable); - uint64_t IntSize = getTypeSize(IntTy); + uint64_t PromotableSize = getIntWidth(Promotable); + uint64_t IntSize = getIntWidth(IntTy); assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize); return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy; } @@ -4273,6 +4364,16 @@ QualType ASTContext::getCFConstantStringType() const { return getTagDeclType(CFConstantStringTypeDecl); } +QualType ASTContext::getObjCSuperType() const { + if (ObjCSuperType.isNull()) { + RecordDecl *ObjCSuperTypeDecl = + CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("objc_super")); + TUDecl->addDecl(ObjCSuperTypeDecl); + ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl); + } + return ObjCSuperType; +} + void ASTContext::setCFConstantStringType(QualType T) { const RecordType *Rec = T->getAs<RecordType>(); assert(Rec && "Invalid CFConstantStringType"); @@ -4361,78 +4462,68 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { return getTagDeclType(BlockDescriptorExtendedType); } -bool ASTContext::BlockRequiresCopying(QualType Ty) const { - if (Ty->isObjCRetainableType()) +/// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty" +/// requires copy/dispose. Note that this must match the logic +/// in buildByrefHelpers. +bool ASTContext::BlockRequiresCopying(QualType Ty, + const VarDecl *D) { + if (const CXXRecordDecl *record = Ty->getAsCXXRecordDecl()) { + const Expr *copyExpr = getBlockVarCopyInits(D); + if (!copyExpr && record->hasTrivialDestructor()) return false; + return true; - if (getLangOpts().CPlusPlus) { - if (const RecordType *RT = Ty->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - return RD->hasConstCopyConstructor(); - + } + + if (!Ty->isObjCRetainableType()) return false; + + Qualifiers qs = Ty.getQualifiers(); + + // If we have lifetime, that dominates. + if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { + assert(getLangOpts().ObjCAutoRefCount); + + switch (lifetime) { + case Qualifiers::OCL_None: llvm_unreachable("impossible"); + + // These are just bits as far as the runtime is concerned. + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + return false; + + // Tell the runtime that this is ARC __weak, called by the + // byref routines. + case Qualifiers::OCL_Weak: + // ARC __strong __block variables need to be retained. + case Qualifiers::OCL_Strong: + return true; } + llvm_unreachable("fell out of lifetime switch!"); } - return false; + return (Ty->isBlockPointerType() || isObjCNSObjectType(Ty) || + Ty->isObjCObjectPointerType()); } -QualType -ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { - // type = struct __Block_byref_1_X { - // void *__isa; - // struct __Block_byref_1_X *__forwarding; - // unsigned int __flags; - // unsigned int __size; - // void *__copy_helper; // as needed - // void *__destroy_help // as needed - // int X; - // } * - - bool HasCopyAndDispose = BlockRequiresCopying(Ty); - - // FIXME: Move up - SmallString<36> Name; - llvm::raw_svector_ostream(Name) << "__Block_byref_" << - ++UniqueBlockByRefTypeID << '_' << DeclName; - RecordDecl *T; - T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str())); - T->startDefinition(); - QualType Int32Ty = IntTy; - assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); - QualType FieldTypes[] = { - getPointerType(VoidPtrTy), - getPointerType(getTagDeclType(T)), - Int32Ty, - Int32Ty, - getPointerType(VoidPtrTy), - getPointerType(VoidPtrTy), - Ty - }; - - StringRef FieldNames[] = { - "__isa", - "__forwarding", - "__flags", - "__size", - "__copy_helper", - "__destroy_helper", - DeclName, - }; - - for (size_t i = 0; i < 7; ++i) { - if (!HasCopyAndDispose && i >=4 && i <= 5) - continue; - FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - SourceLocation(), - &Idents.get(FieldNames[i]), - FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, /*Mutable=*/false, - ICIS_NoInit); - Field->setAccess(AS_public); - T->addDecl(Field); - } - - T->completeDefinition(); - - return getPointerType(getTagDeclType(T)); +bool ASTContext::getByrefLifetime(QualType Ty, + Qualifiers::ObjCLifetime &LifeTime, + bool &HasByrefExtendedLayout) const { + + if (!getLangOpts().ObjC1 || + getLangOpts().getGC() != LangOptions::NonGC) + return false; + + HasByrefExtendedLayout = false; + if (Ty->isRecordType()) { + HasByrefExtendedLayout = true; + LifeTime = Qualifiers::OCL_None; + } + else if (getLangOpts().ObjCAutoRefCount) + LifeTime = Ty.getObjCLifetime(); + // MRR. + else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + LifeTime = Qualifiers::OCL_ExplicitNone; + else + LifeTime = Qualifiers::OCL_None; + return true; } TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { @@ -4793,17 +4884,19 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, true /* outermost type */); } -static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { - switch (T->getAs<BuiltinType>()->getKind()) { - default: llvm_unreachable("Unhandled builtin type kind"); +static char getObjCEncodingForPrimitiveKind(const ASTContext *C, + BuiltinType::Kind kind) { + switch (kind) { case BuiltinType::Void: return 'v'; case BuiltinType::Bool: return 'B'; case BuiltinType::Char_U: case BuiltinType::UChar: return 'C'; + case BuiltinType::Char16: case BuiltinType::UShort: return 'S'; + case BuiltinType::Char32: case BuiltinType::UInt: return 'I'; case BuiltinType::ULong: - return C->getIntWidth(T) == 32 ? 'L' : 'Q'; + return C->getTargetInfo().getLongWidth() == 32 ? 'L' : 'Q'; case BuiltinType::UInt128: return 'T'; case BuiltinType::ULongLong: return 'Q'; case BuiltinType::Char_S: @@ -4813,13 +4906,40 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { case BuiltinType::WChar_U: case BuiltinType::Int: return 'i'; case BuiltinType::Long: - return C->getIntWidth(T) == 32 ? 'l' : 'q'; + return C->getTargetInfo().getLongWidth() == 32 ? 'l' : 'q'; case BuiltinType::LongLong: return 'q'; case BuiltinType::Int128: return 't'; case BuiltinType::Float: return 'f'; case BuiltinType::Double: return 'd'; case BuiltinType::LongDouble: return 'D'; + case BuiltinType::NullPtr: return '*'; // like char* + + case BuiltinType::Half: + // FIXME: potentially need @encodes for these! + return ' '; + + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + llvm_unreachable("@encoding ObjC primitive type"); + + // OpenCL and placeholder types don't need @encodings. + case BuiltinType::OCLImage1d: + case BuiltinType::OCLImage1dArray: + case BuiltinType::OCLImage1dBuffer: + case BuiltinType::OCLImage2d: + case BuiltinType::OCLImage2dArray: + case BuiltinType::OCLImage3d: + case BuiltinType::OCLEvent: + case BuiltinType::OCLSampler: + case BuiltinType::Dependent: +#define BUILTIN_TYPE(KIND, ID) +#define PLACEHOLDER_TYPE(KIND, ID) \ + case BuiltinType::KIND: +#include "clang/AST/BuiltinTypes.def" + llvm_unreachable("invalid builtin type for @encode"); } + llvm_unreachable("invalid BuiltinType::Kind value"); } static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { @@ -4830,7 +4950,8 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { return 'i'; // The encoding of a fixed enum type matches its fixed underlying type. - return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType()); + const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>(); + return getObjCEncodingForPrimitiveKind(C, BT->getKind()); } static void EncodeBitField(const ASTContext *Ctx, std::string& S, @@ -4858,8 +4979,10 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); if (const EnumType *ET = T->getAs<EnumType>()) S += ObjCEncodingForEnumType(Ctx, ET); - else - S += ObjCEncodingForPrimitiveKind(Ctx, T); + else { + const BuiltinType *BT = T->castAs<BuiltinType>(); + S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind()); + } } S += llvm::utostr(FD->getBitWidthValue(*Ctx)); } @@ -4873,33 +4996,52 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool EncodingProperty, bool StructField, bool EncodeBlockParameters, - bool EncodeClassNames) const { - if (T->getAs<BuiltinType>()) { + bool EncodeClassNames, + bool EncodePointerToObjCTypedef) const { + CanQualType CT = getCanonicalType(T); + switch (CT->getTypeClass()) { + case Type::Builtin: + case Type::Enum: if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); - S += ObjCEncodingForPrimitiveKind(this, T); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT)) + S += getObjCEncodingForPrimitiveKind(this, BT->getKind()); + else + S += ObjCEncodingForEnumType(this, cast<EnumType>(CT)); return; - } - if (const ComplexType *CT = T->getAs<ComplexType>()) { + case Type::Complex: { + const ComplexType *CT = T->castAs<ComplexType>(); S += 'j'; getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, false); return; } - - // encoding for pointer or r3eference types. - QualType PointeeTy; - if (const PointerType *PT = T->getAs<PointerType>()) { - if (PT->isObjCSelType()) { - S += ':'; - return; - } - PointeeTy = PT->getPointeeType(); + + case Type::Atomic: { + const AtomicType *AT = T->castAs<AtomicType>(); + S += 'A'; + getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0, + false, false); + return; } - else if (const ReferenceType *RT = T->getAs<ReferenceType>()) - PointeeTy = RT->getPointeeType(); - if (!PointeeTy.isNull()) { + + // encoding for pointer or reference types. + case Type::Pointer: + case Type::LValueReference: + case Type::RValueReference: { + QualType PointeeTy; + if (isa<PointerType>(CT)) { + const PointerType *PT = T->castAs<PointerType>(); + if (PT->isObjCSelType()) { + S += ':'; + return; + } + PointeeTy = PT->getPointeeType(); + } else { + PointeeTy = T->castAs<ReferenceType>()->getPointeeType(); + } + bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -4954,10 +5096,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, NULL); return; } - - if (const ArrayType *AT = - // Ignore type qualifiers etc. - dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { + + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: { + const ArrayType *AT = cast<ArrayType>(CT); + if (isa<IncompleteArrayType>(AT) && !StructField) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; @@ -4986,13 +5130,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - if (T->getAs<FunctionType>()) { + case Type::FunctionNoProto: + case Type::FunctionProto: S += '?'; return; - } - if (const RecordType *RTy = T->getAs<RecordType>()) { - RecordDecl *RDecl = RTy->getDecl(); + case Type::Record: { + RecordDecl *RDecl = cast<RecordType>(CT)->getDecl(); S += RDecl->isUnion() ? '(' : '{'; // Anonymous structures print as '?' if (const IdentifierInfo *II = RDecl->getIdentifier()) { @@ -5000,13 +5144,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( + llvm::raw_string_ostream OS(S); + TemplateSpecializationType::PrintTemplateArgumentList(OS, TemplateArgs.data(), TemplateArgs.size(), (*this).getPrintingPolicy()); - - S += TemplateArgsStr; } } else { S += '?'; @@ -5043,19 +5185,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += RDecl->isUnion() ? ')' : '}'; return; } - - if (const EnumType *ET = T->getAs<EnumType>()) { - if (FD && FD->isBitField()) - EncodeBitField(this, S, T, FD); - else - S += ObjCEncodingForEnumType(this, ET); - return; - } - if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { + case Type::BlockPointer: { + const BlockPointerType *BT = T->castAs<BlockPointerType>(); S += "@?"; // Unlike a pointer-to-function, which is "^?". if (EncodeBlockParameters) { - const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); + const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>(); S += '<'; // Block return type @@ -5089,11 +5224,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - // Ignore protocol qualifiers when mangling at this level. - if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>()) - T = OT->getBaseType(); + case Type::ObjCObject: + case Type::ObjCInterface: { + // Ignore protocol qualifiers when mangling at this level. + T = T->castAs<ObjCObjectType>()->getBaseType(); - if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { + // The assumption seems to be that this assert will succeed + // because nested levels will have filtered out 'id' and 'Class'. + const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>(); // @encode(class_name) ObjCInterfaceDecl *OI = OIT->getDecl(); S += '{'; @@ -5107,13 +5245,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (Field->isBitField()) getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); else - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD); + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD, + false, false, false, false, false, + EncodePointerToObjCTypedef); } S += '}'; return; } - if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) { + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>(); if (OPT->isObjCIdType()) { S += '@'; return; @@ -5148,14 +5289,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, QualType PointeeTy = OPT->getPointeeType(); if (!EncodingProperty && - isa<TypedefType>(PointeeTy.getTypePtr())) { + isa<TypedefType>(PointeeTy.getTypePtr()) && + !EncodePointerToObjCTypedef) { // Another historical/compatibility reason. // We encode the underlying type which comes out as // {...}; S += '^'; getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, - NULL); + NULL, + false, false, false, false, false, + /*EncodePointerToObjCTypedef*/true); return; } @@ -5176,18 +5320,29 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } // gcc just blithely ignores member pointers. - // TODO: maybe there should be a mangling for these - if (T->getAs<MemberPointerType>()) + // FIXME: we shoul do better than that. 'M' is available. + case Type::MemberPointer: return; - if (T->isVectorType()) { + case Type::Vector: + case Type::ExtVector: // This matches gcc's encoding, even though technically it is // insufficient. // FIXME. We should do a better job than gcc. return; + +#define ABSTRACT_TYPE(KIND, BASE) +#define TYPE(KIND, BASE) +#define DEPENDENT_TYPE(KIND, BASE) \ + case Type::KIND: +#define NON_CANONICAL_TYPE(KIND, BASE) \ + case Type::KIND: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \ + case Type::KIND: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("@encode for dependent type!"); } - - llvm_unreachable("@encode for type not implemented!"); + llvm_unreachable("bad type kind!"); } void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, @@ -5426,6 +5581,85 @@ static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) { return VaListTypeDecl; } +static TypedefDecl * +CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) { + RecordDecl *VaListTagDecl; + if (Context->getLangOpts().CPlusPlus) { + // namespace std { struct __va_list { + NamespaceDecl *NS; + NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + /*Inline*/false, SourceLocation(), + SourceLocation(), &Context->Idents.get("std"), + /*PrevDecl*/0); + + VaListTagDecl = CXXRecordDecl::Create(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__va_list")); + VaListTagDecl->setDeclContext(NS); + } else { + // struct __va_list + VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + &Context->Idents.get("__va_list")); + } + + VaListTagDecl->startDefinition(); + + const size_t NumFields = 5; + QualType FieldTypes[NumFields]; + const char *FieldNames[NumFields]; + + // void *__stack; + FieldTypes[0] = Context->getPointerType(Context->VoidTy); + FieldNames[0] = "__stack"; + + // void *__gr_top; + FieldTypes[1] = Context->getPointerType(Context->VoidTy); + FieldNames[1] = "__gr_top"; + + // void *__vr_top; + FieldTypes[2] = Context->getPointerType(Context->VoidTy); + FieldNames[2] = "__vr_top"; + + // int __gr_offs; + FieldTypes[3] = Context->IntTy; + FieldNames[3] = "__gr_offs"; + + // int __vr_offs; + FieldTypes[4] = Context->IntTy; + FieldNames[4] = "__vr_offs"; + + // Create fields + for (unsigned i = 0; i < NumFields; ++i) { + FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context), + VaListTagDecl, + SourceLocation(), + SourceLocation(), + &Context->Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit); + Field->setAccess(AS_public); + VaListTagDecl->addDecl(Field); + } + VaListTagDecl->completeDefinition(); + QualType VaListTagType = Context->getRecordType(VaListTagDecl); + Context->VaListTagTy = VaListTagType; + + // } __builtin_va_list; + TypedefDecl *VaListTypedefDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__builtin_va_list"), + Context->getTrivialTypeSourceInfo(VaListTagType)); + + return VaListTypedefDecl; +} + static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) { // typedef struct __va_list_tag { RecordDecl *VaListTagDecl; @@ -5659,6 +5893,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreateCharPtrBuiltinVaListDecl(Context); case TargetInfo::VoidPtrBuiltinVaList: return CreateVoidPtrBuiltinVaListDecl(Context); + case TargetInfo::AArch64ABIBuiltinVaList: + return CreateAArch64ABIBuiltinVaListDecl(Context); case TargetInfo::PowerABIBuiltinVaList: return CreatePowerABIBuiltinVaListDecl(Context); case TargetInfo::X86_64ABIBuiltinVaList: @@ -6496,14 +6732,14 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) return QualType(); - // functypes which return are preferred over those that do not. - if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn()) - allLTypes = false; - 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(); + if (lbaseInfo.getNoReturn() != NoReturn) + allLTypes = false; + if (rbaseInfo.getNoReturn() != NoReturn) + allRTypes = false; + FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); if (lproto && rproto) { // two C99 style function prototypes @@ -6557,7 +6793,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo(); EPI.ExtInfo = einfo; - return getFunctionType(retType, types.begin(), types.size(), EPI); + return getFunctionType(retType, types, EPI); } if (lproto) allRTypes = false; @@ -6594,8 +6830,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); EPI.ExtInfo = einfo; - return getFunctionType(retType, proto->arg_type_begin(), - proto->getNumArgs(), EPI); + return getFunctionType(retType, + ArrayRef<QualType>(proto->arg_type_begin(), + proto->getNumArgs()), + EPI); } if (allLTypes) return lhs; @@ -6603,6 +6841,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return getFunctionNoProtoType(retType, einfo); } +/// Given that we have an enum type and a non-enum type, try to merge them. +static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, + QualType other, bool isBlockReturnType) { + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. + QualType underlyingType = ET->getDecl()->getIntegerType(); + if (underlyingType.isNull()) return QualType(); + if (Context.hasSameType(underlyingType, other)) + return other; + + // In block return types, we're more permissive and accept any + // integral type of the same size. + if (isBlockReturnType && other->isIntegerType() && + Context.getTypeSize(underlyingType) == Context.getTypeSize(other)) + return other; + + return QualType(); +} + QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, bool Unqualified, bool BlockReturnType) { @@ -6684,19 +6943,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // If the canonical type classes don't match. if (LHSClass != RHSClass) { - // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, - // a signed integer type, or an unsigned integer type. - // Compatibility is based on the underlying type, not the promotion - // type. + // Note that we only have special rules for turning block enum + // returns into block int returns, not vice-versa. if (const EnumType* ETy = LHS->getAs<EnumType>()) { - QualType TINT = ETy->getDecl()->getIntegerType(); - if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType())) - return RHS; + return mergeEnumWithInteger(*this, ETy, RHS, false); } if (const EnumType* ETy = RHS->getAs<EnumType>()) { - QualType TINT = ETy->getDecl()->getIntegerType(); - if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType())) - return LHS; + return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType); } // allow block pointer type to match an 'id' type. if (OfBlockPointer && !BlockReturnType) { @@ -6928,8 +7181,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = getFunctionExtInfo(LHS); QualType ResultType - = getFunctionType(OldReturnType, FPT->arg_type_begin(), - FPT->getNumArgs(), EPI); + = getFunctionType(OldReturnType, + ArrayRef<QualType>(FPT->arg_type_begin(), + FPT->getNumArgs()), + EPI); return ResultType; } } @@ -7137,6 +7392,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, case 'H': Type = Context.getObjCSelType(); break; + case 'M': + Type = Context.getObjCSuperType(); + break; case 'a': Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); @@ -7318,7 +7576,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, EPI.ExtInfo = EI; EPI.Variadic = Variadic; - return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI); + return getFunctionType(ResType, ArgTypes, EPI); } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { @@ -7383,9 +7641,6 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { TSK = VD->getTemplateSpecializationKind(); Linkage L = VD->getLinkage(); - if (L == ExternalLinkage && getLangOpts().CPlusPlus && - VD->getType()->getLinkage() == UniqueExternalLinkage) - L = UniqueExternalLinkage; switch (L) { case NoLinkage: @@ -7418,7 +7673,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (!VD->isFileVarDecl()) return false; - } else if (!isa<FunctionDecl>(D)) + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // We never need to emit an uninstantiated function template. + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return false; + } else + return false; + + // If this is a member of a class template, we do not need to emit it. + if (D->getDeclContext()->isDependentContext()) return false; // Weak references don't produce any output by themselves. @@ -7438,13 +7701,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) return true; - // The key function for a class is required. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - const CXXRecordDecl *RD = MD->getParent(); - if (MD->isOutOfLine() && RD->isDynamicClass()) { - const CXXMethodDecl *KeyFunc = getKeyFunction(RD); - if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) - return true; + // The key function for a class is required. This rule only comes + // into play when inline functions can be key functions, though. + if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD); + if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) + return true; + } } } @@ -7465,27 +7731,20 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) return false; - // Structs that have non-trivial constructors or destructors are required. + // Variables that can be needed in other TUs are required. + GVALinkage L = GetGVALinkageForVariable(VD); + if (L != GVA_Internal && L != GVA_TemplateInstantiation) + return true; - // FIXME: Handle references. - // FIXME: Be more selective about which constructors we care about. - if (const RecordType *RT = VD->getType()->getAs<RecordType>()) { - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() && - RD->hasTrivialCopyConstructor() && - RD->hasTrivialMoveConstructor() && - RD->hasTrivialDestructor())) - return true; - } - } + // Variables that have destruction with side-effects are required. + if (VD->getType().isDestructedType()) + return true; - GVALinkage L = GetGVALinkageForVariable(VD); - if (L == GVA_Internal || L == GVA_TemplateInstantiation) { - if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this))) - return false; - } + // Variables that have initialization with side-effects are required. + if (VD->getInit() && VD->getInit()->HasSideEffects(*this)) + return true; - return true; + return false; } CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) { @@ -7494,7 +7753,8 @@ CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) { } CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const { - if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft) + if (CC == CC_C && !LangOpts.MRTD && + getTargetInfo().getCXXABI().isMemberFunctionCCDefault()) return CC_Default; return CC; } @@ -7505,11 +7765,13 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { } MangleContext *ASTContext::createMangleContext() { - switch (Target->getCXXABI()) { - case CXXABI_ARM: - case CXXABI_Itanium: + switch (Target->getCXXABI().getKind()) { + case TargetCXXABI::GenericAArch64: + case TargetCXXABI::GenericItanium: + case TargetCXXABI::GenericARM: + case TargetCXXABI::iOS: return createItaniumMangleContext(*this, getDiagnostics()); - case CXXABI_Microsoft: + case TargetCXXABI::Microsoft: return createMicrosoftMangleContext(*this, getDiagnostics()); } llvm_unreachable("Unsupported ABI"); @@ -7534,6 +7796,23 @@ size_t ASTContext::getSideTableAllocatedMemory() const { + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); } +void ASTContext::addUnnamedTag(const TagDecl *Tag) { + // FIXME: This mangling should be applied to function local classes too + if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() || + !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage) + return; + + std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P = + UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0)); + UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++)); +} + +int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const { + llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I = + UnnamedMangleNumbers.find(Tag); + return I != UnnamedMangleNumbers.end() ? I->second : -1; +} + unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { CXXRecordDecl *Lambda = CallOperator->getParent(); return LambdaMangleContexts[Lambda->getDeclContext()] diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 0b9c5249448f..1ed65e476ce3 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -11,12 +11,11 @@ // //===----------------------------------------------------------------------===// #include "clang/AST/ASTDiagnostic.h" - #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/TemplateBase.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -232,7 +231,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, QualType ToType, bool PrintTree, bool PrintFromType, bool ElideType, - bool ShowColors, std::string &S); + bool ShowColors, raw_ostream &OS); void clang::FormatASTNodeDiagnosticArgument( DiagnosticsEngine::ArgumentKind Kind, @@ -248,7 +247,8 @@ void clang::FormatASTNodeDiagnosticArgument( ArrayRef<intptr_t> QualTypeVals) { ASTContext &Context = *static_cast<ASTContext*>(Cookie); - std::string S; + size_t OldEnd = Output.size(); + llvm::raw_svector_ostream OS(Output); bool NeedQuotes = true; switch (Kind) { @@ -262,7 +262,7 @@ void clang::FormatASTNodeDiagnosticArgument( if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree, TDT.PrintFromType, TDT.ElideType, - TDT.ShowColors, S)) { + TDT.ShowColors, OS)) { NeedQuotes = !TDT.PrintTree; TDT.TemplateDiffUsed = true; break; @@ -273,7 +273,7 @@ void clang::FormatASTNodeDiagnosticArgument( if (TDT.PrintTree) return; - // Attempting to do a templete diff on non-templates. Set the variables + // Attempting to do a template diff on non-templates. Set the variables // and continue with regular type printing of the appropriate type. Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType; ModLen = 0; @@ -285,23 +285,23 @@ void clang::FormatASTNodeDiagnosticArgument( "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); - S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs, - QualTypeVals); + OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs, + QualTypeVals); NeedQuotes = false; break; } case DiagnosticsEngine::ak_declarationname: { - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - S = N.getAsString(); - if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) - S = '+' + S; + OS << '+'; else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0) - S = '-' + S; + OS << '-'; else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); + + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + N.printName(OS); break; } case DiagnosticsEngine::ak_nameddecl: { @@ -314,13 +314,12 @@ void clang::FormatASTNodeDiagnosticArgument( Qualified = false; } const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val); - ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified); + ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified); break; } case DiagnosticsEngine::ak_nestednamespec: { - llvm::raw_string_ostream OS(S); - reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, - Context.getPrintingPolicy()); + NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val); + NNS->print(OS, Context.getPrintingPolicy()); NeedQuotes = false; break; } @@ -331,39 +330,39 @@ void clang::FormatASTNodeDiagnosticArgument( if (DC->isTranslationUnit()) { // FIXME: Get these strings from some localized place if (Context.getLangOpts().CPlusPlus) - S = "the global namespace"; + OS << "the global namespace"; else - S = "the global scope"; + OS << "the global scope"; } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { - S = ConvertTypeToDiagnosticString(Context, - Context.getTypeDeclType(Type), - PrevArgs, NumPrevArgs, QualTypeVals); + OS << ConvertTypeToDiagnosticString(Context, + Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs, + QualTypeVals); } else { // FIXME: Get these strings from some localized place NamedDecl *ND = cast<NamedDecl>(DC); if (isa<NamespaceDecl>(ND)) - S += "namespace "; + OS << "namespace "; else if (isa<ObjCMethodDecl>(ND)) - S += "method "; + OS << "method "; else if (isa<FunctionDecl>(ND)) - S += "function "; - - S += "'"; - ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true); - S += "'"; + OS << "function "; + + OS << '\''; + ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true); + OS << '\''; } NeedQuotes = false; break; } } - - if (NeedQuotes) - Output.push_back('\''); - - Output.append(S.begin(), S.end()); - - if (NeedQuotes) + + OS.flush(); + + if (NeedQuotes) { + Output.insert(Output.begin()+OldEnd, '\''); Output.push_back('\''); + } } /// TemplateDiff - A class that constructs a pretty string for a pair of @@ -396,21 +395,39 @@ class TemplateDiff { /// will this type be outputed. QualType ToType; - /// Str - Storage for the output stream. - llvm::SmallString<128> Str; - /// OS - The stream used to construct the output strings. - llvm::raw_svector_ostream OS; + raw_ostream &OS; /// IsBold - Keeps track of the bold formatting for the output string. bool IsBold; /// DiffTree - A tree representation the differences between two types. class DiffTree { + public: + /// DiffKind - The difference in a DiffNode and which fields are used. + enum DiffKind { + /// Incomplete or invalid node. + Invalid, + /// Another level of templates, uses TemplateDecl and Qualifiers + Template, + /// Type difference, uses QualType + Type, + /// Expression difference, uses Expr + Expression, + /// Template argument difference, uses TemplateDecl + TemplateTemplate, + /// Integer difference, uses APSInt and Expr + Integer, + /// Declaration difference, uses ValueDecl + Declaration + }; + private: /// DiffNode - The root node stores the original type. Each child node /// stores template arguments of their parents. For templated types, the /// template decl is also stored. struct DiffNode { + DiffKind Kind; + /// NextNode - The index of the next sibling node or 0. unsigned NextNode; @@ -439,6 +456,9 @@ class TemplateDiff { /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid. bool IsValidFromInt, IsValidToInt; + /// FromValueDecl, ToValueDecl - Whether the argument is a decl. + ValueDecl *FromValueDecl, *ToValueDecl; + /// FromDefault, ToDefault - Whether the argument is a default argument. bool FromDefault, ToDefault; @@ -446,13 +466,14 @@ class TemplateDiff { bool Same; DiffNode(unsigned ParentNode = 0) - : NextNode(0), ChildNode(0), ParentNode(ParentNode), + : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode), FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0), - FromDefault(false), ToDefault(false), Same(false) { } + IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0), + ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { } }; /// FlatTree - A flattened tree used to store the DiffNodes. - llvm::SmallVector<DiffNode, 16> FlatTree; + SmallVector<DiffNode, 16> FlatTree; /// CurrentNode - The index of the current node being used. unsigned CurrentNode; @@ -504,6 +525,12 @@ class TemplateDiff { FlatTree[CurrentNode].ToQual = ToQual; } + /// SetNode - Set FromValueDecl and ToValueDecl of the current node. + void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) { + FlatTree[CurrentNode].FromValueDecl = FromValueDecl; + FlatTree[CurrentNode].ToValueDecl = ToValueDecl; + } + /// SetSame - Sets the same flag of the current node. void SetSame(bool Same) { FlatTree[CurrentNode].Same = Same; @@ -515,6 +542,11 @@ class TemplateDiff { FlatTree[CurrentNode].ToDefault = ToDefault; } + /// SetKind - Sets the current node's type. + void SetKind(DiffKind Kind) { + FlatTree[CurrentNode].Kind = Kind; + } + /// Up - Changes the node to the parent of the current node. void Up() { CurrentNode = FlatTree[CurrentNode].ParentNode; @@ -554,39 +586,6 @@ class TemplateDiff { ReadNode = FlatTree[ReadNode].ParentNode; } - /// NodeIsTemplate - Returns true if a template decl is set, and types are - /// set. - bool NodeIsTemplate() { - return (FlatTree[ReadNode].FromTD && - !FlatTree[ReadNode].ToType.isNull()) || - (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull()); - } - - /// NodeIsQualType - Returns true if a Qualtype is set. - bool NodeIsQualType() { - return !FlatTree[ReadNode].FromType.isNull() || - !FlatTree[ReadNode].ToType.isNull(); - } - - /// NodeIsExpr - Returns true if an expr is set. - bool NodeIsExpr() { - return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr; - } - - /// NodeIsTemplateTemplate - Returns true if the argument is a template - /// template type. - bool NodeIsTemplateTemplate() { - return FlatTree[ReadNode].FromType.isNull() && - FlatTree[ReadNode].ToType.isNull() && - (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD); - } - - /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's. - bool NodeIsAPSInt() { - return FlatTree[ReadNode].IsValidFromInt || - FlatTree[ReadNode].IsValidToInt; - } - /// GetNode - Gets the FromType and ToType. void GetNode(QualType &FromType, QualType &ToType) { FromType = FlatTree[ReadNode].FromType; @@ -620,6 +619,12 @@ class TemplateDiff { ToQual = FlatTree[ReadNode].ToQual; } + /// GetNode - Gets the FromValueDecl and ToValueDecl. + void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) { + FromValueDecl = FlatTree[ReadNode].FromValueDecl; + ToValueDecl = FlatTree[ReadNode].ToValueDecl; + } + /// NodeIsSame - Returns true the arguments are the same. bool NodeIsSame() { return FlatTree[ReadNode].Same; @@ -662,9 +667,12 @@ class TemplateDiff { /// Empty - Returns true if the tree has no information. bool Empty() { - return !FlatTree[0].FromTD && !FlatTree[0].ToTD && - !FlatTree[0].FromExpr && !FlatTree[0].ToExpr && - FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull(); + return GetKind() == Invalid; + } + + /// GetKind - Returns the current node's type. + DiffKind GetKind() { + return FlatTree[ReadNode].Kind; } }; @@ -681,6 +689,10 @@ class TemplateDiff { /// traverse over. const TemplateSpecializationType *TST; + /// DesugarTST - desugared template specialization used to extract + /// default argument information + const TemplateSpecializationType *DesugarTST; + /// Index - the index of the template argument in TST. unsigned Index; @@ -693,8 +705,10 @@ class TemplateDiff { /// TSTiterator - Constructs an iterator and sets it to the first template /// argument. - TSTiterator(const TemplateSpecializationType *TST) - : TST(TST), Index(0), CurrentTA(0), EndTA(0) { + TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST) + : TST(TST), + DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())), + Index(0), CurrentTA(0), EndTA(0) { if (isEnd()) return; // Set to first template argument. If not a parameter pack, done. @@ -715,12 +729,17 @@ class TemplateDiff { /// isEnd - Returns true if the iterator is one past the end. bool isEnd() const { - return Index == TST->getNumArgs(); + return Index >= TST->getNumArgs(); } /// &operator++ - Increment the iterator to the next template argument. TSTiterator &operator++() { - assert(!isEnd() && "Iterator incremented past end of arguments."); + // After the end, Index should be the default argument position in + // DesugarTST, if it exists. + if (isEnd()) { + ++Index; + return *this; + } // If in a parameter pack, advance in the parameter pack. if (CurrentTA != EndTA) { @@ -761,6 +780,11 @@ class TemplateDiff { pointer operator->() const { return &operator*(); } + + /// getDesugar - Returns the deduced template argument from DesguarTST + reference getDesugar() const { + return DesugarTST->getArg(Index); + } }; // These functions build up the template diff tree, including functions to @@ -787,7 +811,7 @@ class TemplateDiff { TemplateName(CTSD->getSpecializedTemplate()), CTSD->getTemplateArgs().data(), CTSD->getTemplateArgs().size(), - Ty.getCanonicalType()); + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs<TemplateSpecializationType>(); } @@ -800,7 +824,7 @@ class TemplateDiff { TemplateParameterList *Params = FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); unsigned TotalArgs = 0; - for (TSTiterator FromIter(FromTST), ToIter(ToTST); + for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { Tree.AddNode(); @@ -814,11 +838,12 @@ class TemplateDiff { if (TemplateTypeParmDecl *DefaultTTPD = dyn_cast<TemplateTypeParmDecl>(ParamND)) { QualType FromType, ToType; - GetType(FromIter, DefaultTTPD, FromType); - GetType(ToIter, DefaultTTPD, ToType); + FromType = GetType(FromIter, DefaultTTPD); + ToType = GetType(ToIter, DefaultTTPD); Tree.SetNode(FromType, ToType); Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), ToIter.isEnd() && !ToType.isNull()); + Tree.SetKind(DiffTree::Type); if (!FromType.isNull() && !ToType.isNull()) { if (Context.hasSameType(FromType, ToType)) { Tree.SetSame(true); @@ -837,6 +862,7 @@ class TemplateDiff { Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), ToArgTST->getTemplateName().getAsTemplateDecl()); Tree.SetNode(FromQual, ToQual); + Tree.SetKind(DiffTree::Template); DiffTemplate(FromArgTST, ToArgTST); } } @@ -846,41 +872,83 @@ class TemplateDiff { // Handle Expressions if (NonTypeTemplateParmDecl *DefaultNTTPD = dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { - Expr *FromExpr, *ToExpr; + Expr *FromExpr = 0, *ToExpr = 0; llvm::APSInt FromInt, ToInt; + ValueDecl *FromValueDecl = 0, *ToValueDecl = 0; + unsigned ParamWidth = 128; // Safe default + if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) + ParamWidth = Context.getIntWidth(DefaultNTTPD->getType()); bool HasFromInt = !FromIter.isEnd() && FromIter->getKind() == TemplateArgument::Integral; bool HasToInt = !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::Integral; - //bool IsValidFromInt = false, IsValidToInt = false; + bool HasFromValueDecl = + !FromIter.isEnd() && + FromIter->getKind() == TemplateArgument::Declaration; + bool HasToValueDecl = + !ToIter.isEnd() && + ToIter->getKind() == TemplateArgument::Declaration; + + assert(((!HasFromInt && !HasToInt) || + (!HasFromValueDecl && !HasToValueDecl)) && + "Template argument cannot be both integer and declaration"); + if (HasFromInt) FromInt = FromIter->getAsIntegral(); + else if (HasFromValueDecl) + FromValueDecl = FromIter->getAsDecl(); else - GetExpr(FromIter, DefaultNTTPD, FromExpr); + FromExpr = GetExpr(FromIter, DefaultNTTPD); if (HasToInt) ToInt = ToIter->getAsIntegral(); + else if (HasToValueDecl) + ToValueDecl = ToIter->getAsDecl(); else - GetExpr(ToIter, DefaultNTTPD, ToExpr); + ToExpr = GetExpr(ToIter, DefaultNTTPD); - if (!HasFromInt && !HasToInt) { + if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) { Tree.SetNode(FromExpr, ToExpr); - Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr); - } else { + if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) { + if (FromExpr) + FromInt = GetInt(FromIter, FromExpr); + if (ToExpr) + ToInt = GetInt(ToIter, ToExpr); + Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr); + Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); + Tree.SetKind(DiffTree::Integer); + } else { + Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr)); + Tree.SetKind(DiffTree::Expression); + } + } else if (HasFromInt || HasToInt) { if (!HasFromInt && FromExpr) { - FromInt = FromExpr->EvaluateKnownConstInt(Context); + FromInt = GetInt(FromIter, FromExpr); HasFromInt = true; } if (!HasToInt && ToExpr) { - ToInt = ToExpr->EvaluateKnownConstInt(Context); + ToInt = GetInt(ToIter, ToExpr); HasToInt = true; } Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); - Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt)); + Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); Tree.SetDefault(FromIter.isEnd() && HasFromInt, ToIter.isEnd() && HasToInt); + Tree.SetKind(DiffTree::Integer); + } else { + if (!HasFromValueDecl && FromExpr) + FromValueDecl = GetValueDecl(FromIter, FromExpr); + if (!HasToValueDecl && ToExpr) + ToValueDecl = GetValueDecl(ToIter, ToExpr); + Tree.SetNode(FromValueDecl, ToValueDecl); + Tree.SetSame(FromValueDecl && ToValueDecl && + FromValueDecl->getCanonicalDecl() == + ToValueDecl->getCanonicalDecl()); + Tree.SetDefault(FromIter.isEnd() && FromValueDecl, + ToIter.isEnd() && ToValueDecl); + Tree.SetKind(DiffTree::Declaration); } } @@ -888,15 +956,17 @@ class TemplateDiff { if (TemplateTemplateParmDecl *DefaultTTPD = dyn_cast<TemplateTemplateParmDecl>(ParamND)) { TemplateDecl *FromDecl, *ToDecl; - GetTemplateDecl(FromIter, DefaultTTPD, FromDecl); - GetTemplateDecl(ToIter, DefaultTTPD, ToDecl); + FromDecl = GetTemplateDecl(FromIter, DefaultTTPD); + ToDecl = GetTemplateDecl(ToIter, DefaultTTPD); Tree.SetNode(FromDecl, ToDecl); - Tree.SetSame(FromDecl && ToDecl && - FromDecl->getIdentifier() == ToDecl->getIdentifier()); + Tree.SetSame( + FromDecl && ToDecl && + FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); + Tree.SetKind(DiffTree::TemplateTemplate); } - if (!FromIter.isEnd()) ++FromIter; - if (!ToIter.isEnd()) ++ToIter; + ++FromIter; + ++ToIter; Tree.Up(); } } @@ -917,8 +987,8 @@ class TemplateDiff { /// even if the template arguments are not. static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST, const TemplateSpecializationType *ToTST) { - return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() == - ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier(); + return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() == + ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl(); } /// hasSameTemplate - Returns true if both types are specialized from the @@ -962,22 +1032,21 @@ class TemplateDiff { /// GetType - Retrieves the template type arguments, including default /// arguments. - void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD, - QualType &ArgType) { - ArgType = QualType(); + QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); if (!Iter.isEnd()) - ArgType = Iter->getAsType(); - else if (!isVariadic) - ArgType = DefaultTTPD->getDefaultArgument(); + return Iter->getAsType(); + if (!isVariadic) + return DefaultTTPD->getDefaultArgument(); + + return QualType(); } /// GetExpr - Retrieves the template expression argument, including default /// arguments. - void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD, - Expr *&ArgExpr) { - ArgExpr = 0; + Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) { + Expr *ArgExpr = 0; bool isVariadic = DefaultNTTPD->isParameterPack(); if (!Iter.isEnd()) @@ -989,14 +1058,50 @@ class TemplateDiff { while (SubstNonTypeTemplateParmExpr *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr)) ArgExpr = SNTTPE->getReplacement(); + + return ArgExpr; + } + + /// GetInt - Retrieves the template integer argument, including evaluating + /// default arguments. + llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) { + // Default, value-depenedent expressions require fetching + // from the desugared TemplateArgument + if (Iter.isEnd() && ArgExpr->isValueDependent()) + switch (Iter.getDesugar().getKind()) { + case TemplateArgument::Integral: + return Iter.getDesugar().getAsIntegral(); + case TemplateArgument::Expression: + ArgExpr = Iter.getDesugar().getAsExpr(); + return ArgExpr->EvaluateKnownConstInt(Context); + default: + assert(0 && "Unexpected template argument kind"); + } + return ArgExpr->EvaluateKnownConstInt(Context); + } + + /// GetValueDecl - Retrieves the template integer argument, including + /// default expression argument. + ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { + // Default, value-depenedent expressions require fetching + // from the desugared TemplateArgument + if (Iter.isEnd() && ArgExpr->isValueDependent()) + switch (Iter.getDesugar().getKind()) { + case TemplateArgument::Declaration: + return Iter.getDesugar().getAsDecl(); + case TemplateArgument::Expression: + ArgExpr = Iter.getDesugar().getAsExpr(); + return cast<DeclRefExpr>(ArgExpr)->getDecl(); + default: + assert(0 && "Unexpected template argument kind"); + } + return cast<DeclRefExpr>(ArgExpr)->getDecl(); } /// GetTemplateDecl - Retrieves the template template arguments, including /// default arguments. - void GetTemplateDecl(const TSTiterator &Iter, - TemplateTemplateParmDecl *DefaultTTPD, - TemplateDecl *&ArgDecl) { - ArgDecl = 0; + TemplateDecl *GetTemplateDecl(const TSTiterator &Iter, + TemplateTemplateParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument(); @@ -1005,13 +1110,25 @@ class TemplateDiff { DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); if (!Iter.isEnd()) - ArgDecl = Iter->getAsTemplate().getAsTemplateDecl(); - else if (!isVariadic) - ArgDecl = DefaultTD; + return Iter->getAsTemplate().getAsTemplateDecl(); + if (!isVariadic) + return DefaultTD; + + return 0; + } + + /// IsSameConvertedInt - Returns true if both integers are equal when + /// converted to an integer type with the given width. + static bool IsSameConvertedInt(unsigned Width, const llvm::APSInt &X, + const llvm::APSInt &Y) { + llvm::APInt ConvertedX = X.extOrTrunc(Width); + llvm::APInt ConvertedY = Y.extOrTrunc(Width); + return ConvertedX == ConvertedY; } /// IsEqualExpr - Returns true if the expressions evaluate to the same value. - static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) { + static bool IsEqualExpr(ASTContext &Context, unsigned ParamWidth, + Expr *FromExpr, Expr *ToExpr) { if (FromExpr == ToExpr) return true; @@ -1033,7 +1150,7 @@ class TemplateDiff { Expr::EvalResult FromResult, ToResult; if (!FromExpr->EvaluateAsRValue(FromResult, Context) || !ToExpr->EvaluateAsRValue(ToResult, Context)) - assert(0 && "Template arguments must be known at compile time."); + return false; APValue &FromVal = FromResult.Val; APValue &ToVal = ToResult.Val; @@ -1042,7 +1159,7 @@ class TemplateDiff { switch (FromVal.getKind()) { case APValue::Int: - return FromVal.getInt() == ToVal.getInt(); + return IsSameConvertedInt(ParamWidth, FromVal.getInt(), ToVal.getInt()); case APValue::LValue: { APValue::LValueBase FromBase = FromVal.getLValueBase(); APValue::LValueBase ToBase = ToVal.getLValueBase(); @@ -1068,81 +1185,97 @@ class TemplateDiff { void TreeToString(int Indent = 1) { if (PrintTree) { OS << '\n'; - for (int i = 0; i < Indent; ++i) - OS << " "; + OS.indent(2 * Indent); ++Indent; } // Handle cases where the difference is not templates with different // arguments. - if (!Tree.NodeIsTemplate()) { - if (Tree.NodeIsQualType()) { + switch (Tree.GetKind()) { + case DiffTree::Invalid: + llvm_unreachable("Template diffing failed with bad DiffNode"); + case DiffTree::Type: { QualType FromType, ToType; Tree.GetNode(FromType, ToType); PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - if (Tree.NodeIsExpr()) { + case DiffTree::Expression: { Expr *FromExpr, *ToExpr; Tree.GetNode(FromExpr, ToExpr); PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - if (Tree.NodeIsTemplateTemplate()) { + case DiffTree::TemplateTemplate: { TemplateDecl *FromTD, *ToTD; Tree.GetNode(FromTD, ToTD); PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } - - if (Tree.NodeIsAPSInt()) { + case DiffTree::Integer: { llvm::APSInt FromInt, ToInt; + Expr *FromExpr, *ToExpr; bool IsValidFromInt, IsValidToInt; + Tree.GetNode(FromExpr, ToExpr); Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt); PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, - Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); + FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(), + Tree.NodeIsSame()); return; } - llvm_unreachable("Unable to deduce template difference."); - } - - // Node is root of template. Recurse on children. - TemplateDecl *FromTD, *ToTD; - Tree.GetNode(FromTD, ToTD); - - assert(Tree.HasChildren() && "Template difference not found in diff tree."); - - Qualifiers FromQual, ToQual; - Tree.GetNode(FromQual, ToQual); - PrintQualifiers(FromQual, ToQual); + case DiffTree::Declaration: { + ValueDecl *FromValueDecl, *ToValueDecl; + Tree.GetNode(FromValueDecl, ToValueDecl); + PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(), + Tree.ToDefault(), Tree.NodeIsSame()); + return; + } + case DiffTree::Template: { + // Node is root of template. Recurse on children. + TemplateDecl *FromTD, *ToTD; + Tree.GetNode(FromTD, ToTD); - OS << FromTD->getNameAsString() << '<'; - Tree.MoveToChild(); - unsigned NumElideArgs = 0; - do { - if (ElideType) { - if (Tree.NodeIsSame()) { - ++NumElideArgs; - continue; + if (!Tree.HasChildren()) { + // If we're dealing with a template specialization with zero + // arguments, there are no children; special-case this. + OS << FromTD->getNameAsString() << "<>"; + return; } - if (NumElideArgs > 0) { + + Qualifiers FromQual, ToQual; + Tree.GetNode(FromQual, ToQual); + PrintQualifiers(FromQual, ToQual); + + OS << FromTD->getNameAsString() << '<'; + Tree.MoveToChild(); + unsigned NumElideArgs = 0; + do { + if (ElideType) { + if (Tree.NodeIsSame()) { + ++NumElideArgs; + continue; + } + if (NumElideArgs > 0) { + PrintElideArgs(NumElideArgs, Indent); + NumElideArgs = 0; + OS << ", "; + } + } + TreeToString(Indent); + if (Tree.HasNextSibling()) + OS << ", "; + } while (Tree.AdvanceSibling()); + if (NumElideArgs > 0) PrintElideArgs(NumElideArgs, Indent); - NumElideArgs = 0; - OS << ", "; - } + + Tree.Parent(); + OS << ">"; + return; } - TreeToString(Indent); - if (Tree.HasNextSibling()) - OS << ", "; - } while (Tree.AdvanceSibling()); - if (NumElideArgs > 0) - PrintElideArgs(NumElideArgs, Indent); - - Tree.Parent(); - OS << ">"; + } } // To signal to the text printer that a certain text needs to be bolded, @@ -1260,21 +1393,29 @@ class TemplateDiff { void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD, bool FromDefault, bool ToDefault, bool Same) { assert((FromTD || ToTD) && "Only one template argument may be missing."); + + std::string FromName = FromTD ? FromTD->getName() : "(no argument)"; + std::string ToName = ToTD ? ToTD->getName() : "(no argument)"; + if (FromTD && ToTD && FromName == ToName) { + FromName = FromTD->getQualifiedNameAsString(); + ToName = ToTD->getQualifiedNameAsString(); + } + if (Same) { OS << "template " << FromTD->getNameAsString(); } else if (!PrintTree) { OS << (FromDefault ? "(default) template " : "template "); Bold(); - OS << (FromTD ? FromTD->getNameAsString() : "(no argument)"); + OS << FromName; Unbold(); } else { OS << (FromDefault ? "[(default) template " : "[template "); Bold(); - OS << (FromTD ? FromTD->getNameAsString() : "(no argument)"); + OS << FromName; Unbold(); OS << " != " << (ToDefault ? "(default) template " : "template "); Bold(); - OS << (ToTD ? ToTD->getNameAsString() : "(no argument)"); + OS << ToName; Unbold(); OS << ']'; } @@ -1283,8 +1424,8 @@ class TemplateDiff { /// PrintAPSInt - Handles printing of integral arguments, highlighting /// argument differences. void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt, - bool IsValidFromInt, bool IsValidToInt, bool FromDefault, - bool ToDefault, bool Same) { + bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr, + Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) { assert((IsValidFromInt || IsValidToInt) && "Only one integral argument may be missing."); @@ -1292,20 +1433,74 @@ class TemplateDiff { OS << FromInt.toString(10); } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); + PrintAPSInt(FromInt, FromExpr, IsValidFromInt); + } else { + OS << (FromDefault ? "[(default) " : "["); + PrintAPSInt(FromInt, FromExpr, IsValidFromInt); + OS << " != " << (ToDefault ? "(default) " : ""); + PrintAPSInt(ToInt, ToExpr, IsValidToInt); + OS << ']'; + } + } + + /// PrintAPSInt - If valid, print the APSInt. If the expression is + /// gives more information, print it too. + void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) { + Bold(); + if (Valid) { + if (HasExtraInfo(E)) { + PrintExpr(E); + Unbold(); + OS << " aka "; + Bold(); + } + OS << Val.toString(10); + } else { + OS << "(no argument)"; + } + Unbold(); + } + + /// HasExtraInfo - Returns true if E is not an integer literal or the + /// negation of an integer literal + bool HasExtraInfo(Expr *E) { + if (!E) return false; + if (isa<IntegerLiteral>(E)) return false; + + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) + if (UO->getOpcode() == UO_Minus) + if (isa<IntegerLiteral>(UO->getSubExpr())) + return false; + + return true; + } + + /// PrintDecl - Handles printing of Decl arguments, highlighting + /// argument differences. + void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, + bool FromDefault, bool ToDefault, bool Same) { + assert((FromValueDecl || ToValueDecl) && + "Only one Decl argument may be NULL"); + + if (Same) { + OS << FromValueDecl->getName(); + } else if (!PrintTree) { + OS << (FromDefault ? "(default) " : ""); Bold(); - OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); } else { OS << (FromDefault ? "[(default) " : "["); Bold(); - OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); OS << " != " << (ToDefault ? "(default) " : ""); Bold(); - OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)"); + OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)"); Unbold(); OS << ']'; } + } // Prints the appropriate placeholder for elided template arguments. @@ -1386,9 +1581,9 @@ class TemplateDiff { public: - TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType, - bool PrintTree, bool PrintFromType, bool ElideType, - bool ShowColor) + TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType, + QualType ToType, bool PrintTree, bool PrintFromType, + bool ElideType, bool ShowColor) : Context(Context), Policy(Context.getLangOpts()), ElideType(ElideType), @@ -1397,7 +1592,7 @@ public: // When printing a single type, the FromType is the one printed. FromType(PrintFromType ? FromType : ToType), ToType(PrintFromType ? ToType : FromType), - OS(Str), + OS(OS), IsBold(false) { } @@ -1424,6 +1619,7 @@ public: ToQual -= QualType(ToOrigTST, 0).getQualifiers(); Tree.SetNode(FromType, ToType); Tree.SetNode(FromQual, ToQual); + Tree.SetKind(DiffTree::Template); // Same base template, but different arguments. Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(), @@ -1432,17 +1628,16 @@ public: DiffTemplate(FromOrigTST, ToOrigTST); } - /// MakeString - When the two types given are templated types with the same + /// Emit - When the two types given are templated types with the same /// base template, a string representation of the type difference will be - /// loaded into S and return true. Otherwise, return false. - bool MakeString(std::string &S) { + /// emitted to the stream and return true. Otherwise, return false. + bool Emit() { Tree.StartTraverse(); if (Tree.Empty()) return false; TreeToString(); assert(!IsBold && "Bold is applied to end of string."); - S = OS.str(); return true; } }; // end class TemplateDiff @@ -1454,11 +1649,11 @@ public: static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType, QualType ToType, bool PrintTree, bool PrintFromType, bool ElideType, - bool ShowColors, std::string &S) { + bool ShowColors, raw_ostream &OS) { if (PrintTree) PrintFromType = true; - TemplateDiff TD(Context, FromType, ToType, PrintTree, PrintFromType, + TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType, ElideType, ShowColors); TD.DiffTemplate(); - return TD.MakeString(S); + return TD.Emit(); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp new file mode 100644 index 000000000000..b1d174b855eb --- /dev/null +++ b/lib/AST/ASTDumper.cpp @@ -0,0 +1,1996 @@ +//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// +// +// 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 AST dump methods, which dump out the +// AST in a form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; +using namespace clang::comments; + +//===----------------------------------------------------------------------===// +// ASTDumper Visitor +//===----------------------------------------------------------------------===// + +namespace { + // Colors used for various parts of the AST dump + + struct TerminalColor { + raw_ostream::Colors Color; + bool Bold; + }; + + // Decl kind names (VarDecl, FunctionDecl, etc) + static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true }; + // Attr names (CleanupAttr, GuardedByAttr, etc) + static const TerminalColor AttrColor = { raw_ostream::BLUE, true }; + // Statement names (DeclStmt, ImplicitCastExpr, etc) + static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true }; + // Comment names (FullComment, ParagraphComment, TextComment, etc) + static const TerminalColor CommentColor = { raw_ostream::YELLOW, true }; + + // Type names (int, float, etc, plus user defined types) + static const TerminalColor TypeColor = { raw_ostream::GREEN, false }; + + // Pointer address + static const TerminalColor AddressColor = { raw_ostream::YELLOW, false }; + // Source locations + static const TerminalColor LocationColor = { raw_ostream::YELLOW, false }; + + // lvalue/xvalue + static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false }; + // bitfield/objcproperty/objcsubscript/vectorcomponent + static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false }; + + // Null statements + static const TerminalColor NullColor = { raw_ostream::BLUE, false }; + + // CastKind from CastExpr's + static const TerminalColor CastColor = { raw_ostream::RED, false }; + + // Value of the statement + static const TerminalColor ValueColor = { raw_ostream::CYAN, true }; + // Decl names + static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true }; + + // Indents ( `, -. | ) + static const TerminalColor IndentColor = { raw_ostream::BLUE, false }; + + class ASTDumper + : public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>, + public ConstCommentVisitor<ASTDumper> { + raw_ostream &OS; + const CommandTraits *Traits; + const SourceManager *SM; + bool IsFirstLine; + + // Indicates whether more child are expected at the current tree depth + enum IndentType { IT_Child, IT_LastChild }; + + /// Indents[i] indicates if another child exists at level i. + /// Used by Indent() to print the tree structure. + llvm::SmallVector<IndentType, 32> Indents; + + /// Indicates that more children will be needed at this indent level. + /// If true, prevents lastChild() from marking the node as the last child. + /// This is used when there are multiple collections of children to be + /// dumped as well as during conditional node dumping. + bool MoreChildren; + + /// Keep track of the last location we print out so that we can + /// print out deltas from then on out. + const char *LastLocFilename; + unsigned LastLocLine; + + /// The \c FullComment parent of the comment being dumped. + const FullComment *FC; + + bool ShowColors; + + class IndentScope { + ASTDumper &Dumper; + // Preserve the Dumper's MoreChildren value from the previous IndentScope + bool MoreChildren; + public: + IndentScope(ASTDumper &Dumper) : Dumper(Dumper) { + MoreChildren = Dumper.hasMoreChildren(); + Dumper.setMoreChildren(false); + Dumper.indent(); + } + ~IndentScope() { + Dumper.setMoreChildren(MoreChildren); + Dumper.unindent(); + } + }; + + class ColorScope { + ASTDumper &Dumper; + public: + ColorScope(ASTDumper &Dumper, TerminalColor Color) + : Dumper(Dumper) { + if (Dumper.ShowColors) + Dumper.OS.changeColor(Color.Color, Color.Bold); + } + ~ColorScope() { + if (Dumper.ShowColors) + Dumper.OS.resetColor(); + } + }; + + public: + ASTDumper(raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) + : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), + LastLocFilename(""), LastLocLine(~0U), FC(0), + ShowColors(SM && SM->getDiagnostics().getShowColors()) { } + + ASTDumper(raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM, bool ShowColors) + : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), + LastLocFilename(""), LastLocLine(~0U), + ShowColors(ShowColors) { } + + ~ASTDumper() { + OS << "\n"; + } + + void dumpDecl(const Decl *D); + void dumpStmt(const Stmt *S); + void dumpFullComment(const FullComment *C); + + // Formatting + void indent(); + void unindent(); + void lastChild(); + bool hasMoreChildren(); + void setMoreChildren(bool Value); + + // Utilities + void dumpPointer(const void *Ptr); + void dumpSourceRange(SourceRange R); + void dumpLocation(SourceLocation Loc); + void dumpBareType(QualType T); + void dumpType(QualType T); + void dumpBareDeclRef(const Decl *Node); + void dumpDeclRef(const Decl *Node, const char *Label = 0); + void dumpName(const NamedDecl *D); + bool hasNodes(const DeclContext *DC); + void dumpDeclContext(const DeclContext *DC); + void dumpAttr(const Attr *A); + + // C++ Utilities + void dumpAccessSpecifier(AccessSpecifier AS); + void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); + void dumpTemplateParameters(const TemplateParameterList *TPL); + void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); + void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A); + void dumpTemplateArgumentList(const TemplateArgumentList &TAL); + void dumpTemplateArgument(const TemplateArgument &A, + SourceRange R = SourceRange()); + + // Decls + void VisitLabelDecl(const LabelDecl *D); + void VisitTypedefDecl(const TypedefDecl *D); + void VisitEnumDecl(const EnumDecl *D); + void VisitRecordDecl(const RecordDecl *D); + void VisitEnumConstantDecl(const EnumConstantDecl *D); + void VisitIndirectFieldDecl(const IndirectFieldDecl *D); + void VisitFunctionDecl(const FunctionDecl *D); + void VisitFieldDecl(const FieldDecl *D); + void VisitVarDecl(const VarDecl *D); + void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); + void VisitImportDecl(const ImportDecl *D); + + // C++ Decls + void VisitNamespaceDecl(const NamespaceDecl *D); + void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); + void VisitTypeAliasDecl(const TypeAliasDecl *D); + void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); + void VisitCXXRecordDecl(const CXXRecordDecl *D); + void VisitStaticAssertDecl(const StaticAssertDecl *D); + void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); + void VisitClassTemplateDecl(const ClassTemplateDecl *D); + void VisitClassTemplateSpecializationDecl( + const ClassTemplateSpecializationDecl *D); + void VisitClassTemplatePartialSpecializationDecl( + const ClassTemplatePartialSpecializationDecl *D); + void VisitClassScopeFunctionSpecializationDecl( + const ClassScopeFunctionSpecializationDecl *D); + void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); + void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); + void VisitUsingDecl(const UsingDecl *D); + void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); + void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); + void VisitUsingShadowDecl(const UsingShadowDecl *D); + void VisitLinkageSpecDecl(const LinkageSpecDecl *D); + void VisitAccessSpecDecl(const AccessSpecDecl *D); + void VisitFriendDecl(const FriendDecl *D); + + // ObjC Decls + void VisitObjCIvarDecl(const ObjCIvarDecl *D); + void VisitObjCMethodDecl(const ObjCMethodDecl *D); + void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); + void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); + void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); + void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); + void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); + void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); + void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); + void VisitBlockDecl(const BlockDecl *D); + + // Stmts. + void VisitStmt(const Stmt *Node); + void VisitDeclStmt(const DeclStmt *Node); + void VisitAttributedStmt(const AttributedStmt *Node); + void VisitLabelStmt(const LabelStmt *Node); + void VisitGotoStmt(const GotoStmt *Node); + + // Exprs + void VisitExpr(const Expr *Node); + void VisitCastExpr(const CastExpr *Node); + void VisitDeclRefExpr(const DeclRefExpr *Node); + void VisitPredefinedExpr(const PredefinedExpr *Node); + void VisitCharacterLiteral(const CharacterLiteral *Node); + void VisitIntegerLiteral(const IntegerLiteral *Node); + void VisitFloatingLiteral(const FloatingLiteral *Node); + void VisitStringLiteral(const StringLiteral *Str); + void VisitUnaryOperator(const UnaryOperator *Node); + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node); + void VisitMemberExpr(const MemberExpr *Node); + void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); + void VisitBinaryOperator(const BinaryOperator *Node); + void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); + void VisitAddrLabelExpr(const AddrLabelExpr *Node); + void VisitBlockExpr(const BlockExpr *Node); + void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); + + // C++ + void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); + void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); + void VisitCXXThisExpr(const CXXThisExpr *Node); + void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); + void VisitCXXConstructExpr(const CXXConstructExpr *Node); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); + void VisitExprWithCleanups(const ExprWithCleanups *Node); + void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); + void dumpCXXTemporary(const CXXTemporary *Temporary); + + // ObjC + void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); + void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(const ObjCMessageExpr *Node); + void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node); + void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node); + void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); + void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); + void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); + + // Comments. + const char *getCommandName(unsigned CommandID); + void dumpComment(const Comment *C); + + // Inline comments. + void visitTextComment(const TextComment *C); + void visitInlineCommandComment(const InlineCommandComment *C); + void visitHTMLStartTagComment(const HTMLStartTagComment *C); + void visitHTMLEndTagComment(const HTMLEndTagComment *C); + + // Block comments. + void visitBlockCommandComment(const BlockCommandComment *C); + void visitParamCommandComment(const ParamCommandComment *C); + void visitTParamCommandComment(const TParamCommandComment *C); + void visitVerbatimBlockComment(const VerbatimBlockComment *C); + void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); + void visitVerbatimLineComment(const VerbatimLineComment *C); + }; +} + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +// Print out the appropriate tree structure using the Indents vector. +// Example of tree and the Indents vector at each level. +// A { } +// |-B { IT_Child } +// | `-C { IT_Child, IT_LastChild } +// `-D { IT_LastChild } +// |-E { IT_LastChild, IT_Child } +// `-F { IT_LastChild, IT_LastChild } +// Type non-last element, last element +// IT_Child "| " "|-" +// IT_LastChild " " "`-" +void ASTDumper::indent() { + if (IsFirstLine) + IsFirstLine = false; + else + OS << "\n"; + + ColorScope Color(*this, IndentColor); + for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(), + E = Indents.end(); + I != E; ++I) { + switch (*I) { + case IT_Child: + if (I == E - 1) + OS << "|-"; + else + OS << "| "; + continue; + case IT_LastChild: + if (I == E - 1) + OS << "`-"; + else + OS << " "; + continue; + } + llvm_unreachable("Invalid IndentType"); + } + Indents.push_back(IT_Child); +} + +void ASTDumper::unindent() { + Indents.pop_back(); +} + +// Call before each potential last child node is to be dumped. If MoreChildren +// is false, then this is the last child, otherwise treat as a regular node. +void ASTDumper::lastChild() { + if (!hasMoreChildren()) + Indents.back() = IT_LastChild; +} + +// MoreChildren should be set before calling another function that may print +// additional nodes to prevent conflicting final child nodes. +bool ASTDumper::hasMoreChildren() { + return MoreChildren; +} + +void ASTDumper::setMoreChildren(bool Value) { + MoreChildren = Value; +} + +void ASTDumper::dumpPointer(const void *Ptr) { + ColorScope Color(*this, AddressColor); + OS << ' ' << Ptr; +} + +void ASTDumper::dumpLocation(SourceLocation Loc) { + ColorScope Color(*this, LocationColor); + SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); + + // The general format we print out is filename:line:col, but we drop pieces + // that haven't changed since the last loc printed. + PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); + + if (PLoc.isInvalid()) { + OS << "<invalid sloc>"; + return; + } + + if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + LastLocFilename = PLoc.getFilename(); + LastLocLine = PLoc.getLine(); + } else if (PLoc.getLine() != LastLocLine) { + OS << "line" << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + LastLocLine = PLoc.getLine(); + } else { + OS << "col" << ':' << PLoc.getColumn(); + } +} + +void ASTDumper::dumpSourceRange(SourceRange R) { + // Can't translate locations if a SourceManager isn't available. + if (!SM) + return; + + OS << " <"; + dumpLocation(R.getBegin()); + if (R.getBegin() != R.getEnd()) { + OS << ", "; + dumpLocation(R.getEnd()); + } + OS << ">"; + + // <t2.c:123:421[blah], t2.c:412:321> + +} + +void ASTDumper::dumpBareType(QualType T) { + ColorScope Color(*this, TypeColor); + + SplitQualType T_split = T.split(); + OS << "'" << QualType::getAsString(T_split) << "'"; + + if (!T.isNull()) { + // If the type is sugared, also dump a (shallow) desugared type. + SplitQualType D_split = T.getSplitDesugaredType(); + if (T_split != D_split) + OS << ":'" << QualType::getAsString(D_split) << "'"; + } +} + +void ASTDumper::dumpType(QualType T) { + OS << ' '; + dumpBareType(T); +} + +void ASTDumper::dumpBareDeclRef(const Decl *D) { + { + ColorScope Color(*this, DeclKindNameColor); + OS << D->getDeclKindName(); + } + dumpPointer(D); + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + ColorScope Color(*this, DeclNameColor); + OS << " '"; + ND->getDeclName().printName(OS); + OS << "'"; + } + + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) + dumpType(VD->getType()); +} + +void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) { + if (!D) + return; + + IndentScope Indent(*this); + if (Label) + OS << Label << ' '; + dumpBareDeclRef(D); +} + +void ASTDumper::dumpName(const NamedDecl *ND) { + if (ND->getDeclName()) { + ColorScope Color(*this, DeclNameColor); + OS << ' ' << ND->getNameAsString(); + } +} + +bool ASTDumper::hasNodes(const DeclContext *DC) { + if (!DC) + return false; + + return DC->decls_begin() != DC->decls_end(); +} + +void ASTDumper::dumpDeclContext(const DeclContext *DC) { + if (!DC) + return; + for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + I != E; ++I) { + DeclContext::decl_iterator Next = I; + ++Next; + if (Next == E) + lastChild(); + dumpDecl(*I); + } +} + +void ASTDumper::dumpAttr(const Attr *A) { + IndentScope Indent(*this); + { + ColorScope Color(*this, AttrColor); + switch (A->getKind()) { +#define ATTR(X) case attr::X: OS << #X; break; +#include "clang/Basic/AttrList.inc" + default: llvm_unreachable("unexpected attribute kind"); + } + OS << "Attr"; + } + dumpPointer(A); + dumpSourceRange(A->getRange()); +#include "clang/AST/AttrDump.inc" +} + +static Decl *getPreviousDeclImpl(...) { + return 0; +} + +template<typename T> +static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) { + return D->getPreviousDecl(); +} + +/// Get the previous declaration in the redeclaration chain for a declaration. +static const Decl *getPreviousDecl(const Decl *D) { + switch (D->getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: \ + return getPreviousDeclImpl(cast<DERIVED##Decl>(D)); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); +} + +//===----------------------------------------------------------------------===// +// C++ Utilities +//===----------------------------------------------------------------------===// + +void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) { + switch (AS) { + case AS_none: + break; + case AS_public: + OS << "public"; + break; + case AS_protected: + OS << "protected"; + break; + case AS_private: + OS << "private"; + break; + } +} + +void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { + IndentScope Indent(*this); + OS << "CXXCtorInitializer"; + if (Init->isAnyMemberInitializer()) { + OS << ' '; + dumpBareDeclRef(Init->getAnyMember()); + } else { + dumpType(QualType(Init->getBaseClass(), 0)); + } + dumpStmt(Init->getInit()); +} + +void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { + if (!TPL) + return; + + for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end(); + I != E; ++I) + dumpDecl(*I); +} + +void ASTDumper::dumpTemplateArgumentListInfo( + const TemplateArgumentListInfo &TALI) { + for (unsigned i = 0, e = TALI.size(); i < e; ++i) { + if (i + 1 == e) + lastChild(); + dumpTemplateArgumentLoc(TALI[i]); + } +} + +void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) { + dumpTemplateArgument(A.getArgument(), A.getSourceRange()); +} + +void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { + for (unsigned i = 0, e = TAL.size(); i < e; ++i) + dumpTemplateArgument(TAL[i]); +} + +void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { + IndentScope Indent(*this); + OS << "TemplateArgument"; + if (R.isValid()) + dumpSourceRange(R); + + switch (A.getKind()) { + case TemplateArgument::Null: + OS << " null"; + break; + case TemplateArgument::Type: + OS << " type"; + lastChild(); + dumpType(A.getAsType()); + break; + case TemplateArgument::Declaration: + OS << " decl"; + lastChild(); + dumpDeclRef(A.getAsDecl()); + break; + case TemplateArgument::NullPtr: + OS << " nullptr"; + break; + case TemplateArgument::Integral: + OS << " integral " << A.getAsIntegral(); + break; + case TemplateArgument::Template: + OS << " template "; + A.getAsTemplate().dump(OS); + break; + case TemplateArgument::TemplateExpansion: + OS << " template expansion"; + A.getAsTemplateOrTemplatePattern().dump(OS); + break; + case TemplateArgument::Expression: + OS << " expr"; + lastChild(); + dumpStmt(A.getAsExpr()); + break; + case TemplateArgument::Pack: + OS << " pack"; + for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpTemplateArgument(*I); + } + break; + } +} + +//===----------------------------------------------------------------------===// +// Decl dumping methods. +//===----------------------------------------------------------------------===// + +void ASTDumper::dumpDecl(const Decl *D) { + IndentScope Indent(*this); + + if (!D) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } + + { + ColorScope Color(*this, DeclKindNameColor); + OS << D->getDeclKindName() << "Decl"; + } + dumpPointer(D); + if (D->getLexicalDeclContext() != D->getDeclContext()) + OS << " parent " << cast<Decl>(D->getDeclContext()); + if (const Decl *Prev = getPreviousDecl(D)) + OS << " prev " << Prev; + dumpSourceRange(D->getSourceRange()); + + bool HasAttrs = D->attr_begin() != D->attr_end(); + bool HasComment = D->getASTContext().getCommentForDecl(D, 0); + // Decls within functions are visited by the body + bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) && + hasNodes(dyn_cast<DeclContext>(D)); + + setMoreChildren(HasAttrs || HasComment || HasDeclContext); + ConstDeclVisitor<ASTDumper>::Visit(D); + + setMoreChildren(HasComment || HasDeclContext); + for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpAttr(*I); + } + + setMoreChildren(HasDeclContext); + lastChild(); + dumpFullComment(D->getASTContext().getCommentForDecl(D, 0)); + + setMoreChildren(false); + if (HasDeclContext) + dumpDeclContext(cast<DeclContext>(D)); +} + +void ASTDumper::VisitLabelDecl(const LabelDecl *D) { + dumpName(D); +} + +void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { + dumpName(D); + dumpType(D->getUnderlyingType()); + if (D->isModulePrivate()) + OS << " __module_private__"; +} + +void ASTDumper::VisitEnumDecl(const EnumDecl *D) { + if (D->isScoped()) { + if (D->isScopedUsingClassTag()) + OS << " class"; + else + OS << " struct"; + } + dumpName(D); + if (D->isModulePrivate()) + OS << " __module_private__"; + if (D->isFixed()) + dumpType(D->getIntegerType()); +} + +void ASTDumper::VisitRecordDecl(const RecordDecl *D) { + OS << ' ' << D->getKindName(); + dumpName(D); + if (D->isModulePrivate()) + OS << " __module_private__"; +} + +void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (const Expr *Init = D->getInitExpr()) { + lastChild(); + dumpStmt(Init); + } +} + +void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { + dumpName(D); + dumpType(D->getType()); + for (IndirectFieldDecl::chain_iterator I = D->chain_begin(), + E = D->chain_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDeclRef(*I); + } +} + +void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { + dumpName(D); + dumpType(D->getType()); + + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); + if (D->isInlineSpecified()) + OS << " inline"; + if (D->isVirtualAsWritten()) + OS << " virtual"; + if (D->isModulePrivate()) + OS << " __module_private__"; + + if (D->isPure()) + OS << " pure"; + else if (D->isDeletedAsWritten()) + OS << " delete"; + + bool OldMoreChildren = hasMoreChildren(); + const FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo(); + bool HasTemplateSpecialization = FTSI; + + bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() != + D->getDeclsInPrototypeScope().end(); + + bool HasFunctionDecls = D->param_begin() != D->param_end(); + + const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D); + bool HasCtorInitializers = C && C->init_begin() != C->init_end(); + + bool HasDeclarationBody = D->doesThisDeclarationHaveABody(); + + setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls || + HasCtorInitializers || HasDeclarationBody); + if (HasTemplateSpecialization) { + lastChild(); + dumpTemplateArgumentList(*FTSI->TemplateArguments); + } + + setMoreChildren(OldMoreChildren || HasFunctionDecls || + HasCtorInitializers || HasDeclarationBody); + for (ArrayRef<NamedDecl *>::iterator + I = D->getDeclsInPrototypeScope().begin(), + E = D->getDeclsInPrototypeScope().end(); I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDecl(*I); + } + + setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody); + for (FunctionDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDecl(*I); + } + + setMoreChildren(OldMoreChildren || HasDeclarationBody); + if (HasCtorInitializers) + for (CXXConstructorDecl::init_const_iterator I = C->init_begin(), + E = C->init_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpCXXCtorInitializer(*I); + } + + setMoreChildren(OldMoreChildren); + if (HasDeclarationBody) { + lastChild(); + dumpStmt(D->getBody()); + } +} + +void ASTDumper::VisitFieldDecl(const FieldDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (D->isMutable()) + OS << " mutable"; + if (D->isModulePrivate()) + OS << " __module_private__"; + + bool OldMoreChildren = hasMoreChildren(); + bool IsBitField = D->isBitField(); + Expr *Init = D->getInClassInitializer(); + bool HasInit = Init; + + setMoreChildren(OldMoreChildren || HasInit); + if (IsBitField) { + lastChild(); + dumpStmt(D->getBitWidth()); + } + setMoreChildren(OldMoreChildren); + if (HasInit) { + lastChild(); + dumpStmt(Init); + } +} + +void ASTDumper::VisitVarDecl(const VarDecl *D) { + dumpName(D); + dumpType(D->getType()); + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); + if (D->isThreadSpecified()) + OS << " __thread"; + if (D->isModulePrivate()) + OS << " __module_private__"; + if (D->isNRVOVariable()) + OS << " nrvo"; + if (D->hasInit()) { + lastChild(); + dumpStmt(D->getInit()); + } +} + +void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { + lastChild(); + dumpStmt(D->getAsmString()); +} + +void ASTDumper::VisitImportDecl(const ImportDecl *D) { + OS << ' ' << D->getImportedModule()->getFullModuleName(); +} + +//===----------------------------------------------------------------------===// +// C++ Declarations +//===----------------------------------------------------------------------===// + +void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) { + dumpName(D); + if (D->isInline()) + OS << " inline"; + if (!D->isOriginalNamespace()) + dumpDeclRef(D->getOriginalNamespace(), "original"); +} + +void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { + OS << ' '; + dumpBareDeclRef(D->getNominatedNamespace()); +} + +void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { + dumpName(D); + dumpDeclRef(D->getAliasedNamespace()); +} + +void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { + dumpName(D); + dumpType(D->getUnderlyingType()); +} + +void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + dumpDecl(D->getTemplatedDecl()); +} + +void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { + VisitRecordDecl(D); + if (!D->isCompleteDefinition()) + return; + + for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(), + E = D->bases_end(); + I != E; ++I) { + IndentScope Indent(*this); + if (I->isVirtual()) + OS << "virtual "; + dumpAccessSpecifier(I->getAccessSpecifier()); + dumpType(I->getType()); + if (I->isPackExpansion()) + OS << "..."; + } +} + +void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { + dumpStmt(D->getAssertExpr()); + lastChild(); + dumpStmt(D->getMessage()); +} + +void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + dumpDecl(D->getTemplatedDecl()); + for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(), + E = D->spec_end(); + I != E; ++I) { + FunctionTemplateDecl::spec_iterator Next = I; + ++Next; + if (Next == E) + lastChild(); + switch (I->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + if (D == D->getCanonicalDecl()) + dumpDecl(*I); + else + dumpDeclRef(*I); + break; + case TSK_ExplicitSpecialization: + dumpDeclRef(*I); + break; + } + } +} + +void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + + ClassTemplateDecl::spec_iterator I = D->spec_begin(); + ClassTemplateDecl::spec_iterator E = D->spec_end(); + if (I == E) + lastChild(); + dumpDecl(D->getTemplatedDecl()); + for (; I != E; ++I) { + ClassTemplateDecl::spec_iterator Next = I; + ++Next; + if (Next == E) + lastChild(); + switch (I->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + if (D == D->getCanonicalDecl()) + dumpDecl(*I); + else + dumpDeclRef(*I); + break; + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + dumpDeclRef(*I); + break; + } + } +} + +void ASTDumper::VisitClassTemplateSpecializationDecl( + const ClassTemplateSpecializationDecl *D) { + VisitCXXRecordDecl(D); + dumpTemplateArgumentList(D->getTemplateArgs()); +} + +void ASTDumper::VisitClassTemplatePartialSpecializationDecl( + const ClassTemplatePartialSpecializationDecl *D) { + VisitClassTemplateSpecializationDecl(D); + dumpTemplateParameters(D->getTemplateParameters()); +} + +void ASTDumper::VisitClassScopeFunctionSpecializationDecl( + const ClassScopeFunctionSpecializationDecl *D) { + dumpDeclRef(D->getSpecialization()); + if (D->hasExplicitTemplateArgs()) + dumpTemplateArgumentListInfo(D->templateArgs()); +} + +void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + if (D->wasDeclaredWithTypename()) + OS << " typename"; + else + OS << " class"; + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); + if (D->hasDefaultArgument()) + dumpType(D->getDefaultArgument()); +} + +void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { + dumpType(D->getType()); + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); + if (D->hasDefaultArgument()) + dumpStmt(D->getDefaultArgument()); +} + +void ASTDumper::VisitTemplateTemplateParmDecl( + const TemplateTemplateParmDecl *D) { + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + if (D->hasDefaultArgument()) + dumpTemplateArgumentLoc(D->getDefaultArgument()); +} + +void ASTDumper::VisitUsingDecl(const UsingDecl *D) { + OS << ' '; + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); +} + +void ASTDumper::VisitUnresolvedUsingTypenameDecl( + const UnresolvedUsingTypenameDecl *D) { + OS << ' '; + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); +} + +void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { + OS << ' '; + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); + dumpType(D->getType()); +} + +void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { + OS << ' '; + dumpBareDeclRef(D->getTargetDecl()); +} + +void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { + switch (D->getLanguage()) { + case LinkageSpecDecl::lang_c: OS << " C"; break; + case LinkageSpecDecl::lang_cxx: OS << " C++"; break; + } +} + +void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { + OS << ' '; + dumpAccessSpecifier(D->getAccess()); +} + +void ASTDumper::VisitFriendDecl(const FriendDecl *D) { + lastChild(); + if (TypeSourceInfo *T = D->getFriendType()) + dumpType(T->getType()); + else + dumpDecl(D->getFriendDecl()); +} + +//===----------------------------------------------------------------------===// +// Obj-C Declarations +//===----------------------------------------------------------------------===// + +void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (D->getSynthesize()) + OS << " synthesize"; + + switch (D->getAccessControl()) { + case ObjCIvarDecl::None: + OS << " none"; + break; + case ObjCIvarDecl::Private: + OS << " private"; + break; + case ObjCIvarDecl::Protected: + OS << " protected"; + break; + case ObjCIvarDecl::Public: + OS << " public"; + break; + case ObjCIvarDecl::Package: + OS << " package"; + break; + } +} + +void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { + if (D->isInstanceMethod()) + OS << " -"; + else + OS << " +"; + dumpName(D); + dumpType(D->getResultType()); + + bool OldMoreChildren = hasMoreChildren(); + bool IsVariadic = D->isVariadic(); + bool HasBody = D->hasBody(); + + setMoreChildren(OldMoreChildren || IsVariadic || HasBody); + if (D->isThisDeclarationADefinition()) { + lastChild(); + dumpDeclContext(D); + } else { + for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDecl(*I); + } + } + + setMoreChildren(OldMoreChildren || HasBody); + if (IsVariadic) { + lastChild(); + IndentScope Indent(*this); + OS << "..."; + } + + setMoreChildren(OldMoreChildren); + if (HasBody) { + lastChild(); + dumpStmt(D->getBody()); + } +} + +void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + dumpName(D); + dumpDeclRef(D->getClassInterface()); + if (D->protocol_begin() == D->protocol_end()) + lastChild(); + dumpDeclRef(D->getImplementation()); + for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDeclRef(*I); + } +} + +void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + dumpName(D); + dumpDeclRef(D->getClassInterface()); + lastChild(); + dumpDeclRef(D->getCategoryDecl()); +} + +void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + dumpName(D); + for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDeclRef(*I); + } +} + +void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + dumpName(D); + dumpDeclRef(D->getSuperClass(), "super"); + if (D->protocol_begin() == D->protocol_end()) + lastChild(); + dumpDeclRef(D->getImplementation()); + for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDeclRef(*I); + } +} + +void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { + dumpName(D); + dumpDeclRef(D->getSuperClass(), "super"); + if (D->init_begin() == D->init_end()) + lastChild(); + dumpDeclRef(D->getClassInterface()); + for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), + E = D->init_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpCXXCtorInitializer(*I); + } +} + +void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { + dumpName(D); + lastChild(); + dumpDeclRef(D->getClassInterface()); +} + +void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + dumpName(D); + dumpType(D->getType()); + + if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) + OS << " required"; + else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) + OS << " optional"; + + ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); + if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { + if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) + OS << " readonly"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) + OS << " assign"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) + OS << " readwrite"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) + OS << " retain"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) + OS << " copy"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) + OS << " nonatomic"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) + OS << " atomic"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) + OS << " weak"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) + OS << " strong"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) + OS << " unsafe_unretained"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) { + if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter)) + lastChild(); + dumpDeclRef(D->getGetterMethodDecl(), "getter"); + } + if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) { + lastChild(); + dumpDeclRef(D->getSetterMethodDecl(), "setter"); + } + } +} + +void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + dumpName(D->getPropertyDecl()); + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) + OS << " synthesize"; + else + OS << " dynamic"; + dumpDeclRef(D->getPropertyDecl()); + lastChild(); + dumpDeclRef(D->getPropertyIvarDecl()); +} + +void ASTDumper::VisitBlockDecl(const BlockDecl *D) { + for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) + dumpDecl(*I); + + if (D->isVariadic()) { + IndentScope Indent(*this); + OS << "..."; + } + + if (D->capturesCXXThis()) { + IndentScope Indent(*this); + OS << "capture this"; + } + for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end(); + I != E; ++I) { + IndentScope Indent(*this); + OS << "capture"; + if (I->isByRef()) + OS << " byref"; + if (I->isNested()) + OS << " nested"; + if (I->getVariable()) { + OS << ' '; + dumpBareDeclRef(I->getVariable()); + } + if (I->hasCopyExpr()) + dumpStmt(I->getCopyExpr()); + } + lastChild(); + dumpStmt(D->getBody()); +} + +//===----------------------------------------------------------------------===// +// Stmt dumping methods. +//===----------------------------------------------------------------------===// + +void ASTDumper::dumpStmt(const Stmt *S) { + IndentScope Indent(*this); + + if (!S) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + VisitDeclStmt(DS); + return; + } + + setMoreChildren(S->children()); + ConstStmtVisitor<ASTDumper>::Visit(S); + setMoreChildren(false); + for (Stmt::const_child_range CI = S->children(); CI; ++CI) { + Stmt::const_child_range Next = CI; + ++Next; + if (!Next) + lastChild(); + dumpStmt(*CI); + } +} + +void ASTDumper::VisitStmt(const Stmt *Node) { + { + ColorScope Color(*this, StmtColor); + OS << Node->getStmtClassName(); + } + dumpPointer(Node); + dumpSourceRange(Node->getSourceRange()); +} + +void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { + VisitStmt(Node); + for (DeclStmt::const_decl_iterator I = Node->decl_begin(), + E = Node->decl_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpDecl(*I); + } +} + +void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { + VisitStmt(Node); + for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(), + E = Node->getAttrs().end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpAttr(*I); + } +} + +void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { + VisitStmt(Node); + OS << " '" << Node->getName() << "'"; +} + +void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { + VisitStmt(Node); + OS << " '" << Node->getLabel()->getName() << "'"; + dumpPointer(Node->getLabel()); +} + +//===----------------------------------------------------------------------===// +// Expr dumping methods. +//===----------------------------------------------------------------------===// + +void ASTDumper::VisitExpr(const Expr *Node) { + VisitStmt(Node); + dumpType(Node->getType()); + + { + ColorScope Color(*this, ValueKindColor); + switch (Node->getValueKind()) { + case VK_RValue: + break; + case VK_LValue: + OS << " lvalue"; + break; + case VK_XValue: + OS << " xvalue"; + break; + } + } + + { + ColorScope Color(*this, ObjectKindColor); + switch (Node->getObjectKind()) { + case OK_Ordinary: + break; + case OK_BitField: + OS << " bitfield"; + break; + case OK_ObjCProperty: + OS << " objcproperty"; + break; + case OK_ObjCSubscript: + OS << " objcsubscript"; + break; + case OK_VectorComponent: + OS << " vectorcomponent"; + break; + } + } +} + +static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { + if (Node->path_empty()) + return; + + OS << " ("; + bool First = true; + for (CastExpr::path_const_iterator I = Node->path_begin(), + E = Node->path_end(); + I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + if (!First) + OS << " -> "; + + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isVirtual()) + OS << "virtual "; + OS << RD->getName(); + First = false; + } + + OS << ')'; +} + +void ASTDumper::VisitCastExpr(const CastExpr *Node) { + VisitExpr(Node); + OS << " <"; + { + ColorScope Color(*this, CastColor); + OS << Node->getCastKindName(); + } + dumpBasePath(OS, Node); + OS << ">"; +} + +void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { + VisitExpr(Node); + + OS << " "; + dumpBareDeclRef(Node->getDecl()); + if (Node->getDecl() != Node->getFoundDecl()) { + OS << " ("; + dumpBareDeclRef(Node->getFoundDecl()); + OS << ")"; + } +} + +void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) { + VisitExpr(Node); + OS << " ("; + if (!Node->requiresADL()) + OS << "no "; + OS << "ADL) = '" << Node->getName() << '\''; + + UnresolvedLookupExpr::decls_iterator + I = Node->decls_begin(), E = Node->decls_end(); + if (I == E) + OS << " empty"; + for (; I != E; ++I) + dumpPointer(*I); +} + +void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { + VisitExpr(Node); + + { + ColorScope Color(*this, DeclKindNameColor); + OS << " " << Node->getDecl()->getDeclKindName() << "Decl"; + } + OS << "='" << *Node->getDecl() << "'"; + dumpPointer(Node->getDecl()); + if (Node->isFreeIvar()) + OS << " isFreeIvar"; +} + +void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { + VisitExpr(Node); + switch (Node->getIdentType()) { + default: llvm_unreachable("unknown case"); + case PredefinedExpr::Func: OS << " __func__"; break; + case PredefinedExpr::Function: OS << " __FUNCTION__"; break; + case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break; + case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; + } +} + +void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) { + VisitExpr(Node); + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValue(); +} + +void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) { + VisitExpr(Node); + + bool isSigned = Node->getType()->isSignedIntegerType(); + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValue().toString(10, isSigned); +} + +void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) { + VisitExpr(Node); + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValueAsApproximateDouble(); +} + +void ASTDumper::VisitStringLiteral(const StringLiteral *Str) { + VisitExpr(Str); + ColorScope Color(*this, ValueColor); + OS << " "; + Str->outputString(OS); +} + +void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) { + VisitExpr(Node); + OS << " " << (Node->isPostfix() ? "postfix" : "prefix") + << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; +} + +void ASTDumper::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *Node) { + VisitExpr(Node); + switch(Node->getKind()) { + case UETT_SizeOf: + OS << " sizeof"; + break; + case UETT_AlignOf: + OS << " alignof"; + break; + case UETT_VecStep: + OS << " vec_step"; + break; + } + if (Node->isArgumentType()) + dumpType(Node->getArgumentType()); +} + +void ASTDumper::VisitMemberExpr(const MemberExpr *Node) { + VisitExpr(Node); + OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl(); + dumpPointer(Node->getMemberDecl()); +} + +void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) { + VisitExpr(Node); + OS << " " << Node->getAccessor().getNameStart(); +} + +void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) { + VisitExpr(Node); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; +} + +void ASTDumper::VisitCompoundAssignOperator( + const CompoundAssignOperator *Node) { + VisitExpr(Node); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) + << "' ComputeLHSTy="; + dumpBareType(Node->getComputationLHSType()); + OS << " ComputeResultTy="; + dumpBareType(Node->getComputationResultType()); +} + +void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { + VisitExpr(Node); + dumpDecl(Node->getBlockDecl()); +} + +void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { + VisitExpr(Node); + + if (Expr *Source = Node->getSourceExpr()) { + lastChild(); + dumpStmt(Source); + } +} + +// GNU extensions. + +void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) { + VisitExpr(Node); + OS << " " << Node->getLabel()->getName(); + dumpPointer(Node->getLabel()); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions +//===----------------------------------------------------------------------===// + +void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) { + VisitExpr(Node); + OS << " " << Node->getCastName() + << "<" << Node->getTypeAsWritten().getAsString() << ">" + << " <" << Node->getCastKindName(); + dumpBasePath(OS, Node); + OS << ">"; +} + +void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { + VisitExpr(Node); + OS << " " << (Node->getValue() ? "true" : "false"); +} + +void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { + VisitExpr(Node); + OS << " this"; +} + +void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) { + VisitExpr(Node); + OS << " functional cast to " << Node->getTypeAsWritten().getAsString() + << " <" << Node->getCastKindName() << ">"; +} + +void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) { + VisitExpr(Node); + CXXConstructorDecl *Ctor = Node->getConstructor(); + dumpType(Ctor->getType()); + if (Node->isElidable()) + OS << " elidable"; + if (Node->requiresZeroInitialization()) + OS << " zeroing"; +} + +void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { + VisitExpr(Node); + OS << " "; + dumpCXXTemporary(Node->getTemporary()); +} + +void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { + VisitExpr(Node); + for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) + dumpDeclRef(Node->getObject(i), "cleanup"); +} + +void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { + OS << "(CXXTemporary"; + dumpPointer(Temporary); + OS << ")"; +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { + VisitExpr(Node); + OS << " selector=" << Node->getSelector().getAsString(); + switch (Node->getReceiverKind()) { + case ObjCMessageExpr::Instance: + break; + + case ObjCMessageExpr::Class: + OS << " class="; + dumpBareType(Node->getClassReceiver()); + break; + + case ObjCMessageExpr::SuperInstance: + OS << " super (instance)"; + break; + + case ObjCMessageExpr::SuperClass: + OS << " super (class)"; + break; + } +} + +void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) { + VisitExpr(Node); + OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString(); +} + +void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { + VisitStmt(Node); + if (const VarDecl *CatchParam = Node->getCatchParamDecl()) + dumpDecl(CatchParam); + else + OS << " catch all"; +} + +void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) { + VisitExpr(Node); + dumpType(Node->getEncodedType()); +} + +void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) { + VisitExpr(Node); + + OS << " " << Node->getSelector().getAsString(); +} + +void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) { + VisitExpr(Node); + + OS << ' ' << *Node->getProtocol(); +} + +void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) { + VisitExpr(Node); + if (Node->isImplicitProperty()) { + OS << " Kind=MethodRef Getter=\""; + if (Node->getImplicitPropertyGetter()) + OS << Node->getImplicitPropertyGetter()->getSelector().getAsString(); + else + OS << "(null)"; + + OS << "\" Setter=\""; + if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter()) + OS << Setter->getSelector().getAsString(); + else + OS << "(null)"; + OS << "\""; + } else { + OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"'; + } + + if (Node->isSuperReceiver()) + OS << " super"; + + OS << " Messaging="; + if (Node->isMessagingGetter() && Node->isMessagingSetter()) + OS << "Getter&Setter"; + else if (Node->isMessagingGetter()) + OS << "Getter"; + else if (Node->isMessagingSetter()) + OS << "Setter"; +} + +void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) { + VisitExpr(Node); + if (Node->isArraySubscriptRefExpr()) + OS << " Kind=ArraySubscript GetterForArray=\""; + else + OS << " Kind=DictionarySubscript GetterForDictionary=\""; + if (Node->getAtIndexMethodDecl()) + OS << Node->getAtIndexMethodDecl()->getSelector().getAsString(); + else + OS << "(null)"; + + if (Node->isArraySubscriptRefExpr()) + OS << "\" SetterForArray=\""; + else + OS << "\" SetterForDictionary=\""; + if (Node->setAtIndexMethodDecl()) + OS << Node->setAtIndexMethodDecl()->getSelector().getAsString(); + else + OS << "(null)"; +} + +void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { + VisitExpr(Node); + OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); +} + +//===----------------------------------------------------------------------===// +// Comments +//===----------------------------------------------------------------------===// + +const char *ASTDumper::getCommandName(unsigned CommandID) { + if (Traits) + return Traits->getCommandInfo(CommandID)->Name; + const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); + if (Info) + return Info->Name; + return "<not a builtin command>"; +} + +void ASTDumper::dumpFullComment(const FullComment *C) { + if (!C) + return; + + FC = C; + dumpComment(C); + FC = 0; +} + +void ASTDumper::dumpComment(const Comment *C) { + IndentScope Indent(*this); + + if (!C) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } + + { + ColorScope Color(*this, CommentColor); + OS << C->getCommentKindName(); + } + dumpPointer(C); + dumpSourceRange(C->getSourceRange()); + ConstCommentVisitor<ASTDumper>::visit(C); + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) { + if (I + 1 == E) + lastChild(); + dumpComment(*I); + } +} + +void ASTDumper::visitTextComment(const TextComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + +void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; + switch (C->getRenderKind()) { + case InlineCommandComment::RenderNormal: + OS << " RenderNormal"; + break; + case InlineCommandComment::RenderBold: + OS << " RenderBold"; + break; + case InlineCommandComment::RenderMonospaced: + OS << " RenderMonospaced"; + break; + case InlineCommandComment::RenderEmphasized: + OS << " RenderEmphasized"; + break; + } + + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) + OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; +} + +void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { + OS << " Name=\"" << C->getTagName() << "\""; + if (C->getNumAttrs() != 0) { + OS << " Attrs: "; + for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { + const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); + OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; + } + } + if (C->isSelfClosing()) + OS << " SelfClosing"; +} + +void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { + OS << " Name=\"" << C->getTagName() << "\""; +} + +void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) + OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; +} + +void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) { + OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); + + if (C->isDirectionExplicit()) + OS << " explicitly"; + else + OS << " implicitly"; + + if (C->hasParamName()) { + if (C->isParamIndexValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } + + if (C->isParamIndexValid()) + OS << " ParamIndex=" << C->getParamIndex(); +} + +void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) { + if (C->hasParamName()) { + if (C->isPositionValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } + + if (C->isPositionValid()) { + OS << " Position=<"; + for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { + OS << C->getIndex(i); + if (i != e - 1) + OS << ", "; + } + OS << ">"; + } +} + +void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" + " CloseName=\"" << C->getCloseName() << "\""; +} + +void ASTDumper::visitVerbatimBlockLineComment( + const VerbatimBlockLineComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + +void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { + OS << " Text=\"" << C->getText() << "\""; +} + +//===----------------------------------------------------------------------===// +// Decl method implementations +//===----------------------------------------------------------------------===// + +void Decl::dump() const { + dump(llvm::errs()); +} + +void Decl::dump(raw_ostream &OS) const { + ASTDumper P(OS, &getASTContext().getCommentCommandTraits(), + &getASTContext().getSourceManager()); + P.dumpDecl(this); +} + +void Decl::dumpColor() const { + ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(), + &getASTContext().getSourceManager(), /*ShowColors*/true); + P.dumpDecl(this); +} +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dump(SourceManager &SM) const { + dump(llvm::errs(), SM); +} + +void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { + ASTDumper P(OS, 0, &SM); + P.dumpStmt(this); +} + +void Stmt::dump() const { + ASTDumper P(llvm::errs(), 0, 0); + P.dumpStmt(this); +} + +void Stmt::dumpColor() const { + ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true); + P.dumpStmt(this); +} + +//===----------------------------------------------------------------------===// +// Comment method implementations +//===----------------------------------------------------------------------===// + +void Comment::dump() const { + dump(llvm::errs(), 0, 0); +} + +void Comment::dump(const ASTContext &Context) const { + dump(llvm::errs(), &Context.getCommentCommandTraits(), + &Context.getSourceManager()); +} + +void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) const { + const FullComment *FC = dyn_cast<FullComment>(this); + ASTDumper D(OS, Traits, SM); + D.dumpFullComment(FC); +} + +void Comment::dumpColor() const { + const FullComment *FC = dyn_cast<FullComment>(this); + ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true); + D.dumpFullComment(FC); +} diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 0d4f303af2b5..d2e6d2970531 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// #include "clang/AST/ASTImporter.h" - #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" @@ -122,6 +121,7 @@ namespace clang { bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); + bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); @@ -206,12 +206,16 @@ namespace { /// \brief Whether to complain about failures. bool Complain; + /// \brief \c true if the last diagnostic came from C2. + bool LastDiagFromC2; + StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls, bool StrictTypeSpelling = false, bool Complain = true) : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), - StrictTypeSpelling(StrictTypeSpelling), Complain(Complain) { } + StrictTypeSpelling(StrictTypeSpelling), Complain(Complain), + LastDiagFromC2(false) {} /// \brief Determine whether the two declarations are structurally /// equivalent. @@ -229,11 +233,17 @@ namespace { public: DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { assert(Complain && "Not allowed to complain"); + if (LastDiagFromC2) + C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics()); + LastDiagFromC2 = false; return C1.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { assert(Complain && "Not allowed to complain"); + if (!LastDiagFromC2) + C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics()); + LastDiagFromC2 = true; return C2.getDiagnostics().Report(Loc, DiagID); } }; @@ -892,14 +902,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, /// including the next assigned index (if none of them match). Returns an /// empty option if the context is not a record, i.e.. if the anonymous /// struct/union is at namespace or block scope. -static llvm::Optional<unsigned> -findAnonymousStructOrUnionIndex(RecordDecl *Anon) { +static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) { ASTContext &Context = Anon->getASTContext(); QualType AnonTy = Context.getRecordType(Anon); RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); if (!Owner) - return llvm::Optional<unsigned>(); + return None; unsigned Index = 0; for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), @@ -934,10 +943,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. - if (llvm::Optional<unsigned> Index1 - = findAnonymousStructOrUnionIndex(D1)) { - if (llvm::Optional<unsigned> Index2 - = findAnonymousStructOrUnionIndex(D2)) { + if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D1)) { + if (Optional<unsigned> Index2 = findAnonymousStructOrUnionIndex(D2)) { if (*Index1 != *Index2) return false; } @@ -1612,8 +1619,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>( Importer.Import(FromEPI.ExceptionSpecTemplate)); - return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), - ArgTypes.size(), ToEPI); + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI); } QualType ASTNodeImporter::VisitParenType(const ParenType *T) { @@ -1825,7 +1831,7 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) { if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) { - if (FromRecord->getDefinition() && !ToRecord->getDefinition()) { + if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) { ImportDefinition(FromRecord, ToRecord); } } @@ -1907,11 +1913,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data(); struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data(); ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor; - ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor; - ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor; - ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment; - ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment; - ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor; + ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers; ToData.Aggregate = FromData.Aggregate; ToData.PlainOldData = FromData.PlainOldData; ToData.Empty = FromData.Empty; @@ -1925,30 +1927,41 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.HasMutableFields = FromData.HasMutableFields; ToData.HasOnlyCMembers = FromData.HasOnlyCMembers; ToData.HasInClassInitializer = FromData.HasInClassInitializer; - ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor; + ToData.HasUninitializedReferenceMember + = FromData.HasUninitializedReferenceMember; + ToData.NeedOverloadResolutionForMoveConstructor + = FromData.NeedOverloadResolutionForMoveConstructor; + ToData.NeedOverloadResolutionForMoveAssignment + = FromData.NeedOverloadResolutionForMoveAssignment; + ToData.NeedOverloadResolutionForDestructor + = FromData.NeedOverloadResolutionForDestructor; + ToData.DefaultedMoveConstructorIsDeleted + = FromData.DefaultedMoveConstructorIsDeleted; + ToData.DefaultedMoveAssignmentIsDeleted + = FromData.DefaultedMoveAssignmentIsDeleted; + ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted; + ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers; + ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasConstexprNonCopyMoveConstructor = FromData.HasConstexprNonCopyMoveConstructor; ToData.DefaultedDefaultConstructorIsConstexpr = FromData.DefaultedDefaultConstructorIsConstexpr; ToData.HasConstexprDefaultConstructor = FromData.HasConstexprDefaultConstructor; - ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor; - ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor; - ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment; - ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment; - ToData.HasTrivialDestructor = FromData.HasTrivialDestructor; - ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor; ToData.HasNonLiteralTypeFieldsOrBases = FromData.HasNonLiteralTypeFieldsOrBases; // ComputedVisibleConversions not imported. ToData.UserProvidedDefaultConstructor = FromData.UserProvidedDefaultConstructor; - ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor; - ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor; - ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor; - ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment; - ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment; - ToData.DeclaredDestructor = FromData.DeclaredDestructor; + ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers; + ToData.ImplicitCopyConstructorHasConstParam + = FromData.ImplicitCopyConstructorHasConstParam; + ToData.ImplicitCopyAssignmentHasConstParam + = FromData.ImplicitCopyAssignmentHasConstParam; + ToData.HasDeclaredCopyConstructorWithConstParam + = FromData.HasDeclaredCopyConstructorWithConstParam; + ToData.HasDeclaredCopyAssignmentWithConstParam + = FromData.HasDeclaredCopyAssignmentWithConstParam; ToData.FailedImplicitMoveConstructor = FromData.FailedImplicitMoveConstructor; ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment; @@ -2143,7 +2156,18 @@ bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum); } -bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, +bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, + EnumConstantDecl *ToEC) +{ + const llvm::APSInt &FromVal = FromEC->getInitVal(); + const llvm::APSInt &ToVal = ToEC->getInitVal(); + + return FromVal.isSigned() == ToVal.isSigned() && + FromVal.getBitWidth() == ToVal.getBitWidth() && + FromVal == ToVal; +} + +bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), @@ -2185,7 +2209,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace(); } else { SmallVector<NamedDecl *, 4> ConflictingDecls; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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)) @@ -2248,7 +2272,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) @@ -2328,7 +2352,7 @@ 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) { SmallVector<NamedDecl *, 4> ConflictingDecls; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(SearchName, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) @@ -2414,7 +2438,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { RecordDecl *AdoptDecl = 0; if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(SearchName, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) @@ -2431,10 +2455,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { FoundRecord->isAnonymousStructOrUnion()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. - if (llvm::Optional<unsigned> Index1 + if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D)) { - if (llvm::Optional<unsigned> Index2 - = findAnonymousStructOrUnionIndex(FoundRecord)) { + if (Optional<unsigned> Index2 = + findAnonymousStructOrUnionIndex(FoundRecord)) { if (*Index1 != *Index2) continue; } @@ -2521,12 +2545,18 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { if (!LexicalDC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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 (EnumConstantDecl *FoundEnumConstant + = dyn_cast<EnumConstantDecl>(FoundDecls[I])) { + if (IsStructuralMatch(D, FoundEnumConstant)) + return Importer.Imported(D, FoundEnumConstant); + } + ConflictingDecls.push_back(FoundDecls[I]); } @@ -2567,7 +2597,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (!LexicalDC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) @@ -2629,8 +2659,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { FunctionProtoType::ExtProtoInfo DefaultEPI; FromTy = Importer.getFromContext().getFunctionType( FromFPT->getResultType(), - FromFPT->arg_type_begin(), - FromFPT->arg_type_end() - FromFPT->arg_type_begin(), + ArrayRef<QualType>(FromFPT->arg_type_begin(), + FromFPT->getNumArgs()), DefaultEPI); usedDifferentExceptionSpec = true; } @@ -2686,8 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { cast<CXXRecordDecl>(DC), D->getInnerLocStart(), NameInfo, T, TInfo, - Method->isStatic(), - Method->getStorageClassAsWritten(), + Method->getStorageClass(), Method->isInlineSpecified(), D->isConstexpr(), Importer.Import(D->getLocEnd())); @@ -2695,7 +2724,6 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, D->getInnerLocStart(), NameInfo, T, TInfo, D->getStorageClass(), - D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->isConstexpr()); @@ -2777,7 +2805,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { return 0; // Determine whether we've already imported this field. - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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])) { @@ -2833,7 +2861,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { return 0; // Determine whether we've already imported this field. - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField @@ -2898,7 +2926,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { return 0; // Determine whether we've already imported this ivar - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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])) { @@ -2953,7 +2981,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { VarDecl *MergeWithVar = 0; SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) @@ -3046,8 +3074,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, - D->getStorageClass(), - D->getStorageClassAsWritten()); + D->getStorageClass()); ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc())); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); @@ -3115,7 +3142,6 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), - D->getStorageClassAsWritten(), /*FIXME: Default argument*/ 0); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); @@ -3129,7 +3155,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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])) { @@ -3376,7 +3402,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { return 0; ObjCProtocolDecl *MergeWithProtocol = 0; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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)) @@ -3480,10 +3506,13 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // Import categories. When the categories themselves are imported, they'll // hook themselves into this interface. - for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat; - FromCat = FromCat->getNextClassCategory()) - Importer.Import(FromCat); - + for (ObjCInterfaceDecl::known_categories_iterator + Cat = From->known_categories_begin(), + CatEnd = From->known_categories_end(); + Cat != CatEnd; ++Cat) { + Importer.Import(*Cat); + } + // If we have an @implementation, import it as well. if (From->getImplementation()) { ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>( @@ -3523,7 +3552,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Look for an existing interface with the same name. ObjCInterfaceDecl *MergeWithIface = 0; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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)) @@ -3675,7 +3704,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return 0; // Check whether we have already imported this property. - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + SmallVector<NamedDecl *, 2> FoundDecls; DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCPropertyDecl *FoundProp @@ -3908,7 +3937,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // We may already have a template of the same name; try to find and match it. if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; - llvm::SmallVector<NamedDecl *, 2> FoundDecls; + 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)) @@ -4295,7 +4324,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, bool MinimalImport) : ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), - Minimal(MinimalImport) + Minimal(MinimalImport), LastDiagFromFrom(false) { ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); @@ -4798,10 +4827,18 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, } DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { + if (LastDiagFromFrom) + ToContext.getDiagnostics().notePriorDiagnosticFrom( + FromContext.getDiagnostics()); + LastDiagFromFrom = false; return ToContext.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { + if (!LastDiagFromFrom) + FromContext.getDiagnostics().notePriorDiagnosticFrom( + ToContext.getDiagnostics()); + LastDiagFromFrom = true; return FromContext.getDiagnostics().Report(Loc, DiagID); } diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index cffcc6501eff..daf65e56bdc6 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -13,8 +13,8 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" #include "clang/AST/Expr.h" +#include "clang/AST/Type.h" using namespace clang; Attr::~Attr() { } @@ -23,4 +23,6 @@ void InheritableAttr::anchor() { } void InheritableParamAttr::anchor() { } +void MSInheritanceAttr::anchor() { } + #include "clang/AST/AttrImpl.inc" diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index d20d77ef7ea5..e804fe720558 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -5,13 +5,13 @@ add_clang_library(clangAST ASTConsumer.cpp ASTContext.cpp ASTDiagnostic.cpp + ASTDumper.cpp ASTImporter.cpp AttrImpl.cpp CXXInheritance.cpp Comment.cpp CommentBriefParser.cpp CommentCommandTraits.cpp - CommentDumper.cpp CommentLexer.cpp CommentParser.cpp CommentSema.cpp @@ -22,6 +22,7 @@ add_clang_library(clangAST DeclFriend.cpp DeclGroup.cpp DeclObjC.cpp + DeclOpenMP.cpp DeclPrinter.cpp DeclTemplate.cpp DumpXML.cpp @@ -45,7 +46,6 @@ add_clang_library(clangAST RecordLayoutBuilder.cpp SelectorLocationsKind.cpp Stmt.cpp - StmtDumper.cpp StmtIterator.cpp StmtPrinter.cpp StmtProfile.cpp @@ -64,10 +64,13 @@ add_dependencies(clangAST ClangAttrClasses ClangAttrList ClangAttrImpl + ClangAttrDump ClangCommentCommandInfo + ClangCommentCommandList ClangCommentNodes ClangCommentHTMLTags ClangCommentHTMLTagsProperties + ClangCommentHTMLNamedCharacterReferences ClangDeclNodes ClangDiagnosticAST ClangDiagnosticComment diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 0d9c869d87ca..6d67d9a12b55 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -27,9 +27,9 @@ class CXXABI { public: virtual ~CXXABI(); - /// Returns the size of a member pointer in multiples of the target - /// pointer size. - virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; + /// Returns the width and alignment of a member pointer in bits. + virtual std::pair<uint64_t, unsigned> + getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0; /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 213b214a4e4c..0e0b35d92adf 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CXXInheritance.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecordLayout.h" #include "llvm/ADT/SetVector.h" #include <algorithm> #include <set> @@ -28,7 +28,7 @@ void CXXBasePaths::ComputeDeclsFound() { llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls; for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path) - Decls.insert(*Path->Decls.first); + Decls.insert(Path->Decls.front()); NumDeclsFound = Decls.size(); DeclsFound = new NamedDecl * [NumDeclsFound]; @@ -118,7 +118,19 @@ static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) { } bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { - return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl()); + return forallBases(BaseIsNot, + const_cast<CXXRecordDecl *>(Base->getCanonicalDecl())); +} + +bool +CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const { + assert(isDependentContext()); + + for (; !CurContext->isFileContext(); CurContext = CurContext->getParent()) + if (CurContext->Equals(this)) + return true; + + return false; } bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, @@ -140,7 +152,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, CXXRecordDecl *Base = cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition()); - if (!Base) { + if (!Base || + (Base->isDependentContext() && + !Base->isCurrentInstantiation(Record))) { if (AllowShortCircuit) return false; AllMatches = false; continue; @@ -384,9 +398,9 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); - Path.Decls.first != Path.Decls.second; - ++Path.Decls.first) { - if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag)) return true; } @@ -402,9 +416,9 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); - Path.Decls.first != Path.Decls.second; - ++Path.Decls.first) { - if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS)) + !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS)) return true; } @@ -420,11 +434,11 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); - Path.Decls.first != Path.Decls.second; - ++Path.Decls.first) { + !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { // FIXME: Refactor the "is it a nested-name-specifier?" check - if (isa<TypedefNameDecl>(*Path.Decls.first) || - (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + if (isa<TypedefNameDecl>(Path.Decls.front()) || + Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag)) return true; } @@ -725,4 +739,3 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const { AddIndirectPrimaryBases(BaseDecl, Context, Bases); } } - diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 361f8ac61c2a..db55c045449d 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -32,20 +32,6 @@ const char *Comment::getCommentKindName() const { llvm_unreachable("Unknown comment kind!"); } -void Comment::dump() const { - // It is important that Comment::dump() is defined in a different TU than - // Comment::dump(raw_ostream, SourceManager). If both functions were defined - // in CommentDumper.cpp, that object file would be removed by linker because - // none of its functions are referenced by other object files, despite the - // LLVM_ATTRIBUTE_USED. - dump(llvm::errs(), NULL, NULL); -} - -void Comment::dump(const ASTContext &Context) const { - dump(llvm::errs(), &Context.getCommentCommandTraits(), - &Context.getSourceManager()); -} - namespace { struct good {}; struct bad {}; @@ -255,32 +241,32 @@ void DeclInfo::fill() { while (true) { TL = TL.IgnoreParens(); // Look through qualified types. - if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) { - TL = QualifiedTL->getUnqualifiedLoc(); + if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) { + TL = QualifiedTL.getUnqualifiedLoc(); continue; } // Look through pointer types. - if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) { - TL = PointerTL->getPointeeLoc().getUnqualifiedLoc(); + if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) { + TL = PointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } - if (BlockPointerTypeLoc *BlockPointerTL = - dyn_cast<BlockPointerTypeLoc>(&TL)) { - TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc(); + if (BlockPointerTypeLoc BlockPointerTL = + TL.getAs<BlockPointerTypeLoc>()) { + TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } - if (MemberPointerTypeLoc *MemberPointerTL = - dyn_cast<MemberPointerTypeLoc>(&TL)) { - TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc(); + if (MemberPointerTypeLoc MemberPointerTL = + TL.getAs<MemberPointerTypeLoc>()) { + TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); continue; } // Is this a typedef for a function type? - if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) { + if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { Kind = FunctionKind; - ArrayRef<ParmVarDecl *> Params = FTL->getParams(); + ArrayRef<ParmVarDecl *> Params = FTL.getParams(); ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), Params.size()); - ResultType = FTL->getResultLoc().getType(); + ResultType = FTL.getResultLoc().getType(); break; } break; diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index 95daa7e3f809..090b9211d4c1 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -78,7 +78,7 @@ std::string BriefParser::Parse() { continue; } - if (Tok.is(tok::command)) { + if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) { const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); if (Info->IsBriefCommand) { FirstParagraphOrBrief.clear(); diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index e7e40fd1090f..e24d542c9623 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -15,9 +15,21 @@ namespace comments { #include "clang/AST/CommentCommandInfo.inc" -CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) : - NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) -{ } +CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator, + const CommentOptions &CommentOptions) : + NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) { + registerCommentOptions(CommentOptions); +} + +void CommandTraits::registerCommentOptions( + const CommentOptions &CommentOptions) { + for (CommentOptions::BlockCommandNamesTy::const_iterator + I = CommentOptions.BlockCommandNames.begin(), + E = CommentOptions.BlockCommandNames.end(); + I != E; I++) { + registerBlockCommand(*I); + } +} const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) @@ -31,7 +43,7 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { return getRegisteredCommandInfo(CommandID); } -const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) { +CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) { char *Name = Allocator.Allocate<char>(CommandName.size() + 1); memcpy(Name, CommandName.data(), CommandName.size()); Name[CommandName.size()] = '\0'; @@ -40,13 +52,25 @@ const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) CommandInfo *Info = new (Allocator) CommandInfo(); Info->Name = Name; Info->ID = NextID++; - Info->IsUnknownCommand = true; RegisteredCommands.push_back(Info); return Info; } +const CommandInfo *CommandTraits::registerUnknownCommand( + StringRef CommandName) { + CommandInfo *Info = createCommandInfoWithName(CommandName); + Info->IsUnknownCommand = true; + return Info; +} + +const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) { + CommandInfo *Info = createCommandInfoWithName(CommandName); + Info->IsBlockCommand = true; + return Info; +} + const CommandInfo *CommandTraits::getBuiltinCommandInfo( unsigned CommandID) { if (CommandID < llvm::array_lengthof(Commands)) diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp deleted file mode 100644 index 19d24b2f3a03..000000000000 --- a/lib/AST/CommentDumper.cpp +++ /dev/null @@ -1,257 +0,0 @@ -//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/CommentVisitor.h" -#include "llvm/Support/raw_ostream.h" - -namespace clang { -namespace comments { - -namespace { -class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> { - raw_ostream &OS; - const CommandTraits *Traits; - const SourceManager *SM; - - /// The \c FullComment parent of the comment being dumped. - const FullComment *FC; - - unsigned IndentLevel; - -public: - CommentDumper(raw_ostream &OS, - const CommandTraits *Traits, - const SourceManager *SM, - const FullComment *FC) : - OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0) - { } - - void dumpIndent() const { - for (unsigned i = 1, e = IndentLevel; i < e; ++i) - OS << " "; - } - - void dumpLocation(SourceLocation Loc) { - if (SM) - Loc.print(OS, *SM); - } - - void dumpSourceRange(const Comment *C); - - void dumpComment(const Comment *C); - - void dumpSubtree(const Comment *C); - - // Inline content. - void visitTextComment(const TextComment *C); - void visitInlineCommandComment(const InlineCommandComment *C); - void visitHTMLStartTagComment(const HTMLStartTagComment *C); - void visitHTMLEndTagComment(const HTMLEndTagComment *C); - - // Block content. - void visitParagraphComment(const ParagraphComment *C); - void visitBlockCommandComment(const BlockCommandComment *C); - void visitParamCommandComment(const ParamCommandComment *C); - void visitTParamCommandComment(const TParamCommandComment *C); - void visitVerbatimBlockComment(const VerbatimBlockComment *C); - void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); - void visitVerbatimLineComment(const VerbatimLineComment *C); - - void visitFullComment(const FullComment *C); - - const char *getCommandName(unsigned CommandID) { - if (Traits) - return Traits->getCommandInfo(CommandID)->Name; - const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); - if (Info) - return Info->Name; - return "<not a builtin command>"; - } -}; - -void CommentDumper::dumpSourceRange(const Comment *C) { - if (!SM) - return; - - SourceRange SR = C->getSourceRange(); - - OS << " <"; - dumpLocation(SR.getBegin()); - if (SR.getBegin() != SR.getEnd()) { - OS << ", "; - dumpLocation(SR.getEnd()); - } - OS << ">"; -} - -void CommentDumper::dumpComment(const Comment *C) { - dumpIndent(); - OS << "(" << C->getCommentKindName() - << " " << (const void *) C; - dumpSourceRange(C); -} - -void CommentDumper::dumpSubtree(const Comment *C) { - ++IndentLevel; - if (C) { - visit(C); - for (Comment::child_iterator I = C->child_begin(), - E = C->child_end(); - I != E; ++I) { - OS << '\n'; - dumpSubtree(*I); - } - OS << ')'; - } else { - dumpIndent(); - OS << "<<<NULL>>>"; - } - --IndentLevel; -} - -void CommentDumper::visitTextComment(const TextComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; - switch (C->getRenderKind()) { - case InlineCommandComment::RenderNormal: - OS << " RenderNormal"; - break; - case InlineCommandComment::RenderBold: - OS << " RenderBold"; - break; - case InlineCommandComment::RenderMonospaced: - OS << " RenderMonospaced"; - break; - case InlineCommandComment::RenderEmphasized: - OS << " RenderEmphasized"; - break; - } - - for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) - OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; -} - -void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { - dumpComment(C); - - OS << " Name=\"" << C->getTagName() << "\""; - if (C->getNumAttrs() != 0) { - OS << " Attrs: "; - for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { - const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); - OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; - } - } - if (C->isSelfClosing()) - OS << " SelfClosing"; -} - -void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { - dumpComment(C); - - OS << " Name=\"" << C->getTagName() << "\""; -} - -void CommentDumper::visitParagraphComment(const ParagraphComment *C) { - dumpComment(C); -} - -void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; - for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) - OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; -} - -void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) { - dumpComment(C); - - OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); - - if (C->isDirectionExplicit()) - OS << " explicitly"; - else - OS << " implicitly"; - - if (C->hasParamName()) { - if (C->isParamIndexValid()) - OS << " Param=\"" << C->getParamName(FC) << "\""; - else - OS << " Param=\"" << C->getParamNameAsWritten() << "\""; - } - - if (C->isParamIndexValid()) - OS << " ParamIndex=" << C->getParamIndex(); -} - -void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { - dumpComment(C); - - if (C->hasParamName()) { - if (C->isPositionValid()) - OS << " Param=\"" << C->getParamName(FC) << "\""; - else - OS << " Param=\"" << C->getParamNameAsWritten() << "\""; - } - - if (C->isPositionValid()) { - OS << " Position=<"; - for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { - OS << C->getIndex(i); - if (i != e - 1) - OS << ", "; - } - OS << ">"; - } -} - -void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { - dumpComment(C); - - OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" - " CloseName=\"" << C->getCloseName() << "\""; -} - -void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { - dumpComment(C); - - OS << " Text=\"" << C->getText() << "\""; -} - -void CommentDumper::visitFullComment(const FullComment *C) { - dumpComment(C); -} - -} // unnamed namespace - -void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM) const { - const FullComment *FC = dyn_cast<FullComment>(this); - CommentDumper D(llvm::errs(), Traits, SM, FC); - D.dumpSubtree(this); - llvm::errs() << '\n'; -} - -} // end namespace comments -} // end namespace clang - diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 31a09f71d993..1194520bf360 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -1,7 +1,9 @@ #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentCommandTraits.h" -#include "clang/Basic/ConvertUTF.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" namespace clang { @@ -13,34 +15,46 @@ void Token::dump(const Lexer &L, const SourceManager &SM) const { llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n"; } -namespace { -bool isHTMLNamedCharacterReferenceCharacter(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z'); +static inline bool isHTMLNamedCharacterReferenceCharacter(char C) { + return isLetter(C); } -bool isHTMLDecimalCharacterReferenceCharacter(char C) { - return C >= '0' && C <= '9'; +static inline bool isHTMLDecimalCharacterReferenceCharacter(char C) { + return isDigit(C); } -bool isHTMLHexCharacterReferenceCharacter(char C) { - return (C >= '0' && C <= '9') || - (C >= 'a' && C <= 'f') || - (C >= 'A' && C <= 'F'); +static inline bool isHTMLHexCharacterReferenceCharacter(char C) { + return isHexDigit(C); } +static inline StringRef convertCodePointToUTF8( + llvm::BumpPtrAllocator &Allocator, + unsigned CodePoint) { + char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); + char *ResolvedPtr = Resolved; + if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) + return StringRef(Resolved, ResolvedPtr - Resolved); + else + return StringRef(); +} + +namespace { + #include "clang/AST/CommentHTMLTags.inc" +#include "clang/AST/CommentHTMLNamedCharacterReferences.inc" } // unnamed namespace StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const { + // Fast path, first check a few most widely used named character references. return llvm::StringSwitch<StringRef>(Name) .Case("amp", "&") .Case("lt", "<") .Case("gt", ">") .Case("quot", "\"") .Case("apos", "\'") - .Default(""); + // Slow path. + .Default(translateHTMLNamedCharacterReferenceToUTF8(Name)); } StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const { @@ -50,13 +64,7 @@ StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const { CodePoint *= 10; CodePoint += Name[i] - '0'; } - - char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); - char *ResolvedPtr = Resolved; - if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) - return StringRef(Resolved, ResolvedPtr - Resolved); - else - return StringRef(); + return convertCodePointToUTF8(Allocator, CodePoint); } StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const { @@ -65,20 +73,9 @@ StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const { CodePoint *= 16; const char C = Name[i]; assert(isHTMLHexCharacterReferenceCharacter(C)); - if (C >= '0' && C <= '9') - CodePoint += Name[i] - '0'; - else if (C >= 'a' && C <= 'f') - CodePoint += Name[i] - 'a' + 10; - else - CodePoint += Name[i] - 'A' + 10; + CodePoint += llvm::hexDigitValue(C); } - - char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); - char *ResolvedPtr = Resolved; - if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) - return StringRef(Resolved, ResolvedPtr - Resolved); - else - return StringRef(); + return convertCodePointToUTF8(Allocator, CodePoint); } void Lexer::skipLineStartingDecorations() { @@ -99,7 +96,7 @@ void Lexer::skipLineStartingDecorations() { return; char C = *NewBufferPtr; - while (C == ' ' || C == '\t' || C == '\f' || C == '\v') { + while (isHorizontalWhitespace(C)) { NewBufferPtr++; if (NewBufferPtr == CommentEnd) return; @@ -119,8 +116,7 @@ namespace { /// Returns pointer to the first newline character in the string. const char *findNewline(const char *BufferPtr, const char *BufferEnd) { for ( ; BufferPtr != BufferEnd; ++BufferPtr) { - const char C = *BufferPtr; - if (C == '\n' || C == '\r') + if (isVerticalWhitespace(*BufferPtr)) return BufferPtr; } return BufferEnd; @@ -169,14 +165,11 @@ const char *skipHexCharacterReference(const char *BufferPtr, } bool isHTMLIdentifierStartingCharacter(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z'); + return isLetter(C); } bool isHTMLIdentifierCharacter(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z') || - (C >= '0' && C <= '9'); + return isAlphanumeric(C); } const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) { @@ -205,15 +198,6 @@ const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd) return BufferEnd; } -bool isHorizontalWhitespace(char C) { - return C == ' ' || C == '\t' || C == '\f' || C == '\v'; -} - -bool isWhitespace(char C) { - return C == ' ' || C == '\n' || C == '\r' || - C == '\t' || C == '\f' || C == '\v'; -} - const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) { for ( ; BufferPtr != BufferEnd; ++BufferPtr) { if (!isWhitespace(*BufferPtr)) @@ -227,14 +211,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { } bool isCommandNameStartCharacter(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z'); + return isLetter(C); } bool isCommandNameCharacter(char C) { - return (C >= 'a' && C <= 'z') || - (C >= 'A' && C <= 'Z') || - (C >= '0' && C <= '9'); + return isAlphanumeric(C); } const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { @@ -250,12 +231,10 @@ const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) { const char *CurPtr = BufferPtr; while (CurPtr != BufferEnd) { - char C = *CurPtr; - while (C != '\n' && C != '\r') { + while (!isVerticalWhitespace(*CurPtr)) { CurPtr++; if (CurPtr == BufferEnd) return BufferEnd; - C = *CurPtr; } // We found a newline, check if it is escaped. const char *EscapePtr = CurPtr - 1; @@ -319,6 +298,11 @@ void Lexer::lexCommentText(Token &T) { switch(*TokenPtr) { case '\\': case '@': { + // Commands that start with a backslash and commands that start with + // 'at' have equivalent semantics. But we keep information about the + // exact syntax in AST for comments. + tok::TokenKind CommandKind = + (*TokenPtr == '@') ? tok::at_command : tok::backslash_command; TokenPtr++; if (TokenPtr == CommentEnd) { formTextToken(T, TokenPtr); @@ -379,7 +363,7 @@ void Lexer::lexCommentText(Token &T) { setupAndLexVerbatimLine(T, TokenPtr, Info); return; } - formTokenWithChars(T, TokenPtr, tok::command); + formTokenWithChars(T, TokenPtr, CommandKind); T.setCommandID(Info->getID()); return; } @@ -415,15 +399,12 @@ void Lexer::lexCommentText(Token &T) { return; default: { - while (true) { - TokenPtr++; - if (TokenPtr == CommentEnd) - break; - const char C = *TokenPtr; - if(C == '\n' || C == '\r' || - C == '\\' || C == '@' || C == '&' || C == '<') - break; - } + size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr). + find_first_of("\n\r\\@&<"); + if (End != StringRef::npos) + TokenPtr += End; + else + TokenPtr = CommentEnd; formTextToken(T, TokenPtr); return; } @@ -446,13 +427,11 @@ void Lexer::setupAndLexVerbatimBlock(Token &T, // If there is a newline following the verbatim opening command, skip the // newline so that we don't create an tok::verbatim_block_line with empty // text content. - if (BufferPtr != CommentEnd) { - const char C = *BufferPtr; - if (C == '\n' || C == '\r') { - BufferPtr = skipNewline(BufferPtr, CommentEnd); - State = LS_VerbatimBlockBody; - return; - } + if (BufferPtr != CommentEnd && + isVerticalWhitespace(*BufferPtr)) { + BufferPtr = skipNewline(BufferPtr, CommentEnd); + State = LS_VerbatimBlockBody; + return; } State = LS_VerbatimBlockFirstLine; diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index d0a84741b6f2..09912c618864 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -8,9 +8,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentParser.h" -#include "clang/AST/CommentSema.h" -#include "clang/AST/CommentDiagnostic.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentDiagnostic.h" +#include "clang/AST/CommentSema.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/ErrorHandling.h" @@ -109,11 +110,6 @@ class TextTokenRetokenizer { return true; } - static bool isWhitespace(char C) { - return C == ' ' || C == '\n' || C == '\r' || - C == '\t' || C == '\f' || C == '\v'; - } - void consumeWhitespace() { while (!isEnd()) { if (isWhitespace(peek())) @@ -175,8 +171,7 @@ public: memcpy(TextPtr, WordText.c_str(), Length + 1); StringRef Text = StringRef(TextPtr, Length); - formTokenWithChars(Tok, Loc, WordBegin, - Pos.BufferPtr - WordBegin, Text); + formTokenWithChars(Tok, Loc, WordBegin, Length, Text); return true; } @@ -305,7 +300,7 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC, } BlockCommandComment *Parser::parseBlockCommand() { - assert(Tok.is(tok::command)); + assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command)); ParamCommandComment *PC; TParamCommandComment *TPC; @@ -313,25 +308,29 @@ BlockCommandComment *Parser::parseBlockCommand() { bool IsParam = false; bool IsTParam = false; const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + CommandMarkerKind CommandMarker = + Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At; if (Info->IsParamCommand) { IsParam = true; PC = S.actOnParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandID()); - } if (Info->IsTParamCommand) { + Tok.getCommandID(), + CommandMarker); + } else if (Info->IsTParamCommand) { IsTParam = true; TPC = S.actOnTParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandID()); + Tok.getCommandID(), + CommandMarker); } else { BC = S.actOnBlockCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandID()); + Tok.getCommandID(), + CommandMarker); } consumeToken(); - if (Tok.is(tok::command) && - Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) { + if (isTokBlockCommand()) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. ParagraphComment *Paragraph = S.actOnParagraphComment( @@ -363,10 +362,28 @@ BlockCommandComment *Parser::parseBlockCommand() { Retokenizer.putBackLeftoverTokens(); } - BlockContentComment *Block = parseParagraphOrBlockCommand(); - // Since we have checked for a block command, we should have parsed a - // paragraph. - ParagraphComment *Paragraph = cast<ParagraphComment>(Block); + // If there's a block command ahead, we will attach an empty paragraph to + // this command. + bool EmptyParagraph = false; + if (isTokBlockCommand()) + EmptyParagraph = true; + else if (Tok.is(tok::newline)) { + Token PrevTok = Tok; + consumeToken(); + EmptyParagraph = isTokBlockCommand(); + putBack(PrevTok); + } + + ParagraphComment *Paragraph; + if (EmptyParagraph) + Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>()); + else { + BlockContentComment *Block = parseParagraphOrBlockCommand(); + // Since we have checked for a block command, we should have parsed a + // paragraph. + Paragraph = cast<ParagraphComment>(Block); + } + if (IsParam) { S.actOnParamCommandFinish(PC, Paragraph); return PC; @@ -380,7 +397,7 @@ BlockCommandComment *Parser::parseBlockCommand() { } InlineCommandComment *Parser::parseInlineCommand() { - assert(Tok.is(tok::command)); + assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command)); const Token CommandTok = Tok; consumeToken(); @@ -547,7 +564,8 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { consumeToken(); continue; - case tok::command: { + case tok::backslash_command: + case tok::at_command: { const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); if (Info->IsBlockCommand) { if (Content.size() == 0) @@ -557,6 +575,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { if (Info->IsVerbatimBlockEndCommand) { Diag(Tok.getLocation(), diag::warn_verbatim_block_end_without_start) + << Tok.is(tok::at_command) << Info->Name << SourceRange(Tok.getLocation(), Tok.getEndLocation()); consumeToken(); @@ -694,7 +713,8 @@ BlockContentComment *Parser::parseBlockContent() { switch (Tok.getKind()) { case tok::text: case tok::unknown_command: - case tok::command: + case tok::backslash_command: + case tok::at_command: case tok::html_start_tag: case tok::html_end_tag: return parseParagraphOrBlockCommand(); diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index 08ecb3a994d7..e0138d5f3f27 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -8,14 +8,15 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentSema.h" -#include "clang/AST/CommentDiagnostic.h" +#include "clang/AST/Attr.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentDiagnostic.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" namespace clang { namespace comments { @@ -28,7 +29,8 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, DiagnosticsEngine &Diags, CommandTraits &Traits, const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL), + HeaderfileCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -45,10 +47,16 @@ ParagraphComment *Sema::actOnParagraphComment( return new (Allocator) ParagraphComment(Content); } -BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID) { - return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID); +BlockCommandComment *Sema::actOnBlockCommandStart( + SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) { + BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd, + CommandID, + CommandMarker); + checkContainerDecl(BC); + return BC; } void Sema::actOnBlockCommandArgs(BlockCommandComment *Command, @@ -65,20 +73,139 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command, checkDeprecatedCommand(Command); } -ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID) { +ParamCommandComment *Sema::actOnParamCommandStart( + SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) { ParamCommandComment *Command = - new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID); + new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, + CommandMarker); if (!isFunctionDecl()) Diag(Command->getLocation(), diag::warn_doc_param_not_attached_to_a_function_decl) + << CommandMarker << Command->getCommandNameRange(Traits); return Command; } +void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { + const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); + if (!Info->IsFunctionDeclarationCommand) + return; + + unsigned DiagSelect; + switch (Comment->getCommandID()) { + case CommandTraits::KCI_function: + DiagSelect = !isAnyFunctionDecl() ? 1 : 0; + break; + case CommandTraits::KCI_functiongroup: + DiagSelect = !isAnyFunctionDecl() ? 2 : 0; + break; + case CommandTraits::KCI_method: + DiagSelect = !isObjCMethodDecl() ? 3 : 0; + break; + case CommandTraits::KCI_methodgroup: + DiagSelect = !isObjCMethodDecl() ? 4 : 0; + break; + case CommandTraits::KCI_callback: + DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0; + break; + default: + DiagSelect = 0; + break; + } + if (DiagSelect) + Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch) + << Comment->getCommandMarker() + << (DiagSelect-1) << (DiagSelect-1) + << Comment->getSourceRange(); +} + +void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { + const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); + if (!Info->IsRecordLikeDeclarationCommand) + return; + unsigned DiagSelect; + switch (Comment->getCommandID()) { + case CommandTraits::KCI_class: + DiagSelect = !isClassOrStructDecl() ? 1 : 0; + break; + case CommandTraits::KCI_interface: + DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; + break; + case CommandTraits::KCI_protocol: + DiagSelect = !isObjCProtocolDecl() ? 3 : 0; + break; + case CommandTraits::KCI_struct: + DiagSelect = !isClassOrStructDecl() ? 4 : 0; + break; + case CommandTraits::KCI_union: + DiagSelect = !isUnionDecl() ? 5 : 0; + break; + default: + DiagSelect = 0; + break; + } + if (DiagSelect) + Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch) + << Comment->getCommandMarker() + << (DiagSelect-1) << (DiagSelect-1) + << Comment->getSourceRange(); +} + +void Sema::checkContainerDecl(const BlockCommandComment *Comment) { + const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); + if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl()) + return; + unsigned DiagSelect; + switch (Comment->getCommandID()) { + case CommandTraits::KCI_classdesign: + DiagSelect = 1; + break; + case CommandTraits::KCI_coclass: + DiagSelect = 2; + break; + case CommandTraits::KCI_dependency: + DiagSelect = 3; + break; + case CommandTraits::KCI_helper: + DiagSelect = 4; + break; + case CommandTraits::KCI_helperclass: + DiagSelect = 5; + break; + case CommandTraits::KCI_helps: + DiagSelect = 6; + break; + case CommandTraits::KCI_instancesize: + DiagSelect = 7; + break; + case CommandTraits::KCI_ownership: + DiagSelect = 8; + break; + case CommandTraits::KCI_performance: + DiagSelect = 9; + break; + case CommandTraits::KCI_security: + DiagSelect = 10; + break; + case CommandTraits::KCI_superclass: + DiagSelect = 11; + break; + default: + DiagSelect = 0; + break; + } + if (DiagSelect) + Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch) + << Comment->getCommandMarker() + << (DiagSelect-1) + << Comment->getSourceRange(); +} + void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, @@ -158,15 +285,19 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command, checkBlockCommandEmptyParagraph(Command); } -TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID) { +TParamCommandComment *Sema::actOnTParamCommandStart( + SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID, + CommandMarkerKind CommandMarker) { TParamCommandComment *Command = - new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID); + new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID, + CommandMarker); if (!isTemplateOrSpecialization()) Diag(Command->getLocation(), diag::warn_doc_tparam_not_attached_to_a_template_decl) + << CommandMarker << Command->getCommandNameRange(Traits); return Command; @@ -324,12 +455,15 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, unsigned CommandID, SourceLocation TextBegin, StringRef Text) { - return new (Allocator) VerbatimLineComment( + VerbatimLineComment *VL = new (Allocator) VerbatimLineComment( LocBegin, TextBegin.getLocWithOffset(Text.size()), CommandID, TextBegin, Text); + checkFunctionDeclVerbatimLine(VL); + checkContainerDeclVerbatimLine(VL); + return VL; } HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin, @@ -430,6 +564,7 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { if (!DiagLoc.isValid()) DiagLoc = Command->getCommandNameRange(Traits).getEnd(); Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) + << Command->getCommandMarker() << Command->getCommandName(Traits) << Command->getSourceRange(); } @@ -457,14 +592,19 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { } Diag(Command->getLocation(), diag::warn_doc_returns_attached_to_a_void_function) + << Command->getCommandMarker() << Command->getCommandName(Traits) << DiagKind << Command->getSourceRange(); } return; } + else if (isObjCPropertyDecl()) + return; + Diag(Command->getLocation(), diag::warn_doc_returns_not_attached_to_a_function_decl) + << Command->getCommandMarker() << Command->getCommandName(Traits) << Command->getSourceRange(); } @@ -484,6 +624,12 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { return; } PrevCommand = ReturnsCommand; + } else if (Info->IsHeaderfileCommand) { + if (!HeaderfileCommand) { + HeaderfileCommand = Command; + return; + } + PrevCommand = HeaderfileCommand; } else { // We don't want to check this command for duplicates. return; @@ -491,15 +637,18 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { StringRef CommandName = Command->getCommandName(Traits); StringRef PrevCommandName = PrevCommand->getCommandName(Traits); Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) + << Command->getCommandMarker() << CommandName << Command->getSourceRange(); if (CommandName == PrevCommandName) Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) + << PrevCommand->getCommandMarker() << PrevCommandName << PrevCommand->getSourceRange(); else Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous_alias) + << PrevCommand->getCommandMarker() << PrevCommandName << CommandName; } @@ -559,11 +708,11 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { return; } - llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; + SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; // Comment AST nodes that correspond to \c ParamVars for which we have // found a \\param command or NULL if no documentation was found so far. - llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs; + SmallVector<ParamCommandComment *, 8> ParamVarDocs; ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); ParamVarDocs.resize(ParamVars.size(), NULL); @@ -596,7 +745,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { } // Find parameter declarations that have no corresponding \\param. - llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; + SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { if (!ParamVarDocs[i]) OrphanedParamDecls.push_back(ParamVars[i]); @@ -645,6 +794,40 @@ bool Sema::isFunctionDecl() { return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; } +bool Sema::isAnyFunctionDecl() { + return isFunctionDecl() && ThisDeclInfo->CurrentDecl && + isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); +} + +bool Sema::isObjCMethodDecl() { + return isFunctionDecl() && ThisDeclInfo->CurrentDecl && + isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); +} + +/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to +/// function decl. +bool Sema::isFunctionPointerVarDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { + if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) { + QualType QT = VD->getType(); + return QT->isFunctionPointerType(); + } + } + return false; +} + +bool Sema::isObjCPropertyDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; +} + bool Sema::isTemplateOrSpecialization() { if (!ThisDeclInfo) return false; @@ -653,6 +836,54 @@ bool Sema::isTemplateOrSpecialization() { return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; } +bool Sema::isRecordLikeDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return isUnionDecl() || isClassOrStructDecl() + || isObjCInterfaceDecl() || isObjCProtocolDecl(); +} + +bool Sema::isUnionDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + if (const RecordDecl *RD = + dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl)) + return RD->isUnion(); + return false; +} + +bool Sema::isClassOrStructDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && + !isUnionDecl(); +} + +bool Sema::isObjCInterfaceDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl); +} + +bool Sema::isObjCProtocolDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl); +} + ArrayRef<const ParmVarDecl *> Sema::getParamVars() { if (!ThisDeclInfo->IsFilled) inspectThisDecl(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7b13755979f1..bf807aeb1d69 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -12,23 +12,24 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/TypeLoc.h" -#include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" -#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/ErrorHandling.h" - +#include "llvm/Support/type_traits.h" #include <algorithm> using namespace clang; @@ -37,17 +38,163 @@ using namespace clang; // NamedDecl Implementation //===----------------------------------------------------------------------===// -static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) { +// Visibility rules aren't rigorously externally specified, but here +// are the basic principles behind what we implement: +// +// 1. An explicit visibility attribute is generally a direct expression +// of the user's intent and should be honored. Only the innermost +// visibility attribute applies. If no visibility attribute applies, +// global visibility settings are considered. +// +// 2. There is one caveat to the above: on or in a template pattern, +// an explicit visibility attribute is just a default rule, and +// visibility can be decreased by the visibility of template +// arguments. But this, too, has an exception: an attribute on an +// explicit specialization or instantiation causes all the visibility +// restrictions of the template arguments to be ignored. +// +// 3. A variable that does not otherwise have explicit visibility can +// be restricted by the visibility of its type. +// +// 4. A visibility restriction is explicit if it comes from an +// attribute (or something like it), not a global visibility setting. +// When emitting a reference to an external symbol, visibility +// restrictions are ignored unless they are explicit. +// +// 5. When computing the visibility of a non-type, including a +// non-type member of a class, only non-type visibility restrictions +// are considered: the 'visibility' attribute, global value-visibility +// settings, and a few special cases like __private_extern. +// +// 6. When computing the visibility of a type, including a type member +// of a class, only type visibility restrictions are considered: +// the 'type_visibility' attribute and global type-visibility settings. +// However, a 'visibility' attribute counts as a 'type_visibility' +// attribute on any declaration that only has the former. +// +// The visibility of a "secondary" entity, like a template argument, +// is computed using the kind of that entity, not the kind of the +// primary entity for which we are computing visibility. For example, +// the visibility of a specialization of either of these templates: +// template <class T, bool (&compare)(T, X)> bool has_match(list<T>, X); +// template <class T, bool (&compare)(T, X)> class matcher; +// is restricted according to the type visibility of the argument 'T', +// the type visibility of 'bool(&)(T,X)', and the value visibility of +// the argument function 'compare'. That 'has_match' is a value +// and 'matcher' is a type only matters when looking for attributes +// and settings from the immediate context. + +const unsigned IgnoreExplicitVisibilityBit = 2; + +/// Kinds of LV computation. The linkage side of the computation is +/// always the same, but different things can change how visibility is +/// computed. +enum LVComputationKind { + /// Do an LV computation for, ultimately, a type. + /// Visibility may be restricted by type visibility settings and + /// the visibility of template arguments. + LVForType = NamedDecl::VisibilityForType, + + /// Do an LV computation for, ultimately, a non-type declaration. + /// Visibility may be restricted by value visibility settings and + /// the visibility of template arguments. + LVForValue = NamedDecl::VisibilityForValue, + + /// Do an LV computation for, ultimately, a type that already has + /// some sort of explicit visibility. Visibility may only be + /// restricted by the visibility of template arguments. + LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit), + + /// Do an LV computation for, ultimately, a non-type declaration + /// that already has some sort of explicit visibility. Visibility + /// may only be restricted by the visibility of template arguments. + LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit) +}; + +/// Does this computation kind permit us to consider additional +/// visibility settings from attributes and the like? +static bool hasExplicitVisibilityAlready(LVComputationKind computation) { + return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0); +} + +/// Given an LVComputationKind, return one of the same type/value sort +/// that records that it already has explicit visibility. +static LVComputationKind +withExplicitVisibilityAlready(LVComputationKind oldKind) { + LVComputationKind newKind = + static_cast<LVComputationKind>(unsigned(oldKind) | + IgnoreExplicitVisibilityBit); + assert(oldKind != LVForType || newKind == LVForExplicitType); + assert(oldKind != LVForValue || newKind == LVForExplicitValue); + assert(oldKind != LVForExplicitType || newKind == LVForExplicitType); + assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue); + return newKind; +} + +static Optional<Visibility> getExplicitVisibility(const NamedDecl *D, + LVComputationKind kind) { + assert(!hasExplicitVisibilityAlready(kind) && + "asking for explicit visibility when we shouldn't be"); + return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind); +} + +/// Is the given declaration a "type" or a "value" for the purposes of +/// visibility computation? +static bool usesTypeVisibility(const NamedDecl *D) { + return isa<TypeDecl>(D) || + isa<ClassTemplateDecl>(D) || + isa<ObjCInterfaceDecl>(D); +} + +/// Does the given declaration have member specialization information, +/// and if so, is it an explicit specialization? +template <class T> static typename +llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value, + bool>::type +isExplicitMemberSpecialization(const T *D) { + if (const MemberSpecializationInfo *member = + D->getMemberSpecializationInfo()) { + return member->isExplicitSpecialization(); + } + return false; +} + +/// For templates, this question is easier: a member template can't be +/// explicitly instantiated, so there's a single bit indicating whether +/// or not this is an explicit member specialization. +static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) { + return D->isMemberSpecialization(); +} + +/// Given a visibility attribute, return the explicit visibility +/// associated with it. +template <class T> +static Visibility getVisibilityFromAttr(const T *attr) { + switch (attr->getVisibility()) { + case T::Default: + return DefaultVisibility; + case T::Hidden: + return HiddenVisibility; + case T::Protected: + return ProtectedVisibility; + } + llvm_unreachable("bad visibility kind"); +} + +/// Return the explicit visibility of the given declaration. +static Optional<Visibility> getVisibilityOf(const NamedDecl *D, + NamedDecl::ExplicitVisibilityKind kind) { + // If we're ultimately computing the visibility of a type, look for + // a 'type_visibility' attribute before looking for 'visibility'. + if (kind == NamedDecl::VisibilityForType) { + if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) { + return getVisibilityFromAttr(A); + } + } + // If this declaration has an explicit visibility attribute, use it. if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) { - switch (A->getVisibility()) { - case VisibilityAttr::Default: - return DefaultVisibility; - case VisibilityAttr::Hidden: - return HiddenVisibility; - case VisibilityAttr::Protected: - return ProtectedVisibility; - } + return getVisibilityFromAttr(A); } // If we're on Mac OS X, an 'availability' for Mac OS X attribute @@ -61,43 +208,61 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) { return DefaultVisibility; } - return llvm::Optional<Visibility>(); -} - -typedef NamedDecl::LinkageInfo LinkageInfo; - -static LinkageInfo getLVForType(QualType T) { - std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility(); - return LinkageInfo(P.first, P.second, T->isVisibilityExplicit()); + return None; } /// \brief Get the most restrictive linkage for the types in the given -/// template parameter list. +/// template parameter list. For visibility purposes, template +/// parameters are part of the signature of a template. static LinkageInfo -getLVForTemplateParameterList(const TemplateParameterList *Params) { - LinkageInfo LV(ExternalLinkage, DefaultVisibility, false); - for (TemplateParameterList::const_iterator P = Params->begin(), - PEnd = Params->end(); +getLVForTemplateParameterList(const TemplateParameterList *params) { + LinkageInfo LV; + for (TemplateParameterList::const_iterator P = params->begin(), + PEnd = params->end(); P != PEnd; ++P) { + + // Template type parameters are the most common and never + // contribute to visibility, pack or not. + if (isa<TemplateTypeParmDecl>(*P)) + continue; + + // Non-type template parameters can be restricted by the value type, e.g. + // template <enum X> class A { ... }; + // We have to be careful here, though, because we can be dealing with + // dependent types. if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { - if (NTTP->isExpandedParameterPack()) { - for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { - QualType T = NTTP->getExpansionType(I); - if (!T->isDependentType()) - LV.merge(getLVForType(T)); + // Handle the non-pack case first. + if (!NTTP->isExpandedParameterPack()) { + if (!NTTP->getType()->isDependentType()) { + LV.merge(NTTP->getType()->getLinkageAndVisibility()); } continue; } - if (!NTTP->getType()->isDependentType()) { - LV.merge(getLVForType(NTTP->getType())); - continue; + // Look at all the types in an expanded pack. + for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) { + QualType type = NTTP->getExpansionType(i); + if (!type->isDependentType()) + LV.merge(type->getLinkageAndVisibility()); } + continue; } - if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(*P)) { + // Template template parameters can be restricted by their + // template parameters, recursively. + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + + // Handle the non-pack case first. + if (!TTP->isExpandedParameterPack()) { LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters())); + continue; + } + + // Look at all expansions in an expanded pack. + for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); + i != n; ++i) { + LV.merge(getLVForTemplateParameterList( + TTP->getExpansionTemplateParameters(i))); } } @@ -105,67 +270,177 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) { } /// getLVForDecl - Get the linkage and visibility for the given declaration. -static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate); +static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation); /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. -static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args, - unsigned NumArgs, - bool OnlyTemplate) { - LinkageInfo LV(ExternalLinkage, DefaultVisibility, false); +/// +/// Note that we don't take an LVComputationKind because we always +/// want to honor the visibility of template arguments in the same way. +static LinkageInfo +getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { + LinkageInfo LV; - for (unsigned I = 0; I != NumArgs; ++I) { - switch (Args[I].getKind()) { + for (unsigned i = 0, e = args.size(); i != e; ++i) { + const TemplateArgument &arg = args[i]; + switch (arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Expression: - break; + continue; case TemplateArgument::Type: - LV.mergeWithMin(getLVForType(Args[I].getAsType())); - break; + LV.merge(arg.getAsType()->getLinkageAndVisibility()); + continue; case TemplateArgument::Declaration: - if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl())) - LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate)); - break; + if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) { + assert(!usesTypeVisibility(ND)); + LV.merge(getLVForDecl(ND, LVForValue)); + } + continue; case TemplateArgument::NullPtr: - LV.mergeWithMin(getLVForType(Args[I].getNullPtrType())); - break; + LV.merge(arg.getNullPtrType()->getLinkageAndVisibility()); + continue; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: if (TemplateDecl *Template - = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl()) - LV.mergeWithMin(getLVForDecl(Template, OnlyTemplate)); - break; + = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) + LV.merge(getLVForDecl(Template, LVForValue)); + continue; case TemplateArgument::Pack: - LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(), - Args[I].pack_size(), - OnlyTemplate)); - break; + LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray())); + continue; } + llvm_unreachable("bad template argument kind"); } return LV; } static LinkageInfo -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, - bool OnlyTemplate) { - return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), OnlyTemplate); +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) { + return getLVForTemplateArgumentList(TArgs.asArray()); } -static bool shouldConsiderTemplateVis(const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *spec) { - return !fn->hasAttr<VisibilityAttr>() || spec->isExplicitSpecialization(); +static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo) { + // Include visibility from the template parameters and arguments + // only if this is not an explicit instantiation or specialization + // with direct explicit visibility. (Implicit instantiations won't + // have a direct attribute.) + if (!specInfo->isExplicitInstantiationOrSpecialization()) + return true; + + return !fn->hasAttr<VisibilityAttr>(); +} + +/// Merge in template-related linkage and visibility for the given +/// function template specialization. +/// +/// We don't need a computation kind here because we can assume +/// LVForValue. +/// +/// \param[out] LV the computation to use for the parent +static void +mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *specInfo) { + bool considerVisibility = + shouldConsiderTemplateVisibility(fn, specInfo); + + // Merge information from the template parameters. + FunctionTemplateDecl *temp = specInfo->getTemplate(); + LinkageInfo tempLV = + getLVForTemplateParameterList(temp->getTemplateParameters()); + LV.mergeMaybeWithVisibility(tempLV, considerVisibility); + + // Merge information from the template arguments. + const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs); + LV.mergeMaybeWithVisibility(argsLV, considerVisibility); +} + +/// Does the given declaration have a direct visibility attribute +/// that would match the given rules? +static bool hasDirectVisibilityAttribute(const NamedDecl *D, + LVComputationKind computation) { + switch (computation) { + case LVForType: + case LVForExplicitType: + if (D->hasAttr<TypeVisibilityAttr>()) + return true; + // fallthrough + case LVForValue: + case LVForExplicitValue: + if (D->hasAttr<VisibilityAttr>()) + return true; + return false; + } + llvm_unreachable("bad visibility computation kind"); +} + +/// Should we consider visibility associated with the template +/// arguments and parameters of the given class template specialization? +static bool shouldConsiderTemplateVisibility( + const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation) { + // Include visibility from the template parameters and arguments + // only if this is not an explicit instantiation or specialization + // with direct explicit visibility (and note that implicit + // instantiations won't have a direct attribute). + // + // Furthermore, we want to ignore template parameters and arguments + // for an explicit specialization when computing the visibility of a + // member thereof with explicit visibility. + // + // This is a bit complex; let's unpack it. + // + // An explicit class specialization is an independent, top-level + // declaration. As such, if it or any of its members has an + // explicit visibility attribute, that must directly express the + // user's intent, and we should honor it. The same logic applies to + // an explicit instantiation of a member of such a thing. + + // Fast path: if this is not an explicit instantiation or + // specialization, we always want to consider template-related + // visibility restrictions. + if (!spec->isExplicitInstantiationOrSpecialization()) + return true; + + // This is the 'member thereof' check. + if (spec->isExplicitSpecialization() && + hasExplicitVisibilityAlready(computation)) + return false; + + return !hasDirectVisibilityAttribute(spec, computation); } -static bool -shouldConsiderTemplateVis(const ClassTemplateSpecializationDecl *d) { - return !d->hasAttr<VisibilityAttr>() || d->isExplicitSpecialization(); +/// Merge in template-related linkage and visibility for the given +/// class template specialization. +static void mergeTemplateLV(LinkageInfo &LV, + const ClassTemplateSpecializationDecl *spec, + LVComputationKind computation) { + bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); + + // Merge information from the template parameters, but ignore + // visibility if we're only considering template arguments. + + ClassTemplateDecl *temp = spec->getSpecializedTemplate(); + LinkageInfo tempLV = + getLVForTemplateParameterList(temp->getTemplateParameters()); + LV.mergeMaybeWithVisibility(tempLV, + considerVisibility && !hasExplicitVisibilityAlready(computation)); + + // Merge information from the template arguments. We ignore + // template-argument visibility if we've got an explicit + // instantiation with a visibility attribute. + const TemplateArgumentList &templateArgs = spec->getTemplateArgs(); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs); + LV.mergeMaybeWithVisibility(argsLV, considerVisibility); } static bool useInlineVisibilityHidden(const NamedDecl *D) { @@ -196,8 +471,13 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } +template <typename T> static bool isInExternCContext(T *D) { + const T *First = D->getFirstDeclaration(); + return First->getDeclContext()->isExternCContext(); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, - bool OnlyTemplate) { + LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -218,26 +498,24 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // declared to have external linkage; or (there is no equivalent in C99) if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && - !Var->getType().isVolatileQualified() && - Var->getStorageClass() != SC_Extern && - Var->getStorageClass() != SC_PrivateExtern) { - bool FoundExtern = false; - for (const VarDecl *PrevVar = Var->getPreviousDecl(); - PrevVar && !FoundExtern; - PrevVar = PrevVar->getPreviousDecl()) - if (isExternalLinkage(PrevVar->getLinkage())) - FoundExtern = true; - - if (!FoundExtern) - return LinkageInfo::internal(); - } - if (Var->getStorageClass() == SC_None) { + !Var->getType().isVolatileQualified()) { const VarDecl *PrevVar = Var->getPreviousDecl(); - for (; PrevVar; PrevVar = PrevVar->getPreviousDecl()) - if (PrevVar->getStorageClass() == SC_PrivateExtern) - break; if (PrevVar) return PrevVar->getLinkageAndVisibility(); + + if (Var->getStorageClass() != SC_Extern && + Var->getStorageClass() != SC_PrivateExtern) + return LinkageInfo::internal(); + } + + for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; + PrevVar = PrevVar->getPreviousDecl()) { + if (PrevVar->getStorageClass() == SC_PrivateExtern && + Var->getStorageClass() == SC_None) + return PrevVar->getLinkageAndVisibility(); + // Explicitly declared static. + if (PrevVar->getStorageClass() == SC_Static) + return LinkageInfo::internal(); } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { // C++ [temp]p4: @@ -251,7 +529,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, Function = cast<FunctionDecl>(D); // Explicitly declared static. - if (Function->getStorageClass() == SC_Static) + if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo(InternalLinkage, DefaultVisibility, false); } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // - a data member of an anonymous union. @@ -262,8 +540,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast<VarDecl>(D); const FunctionDecl *Func = dyn_cast<FunctionDecl>(D); - if ((!Var || !Var->getDeclContext()->isExternCContext()) && - (!Func || !Func->getDeclContext()->isExternCContext())) + if ((!Var || !isInExternCContext(Var)) && + (!Func || !isInExternCContext(Func))) return LinkageInfo::uniqueExternal(); } @@ -275,31 +553,41 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // external. LinkageInfo LV; - if (!OnlyTemplate) { - if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) { + if (!hasExplicitVisibilityAlready(computation)) { + if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) { LV.mergeVisibility(*Vis, true); } else { // If we're declared in a namespace with a visibility attribute, - // use that namespace's visibility, but don't call it explicit. + // use that namespace's visibility, and it still counts as explicit. for (const DeclContext *DC = D->getDeclContext(); !isa<TranslationUnitDecl>(DC); DC = DC->getParent()) { const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); if (!ND) continue; - if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) { + if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) { LV.mergeVisibility(*Vis, true); break; } } } - } - if (!OnlyTemplate) { - LV.mergeVisibility(Context.getLangOpts().getVisibilityMode()); - // If we're paying attention to global visibility, apply - // -finline-visibility-hidden if this is an inline method. - if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D)) - LV.mergeVisibility(HiddenVisibility, true); + // Add in global settings if the above didn't give us direct visibility. + if (!LV.isVisibilityExplicit()) { + // Use global type/value visibility as appropriate. + Visibility globalVisibility; + if (computation == LVForValue) { + globalVisibility = Context.getLangOpts().getValueVisibilityMode(); + } else { + assert(computation == LVForType); + globalVisibility = Context.getLangOpts().getTypeVisibilityMode(); + } + LV.mergeVisibility(globalVisibility, /*explicit*/ false); + + // If we're paying attention to global visibility, apply + // -finline-visibility-hidden if this is an inline method. + if (useInlineVisibilityHidden(D)) + LV.mergeVisibility(HiddenVisibility, true); + } } // C++ [basic.link]p4: @@ -330,12 +618,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOpts().CPlusPlus && - !Var->getDeclContext()->isExternCContext()) { - LinkageInfo TypeLV = getLVForType(Var->getType()); - if (TypeLV.linkage() != ExternalLinkage) + if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) { + LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility(); + if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); - LV.mergeVisibility(TypeLV); + if (!LV.isVisibilityExplicit()) + LV.mergeVisibility(TypeLV); } if (Var->getStorageClass() == SC_PrivateExtern) @@ -355,30 +643,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Function->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); - // C99 6.2.2p5: - // If the declaration of an identifier for a function has no - // storage-class specifier, its linkage is determined exactly - // as if it were declared with the storage-class specifier - // extern. - if (!Context.getLangOpts().CPlusPlus && - (Function->getStorageClass() == SC_Extern || - Function->getStorageClass() == SC_PrivateExtern || - Function->getStorageClass() == SC_None)) { - // C99 6.2.2p4: - // For an identifier declared with the storage-class specifier - // extern in a scope in which a prior declaration of that - // identifier is visible, if the prior declaration specifies - // internal or external linkage, the linkage of the identifier - // at the later declaration is the same as the linkage - // specified at the prior declaration. If no prior declaration - // is visible, or if the prior declaration specifies no - // linkage, then the identifier has external linkage. - if (const FunctionDecl *PrevFunc = Function->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(PrevFunc, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } - } + // Note that Sema::MergeCompatibleFunctionDecls already takes care of + // merging storage classes and visibility attributes, so we don't have to + // look at previous decls in here. // In C++, then if the type of the function uses a type with // unique-external linkage, it's not legally usable from outside @@ -389,21 +656,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); - // Consider LV from the template and the template arguments unless - // this is an explicit specialization with a visibility attribute. + // Consider LV from the template and the template arguments. + // We're at file scope, so we do not need to worry about nested + // specializations. if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { - LinkageInfo TempLV = getLVForDecl(specInfo->getTemplate(), true); - const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; - LinkageInfo ArgsLV = getLVForTemplateArgumentList(templateArgs, - OnlyTemplate); - if (shouldConsiderTemplateVis(Function, specInfo)) { - LV.mergeWithMin(TempLV); - LV.mergeWithMin(ArgsLV); - } else { - LV.mergeLinkage(TempLV); - LV.mergeLinkage(ArgsLV); - } + mergeTemplateLV(LV, Function, specInfo); } // - a named class (Clause 9), or an unnamed class defined in a @@ -414,41 +672,33 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // has the typedef name for linkage purposes (7.1.3); or } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) { // Unnamed tags have no linkage. - if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) + if (!Tag->hasNameForLinkage()) return LinkageInfo::none(); // If this is a class template specialization, consider the - // linkage of the template and template arguments. + // linkage of the template and template arguments. We're at file + // scope, so we do not need to worry about nested specializations. if (const ClassTemplateSpecializationDecl *spec = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { - // From the template. - LinkageInfo TempLV = getLVForDecl(spec->getSpecializedTemplate(), true); - - // The arguments at which the template was instantiated. - const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); - LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs, - OnlyTemplate); - if (shouldConsiderTemplateVis(spec)) { - LV.mergeWithMin(TempLV); - LV.mergeWithMin(ArgsLV); - } else { - LV.mergeLinkage(TempLV); - LV.mergeLinkage(ArgsLV); - } + mergeTemplateLV(LV, spec, computation); } // - an enumerator belonging to an enumeration with external linkage; } else if (isa<EnumConstantDecl>(D)) { LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), - OnlyTemplate); - if (!isExternalLinkage(EnumLV.linkage())) + computation); + if (!isExternalLinkage(EnumLV.getLinkage())) return LinkageInfo::none(); LV.merge(EnumLV); // - a template, unless it is a function template that has // internal linkage (Clause 14); } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { - LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters())); + bool considerVisibility = !hasExplicitVisibilityAlready(computation); + LinkageInfo tempLV = + getLVForTemplateParameterList(temp->getTemplateParameters()); + LV.mergeMaybeWithVisibility(tempLV, considerVisibility); + // - a namespace (7.3), unless it is declared within an unnamed // namespace. } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) { @@ -466,13 +716,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // If we ended up with non-external linkage, visibility should // always be default. - if (LV.linkage() != ExternalLinkage) - return LinkageInfo(LV.linkage(), DefaultVisibility, false); + if (LV.getLinkage() != ExternalLinkage) + return LinkageInfo(LV.getLinkage(), DefaultVisibility, false); return LV; } -static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) { +static LinkageInfo getLVForClassMember(const NamedDecl *D, + LVComputationKind computation) { // Only certain class members have linkage. Note that fields don't // really have linkage, but it's convenient to say they do for the // purposes of calculating linkage of pointer-to-data-member @@ -480,46 +731,45 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) { if (!(isa<CXXMethodDecl>(D) || isa<VarDecl>(D) || isa<FieldDecl>(D) || - (isa<TagDecl>(D) && - (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl())))) + isa<TagDecl>(D))) return LinkageInfo::none(); LinkageInfo LV; // If we have an explicit visibility attribute, merge that in. - if (!OnlyTemplate) { - if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) + if (!hasExplicitVisibilityAlready(computation)) { + if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) LV.mergeVisibility(*Vis, true); // If we're paying attention to global visibility, apply // -finline-visibility-hidden if this is an inline method. // // Note that we do this before merging information about // the class visibility. - if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D)) + if (!LV.isVisibilityExplicit() && useInlineVisibilityHidden(D)) LV.mergeVisibility(HiddenVisibility, true); } // If this class member has an explicit visibility attribute, the only // thing that can change its visibility is the template arguments, so // only look for them when processing the class. - bool ClassOnlyTemplate = LV.visibilityExplicit() ? true : OnlyTemplate; - - // If this member has an visibility attribute, ClassF will exclude - // attributes on the class or command line options, keeping only information - // about the template instantiation. If the member has no visibility - // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin - // produces the desired result. - LV.mergeWithMin(getLVForDecl(cast<RecordDecl>(D->getDeclContext()), - ClassOnlyTemplate)); - if (!isExternalLinkage(LV.linkage())) + LVComputationKind classComputation = computation; + if (LV.isVisibilityExplicit()) + classComputation = withExplicitVisibilityAlready(computation); + + LinkageInfo classLV = + getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation); + if (!isExternalLinkage(classLV.getLinkage())) return LinkageInfo::none(); // If the class already has unique-external linkage, we can't improve. - if (LV.linkage() == UniqueExternalLinkage) + if (classLV.getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); - if (!OnlyTemplate) - LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode()); + // Otherwise, don't merge in classLV yet, because in certain cases + // we need to completely ignore the visibility from it. + + // Specifically, if this decl exists and has an explicit attribute. + const NamedDecl *explicitSpecSuppressor = 0; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { // If the type of the function uses a type with unique-external @@ -531,192 +781,269 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) { // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - const TemplateArgumentList &TemplateArgs = *spec->TemplateArguments; - LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs, - OnlyTemplate); - TemplateParameterList *TemplateParams = - spec->getTemplate()->getTemplateParameters(); - LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams); - if (shouldConsiderTemplateVis(MD, spec)) { - LV.mergeWithMin(ArgsLV); - if (!OnlyTemplate) - LV.mergeWithMin(ParamsLV); - } else { - LV.mergeLinkage(ArgsLV); - if (!OnlyTemplate) - LV.mergeLinkage(ParamsLV); + mergeTemplateLV(LV, MD, spec); + if (spec->isExplicitSpecialization()) { + explicitSpecSuppressor = MD; + } else if (isExplicitMemberSpecialization(spec->getTemplate())) { + explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl(); } + } else if (isExplicitMemberSpecialization(MD)) { + explicitSpecSuppressor = MD; } - // Note that in contrast to basically every other situation, we - // *do* apply -fvisibility to method declarations. - } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { if (const ClassTemplateSpecializationDecl *spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { - // Merge template argument/parameter information for member - // class template specializations. - const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); - LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs, - OnlyTemplate); - TemplateParameterList *TemplateParams = - spec->getSpecializedTemplate()->getTemplateParameters(); - LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams); - if (shouldConsiderTemplateVis(spec)) { - LV.mergeWithMin(ArgsLV); - if (!OnlyTemplate) - LV.mergeWithMin(ParamsLV); + mergeTemplateLV(LV, spec, computation); + if (spec->isExplicitSpecialization()) { + explicitSpecSuppressor = spec; } else { - LV.mergeLinkage(ArgsLV); - if (!OnlyTemplate) - LV.mergeLinkage(ParamsLV); + const ClassTemplateDecl *temp = spec->getSpecializedTemplate(); + if (isExplicitMemberSpecialization(temp)) { + explicitSpecSuppressor = temp->getTemplatedDecl(); + } } + } else if (isExplicitMemberSpecialization(RD)) { + explicitSpecSuppressor = RD; } // Static data members. } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { // Modify the variable's linkage by its type, but ignore the // type's visibility unless it's a definition. - LinkageInfo TypeLV = getLVForType(VD->getType()); - if (TypeLV.linkage() != ExternalLinkage) - LV.mergeLinkage(UniqueExternalLinkage); - LV.mergeVisibility(TypeLV); - } + LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility(); + LV.mergeMaybeWithVisibility(typeLV, + !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()); - return LV; -} + if (isExplicitMemberSpecialization(VD)) { + explicitSpecSuppressor = VD; + } -static void clearLinkageForClass(const CXXRecordDecl *record) { - for (CXXRecordDecl::decl_iterator - i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { - Decl *child = *i; - if (isa<NamedDecl>(child)) - cast<NamedDecl>(child)->ClearLinkageCache(); + // Template members. + } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { + bool considerVisibility = + (!LV.isVisibilityExplicit() && + !classLV.isVisibilityExplicit() && + !hasExplicitVisibilityAlready(computation)); + LinkageInfo tempLV = + getLVForTemplateParameterList(temp->getTemplateParameters()); + LV.mergeMaybeWithVisibility(tempLV, considerVisibility); + + if (const RedeclarableTemplateDecl *redeclTemp = + dyn_cast<RedeclarableTemplateDecl>(temp)) { + if (isExplicitMemberSpecialization(redeclTemp)) { + explicitSpecSuppressor = temp->getTemplatedDecl(); + } + } } -} -void NamedDecl::anchor() { } + // We should never be looking for an attribute directly on a template. + assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor)); -void NamedDecl::ClearLinkageCache() { - // Note that we can't skip clearing the linkage of children just - // because the parent doesn't have cached linkage: we don't cache - // when computing linkage for parent contexts. + // If this member is an explicit member specialization, and it has + // an explicit attribute, ignore visibility from the parent. + bool considerClassVisibility = true; + if (explicitSpecSuppressor && + // optimization: hasDVA() is true only with explicit visibility. + LV.isVisibilityExplicit() && + classLV.getVisibility() != DefaultVisibility && + hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) { + considerClassVisibility = false; + } - HasCachedLinkage = 0; + // Finally, merge in information from the class. + LV.mergeMaybeWithVisibility(classLV, considerClassVisibility); + return LV; +} - // If we're changing the linkage of a class, we need to reset the - // linkage of child declarations, too. - if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this)) - clearLinkageForClass(record); +void NamedDecl::anchor() { } - if (ClassTemplateDecl *temp = - dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) { - // Clear linkage for the template pattern. - CXXRecordDecl *record = temp->getTemplatedDecl(); - record->HasCachedLinkage = 0; - clearLinkageForClass(record); +bool NamedDecl::isLinkageValid() const { + if (!HasCachedLinkage) + return true; - // We need to clear linkage for specializations, too. - for (ClassTemplateDecl::spec_iterator - i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLinkageCache(); - } + return getLVForDecl(this, LVForExplicitValue).getLinkage() == + Linkage(CachedLinkage); +} - // Clear cached linkage for function template decls, too. - if (FunctionTemplateDecl *temp = - dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) { - temp->getTemplatedDecl()->ClearLinkageCache(); - for (FunctionTemplateDecl::spec_iterator - i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLinkageCache(); - } - +bool NamedDecl::hasExternalLinkageUncached() const { + return getLVForDecl(this, LVForExplicitValue).getLinkage() == ExternalLinkage; } Linkage NamedDecl::getLinkage() const { - if (HasCachedLinkage) { - assert(Linkage(CachedLinkage) == - getLVForDecl(this, true).linkage()); + if (HasCachedLinkage) return Linkage(CachedLinkage); - } - CachedLinkage = getLVForDecl(this, true).linkage(); + // We don't care about visibility here, so ask for the cheapest + // possible visibility analysis. + CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage(); HasCachedLinkage = 1; + +#ifndef NDEBUG + verifyLinkage(); +#endif + return Linkage(CachedLinkage); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { - LinkageInfo LI = getLVForDecl(this, false); - assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage()); + LVComputationKind computation = + (usesTypeVisibility(this) ? LVForType : LVForValue); + LinkageInfo LI = getLVForDecl(this, computation); + if (HasCachedLinkage) { + assert(Linkage(CachedLinkage) == LI.getLinkage()); + return LI; + } HasCachedLinkage = 1; - CachedLinkage = LI.linkage(); + CachedLinkage = LI.getLinkage(); + +#ifndef NDEBUG + verifyLinkage(); +#endif + return LI; } -llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const { - // Use the most recent declaration of a variable. - if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { - if (llvm::Optional<Visibility> V = - getVisibilityOf(Var->getMostRecentDecl())) - return V; +void NamedDecl::verifyLinkage() const { + // In C (because of gnu inline) and in c++ with microsoft extensions an + // static can follow an extern, so we can have two decls with different + // linkages. + const LangOptions &Opts = getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return; + + // We have just computed the linkage for this decl. By induction we know + // that all other computed linkages match, check that the one we just computed + // also does. + NamedDecl *D = NULL; + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + NamedDecl *T = cast<NamedDecl>(*I); + if (T == this) + continue; + if (T->HasCachedLinkage != 0) { + D = T; + break; + } + } + assert(!D || D->CachedLinkage == CachedLinkage); +} + +Optional<Visibility> +NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { + // Check the declaration itself first. + if (Optional<Visibility> V = getVisibilityOf(this, kind)) + return V; + + // If this is a member class of a specialization of a class template + // and the corresponding decl has explicit visibility, use that. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) { + CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); + if (InstantiatedFrom) + return getVisibilityOf(InstantiatedFrom, kind); + } + + // If there wasn't explicit visibility there, and this is a + // specialization of a class template, check for visibility + // on the pattern. + if (const ClassTemplateSpecializationDecl *spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) + return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(), + kind); + // Use the most recent declaration. + const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl()); + if (MostRecent != this) + return MostRecent->getExplicitVisibility(kind); + + if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { if (Var->isStaticDataMember()) { VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember(); if (InstantiatedFrom) - return getVisibilityOf(InstantiatedFrom); + return getVisibilityOf(InstantiatedFrom, kind); } - return llvm::Optional<Visibility>(); + return None; } - // Use the most recent declaration of a function, and also handle - // function template specializations. + // Also handle function template specializations. if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) { - if (llvm::Optional<Visibility> V - = getVisibilityOf(fn->getMostRecentDecl())) - return V; - // If the function is a specialization of a template with an // explicit visibility attribute, use that. if (FunctionTemplateSpecializationInfo *templateInfo = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl()); + return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), + kind); // If the function is a member of a specialization of a class template // and the corresponding decl has explicit visibility, use that. FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); if (InstantiatedFrom) - return getVisibilityOf(InstantiatedFrom); + return getVisibilityOf(InstantiatedFrom, kind); - return llvm::Optional<Visibility>(); + return None; } - // Otherwise, just check the declaration itself first. - if (llvm::Optional<Visibility> V = getVisibilityOf(this)) - return V; - // The visibility of a template is stored in the templated decl. if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this)) - return getVisibilityOf(TD->getTemplatedDecl()); + return getVisibilityOf(TD->getTemplatedDecl(), kind); - // If there wasn't explicit visibility there, and this is a - // specialization of a class template, check for visibility - // on the pattern. - if (const ClassTemplateSpecializationDecl *spec - = dyn_cast<ClassTemplateSpecializationDecl>(this)) - return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl()); + return None; +} - // If this is a member class of a specialization of a class template - // and the corresponding decl has explicit visibility, use that. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) { - CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); - if (InstantiatedFrom) - return getVisibilityOf(InstantiatedFrom); +static LinkageInfo getLVForLocalDecl(const NamedDecl *D, + LVComputationKind computation) { + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + if (Function->isInAnonymousNamespace() && + !Function->getDeclContext()->isExternCContext()) + return LinkageInfo::uniqueExternal(); + + // This is a "void f();" which got merged with a file static. + if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) + return LinkageInfo::internal(); + + LinkageInfo LV; + if (!hasExplicitVisibilityAlready(computation)) { + if (Optional<Visibility> Vis = + getExplicitVisibility(Function, computation)) + LV.mergeVisibility(*Vis, true); + } + + // Note that Sema::MergeCompatibleFunctionDecls already takes care of + // merging storage classes and visibility attributes, so we don't have to + // look at previous decls in here. + + return LV; } - return llvm::Optional<Visibility>(); + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->hasExternalStorage()) { + if (Var->isInAnonymousNamespace() && + !Var->getDeclContext()->isExternCContext()) + return LinkageInfo::uniqueExternal(); + + LinkageInfo LV; + if (Var->getStorageClass() == SC_PrivateExtern) + LV.mergeVisibility(HiddenVisibility, true); + else if (!hasExplicitVisibilityAlready(computation)) { + if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation)) + LV.mergeVisibility(*Vis, true); + } + + if (const VarDecl *Prev = Var->getPreviousDecl()) { + LinkageInfo PrevLV = getLVForDecl(Prev, computation); + if (PrevLV.getLinkage()) + LV.setLinkage(PrevLV.getLinkage()); + LV.mergeVisibility(PrevLV); + } + + return LV; + } + } + + return LinkageInfo::none(); } -static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { +static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { @@ -751,12 +1078,11 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { if (isa<ParmVarDecl>(ContextDecl)) DC = ContextDecl->getDeclContext()->getRedeclContext(); else - return getLVForDecl(cast<NamedDecl>(ContextDecl), - OnlyTemplate); + return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); } if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) - return getLVForDecl(ND, OnlyTemplate); + return getLVForDecl(ND, computation); return LinkageInfo::external(); } @@ -767,7 +1093,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { // Handle linkage for namespace-scope names. if (D->getDeclContext()->getRedeclContext()->isFileContext()) - return getLVForNamespaceScopeDecl(D, OnlyTemplate); + return getLVForNamespaceScopeDecl(D, computation); // C++ [basic.link]p5: // In addition, a member function, static data member, a named @@ -777,7 +1103,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { // purposes (7.1.3), has external linkage if the name of the class // has external linkage. if (D->getDeclContext()->isRecord()) - return getLVForClassMember(D, OnlyTemplate); + return getLVForClassMember(D, computation); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -790,48 +1116,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { // one such matching entity, the program is ill-formed. Otherwise, // if no matching entity is found, the block scope entity receives // external linkage. - if (D->getLexicalDeclContext()->isFunctionOrMethod()) { - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { - if (Function->isInAnonymousNamespace() && - !Function->getDeclContext()->isExternCContext()) - return LinkageInfo::uniqueExternal(); - - LinkageInfo LV; - if (!OnlyTemplate) { - if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility()) - LV.mergeVisibility(*Vis, true); - } - - if (const FunctionDecl *Prev = Function->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } - - return LV; - } - - if (const VarDecl *Var = dyn_cast<VarDecl>(D)) - if (Var->getStorageClass() == SC_Extern || - Var->getStorageClass() == SC_PrivateExtern) { - if (Var->isInAnonymousNamespace() && - !Var->getDeclContext()->isExternCContext()) - return LinkageInfo::uniqueExternal(); - - LinkageInfo LV; - if (Var->getStorageClass() == SC_PrivateExtern) - LV.mergeVisibility(HiddenVisibility, true); - else if (!OnlyTemplate) { - if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility()) - LV.mergeVisibility(*Vis, true); - } - - // Note that Sema::MergeVarDecl already takes care of implementing - // C99 6.2.2p4 and propagating the visibility attribute, so we don't - // have to do it here. - return LV; - } - } + if (D->getDeclContext()->isFunctionOrMethod()) + return getLVForLocalDecl(D, computation); // C++ [basic.link]p6: // Names not covered by these rules have no linkage. @@ -843,10 +1129,24 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { + std::string QualName; + llvm::raw_string_ostream OS(QualName); + printQualifiedName(OS, P); + return OS.str(); +} + +void NamedDecl::printQualifiedName(raw_ostream &OS) const { + printQualifiedName(OS, getASTContext().getPrintingPolicy()); +} + +void NamedDecl::printQualifiedName(raw_ostream &OS, + const PrintingPolicy &P) const { const DeclContext *Ctx = getDeclContext(); - if (Ctx->isFunctionOrMethod()) - return getNameAsString(); + if (Ctx->isFunctionOrMethod()) { + printName(OS); + return; + } typedef SmallVector<const DeclContext *, 8> ContextsTy; ContextsTy Contexts; @@ -855,22 +1155,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { while (Ctx && isa<NamedDecl>(Ctx)) { Contexts.push_back(Ctx); Ctx = Ctx->getParent(); - }; - - std::string QualName; - llvm::raw_string_ostream OS(QualName); + } for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend(); I != E; ++I) { if (const ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(*I)) { + OS << Spec->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.data(), - TemplateArgs.size(), - P); - OS << Spec->getName() << TemplateArgsStr; + TemplateSpecializationType::PrintTemplateArgumentList(OS, + TemplateArgs.data(), + TemplateArgs.size(), + P); } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) { if (ND->isAnonymousNamespace()) OS << "<anonymous namespace>"; @@ -912,8 +1208,15 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { OS << *this; else OS << "<anonymous>"; +} - return OS.str(); +void NamedDecl::getNameForDiagnostic(raw_ostream &OS, + const PrintingPolicy &Policy, + bool Qualified) const { + if (Qualified) + printQualifiedName(OS, Policy); + else + printName(OS); } bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { @@ -1166,45 +1469,80 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten) { - return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten); + StorageClass S) { + return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S); } VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl)); return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, SC_None, SC_None); + QualType(), 0, SC_None); } void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); - if (getStorageClass() != SC) - ClearLinkageCache(); - VarDeclBits.SClass = SC; } SourceRange VarDecl::getSourceRange() const { if (const Expr *Init = getInit()) { SourceLocation InitEnd = Init->getLocEnd(); - if (InitEnd.isValid()) + // If Init is implicit, ignore its source range and fallback on + // DeclaratorDecl::getSourceRange() to handle postfix elements. + if (InitEnd.isValid() && InitEnd != getLocation()) return SourceRange(getOuterLocStart(), InitEnd); } return DeclaratorDecl::getSourceRange(); } -bool VarDecl::isExternC() const { - if (getLinkage() != ExternalLinkage) - return false; +template<typename T> +static LanguageLinkage getLanguageLinkageTemplate(const T &D) { + // C++ [dcl.link]p1: All function types, function names with external linkage, + // and variable names with external linkage have a language linkage. + if (!isExternalLinkage(D.getLinkage())) + return NoLanguageLinkage; + + // Language linkage is a C++ concept, but saying that everything else in C has + // C language linkage fits the implementation nicely. + ASTContext &Context = D.getASTContext(); + if (!Context.getLangOpts().CPlusPlus) + return CLanguageLinkage; - const DeclContext *DC = getDeclContext(); + // C++ [dcl.link]p4: A C language linkage is ignored in determining the + // language linkage of the names of class members and the function type of + // class member functions. + const DeclContext *DC = D.getDeclContext(); if (DC->isRecord()) + return CXXLanguageLinkage; + + // If the first decl is in an extern "C" context, any other redeclaration + // will have C language linkage. If the first one is not in an extern "C" + // context, we would have reported an error for any other decl being in one. + const T *First = D.getFirstDeclaration(); + if (First->getDeclContext()->isExternCContext()) + return CLanguageLinkage; + return CXXLanguageLinkage; +} + +template<typename T> +static bool isExternCTemplate(const T &D) { + // Since the context is ignored for class members, they can only have C++ + // language linkage or no language linkage. + const DeclContext *DC = D.getDeclContext(); + if (DC->isRecord()) { + assert(D.getASTContext().getLangOpts().CPlusPlus); return false; + } - ASTContext &Context = getASTContext(); - if (!Context.getLangOpts().CPlusPlus) - return true; - return DC->isExternCContext(); + return D.getLanguageLinkage() == CLanguageLinkage; +} + +LanguageLinkage VarDecl::getLanguageLinkage() const { + return getLanguageLinkageTemplate(*this); +} + +bool VarDecl::isExternC() const { + return isExternCTemplate(*this); } VarDecl *VarDecl::getCanonicalDecl() { @@ -1241,12 +1579,11 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // AST for 'extern "C" int foo;' is annotated with 'extern'. if (hasExternalStorage()) return DeclarationOnly; - - if (getStorageClassAsWritten() == SC_Extern || - getStorageClassAsWritten() == SC_PrivateExtern) { + + if (hasExternalStorage()) { for (const VarDecl *PrevVar = getPreviousDecl(); PrevVar; PrevVar = PrevVar->getPreviousDecl()) { - if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit()) + if (PrevVar->getLinkage() == InternalLinkage) return DeclarationOnly; } } @@ -1375,7 +1712,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { // In C++11, any variable of reference type can be used in a constant // expression if it is initialized by a constant expression. - if (Lang.CPlusPlus0x && getType()->isReferenceType()) + if (Lang.CPlusPlus11 && getType()->isReferenceType()) return true; // Only const objects can be used in constant expressions in C++. C++98 does @@ -1391,7 +1728,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { // Additionally, in C++11, non-volatile constexpr variables can be used in // constant expressions. - return Lang.CPlusPlus0x && isConstexpr(); + return Lang.CPlusPlus11 && isConstexpr(); } /// Convert the initializer for this declaration to the elaborated EvaluatedStmt @@ -1409,12 +1746,12 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const { } APValue *VarDecl::evaluateValue() const { - llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + SmallVector<PartialDiagnosticAt, 8> Notes; return evaluateValue(Notes); } APValue *VarDecl::evaluateValue( - llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const { + SmallVectorImpl<PartialDiagnosticAt> &Notes) const { EvaluatedStmt *Eval = ensureEvaluatedStmt(); // We only produce notes indicating why an initializer is non-constant the @@ -1447,7 +1784,7 @@ APValue *VarDecl::evaluateValue( // In C++11, we have determined whether the initializer was a constant // expression as a side-effect. - if (getASTContext().getLangOpts().CPlusPlus0x && !Eval->CheckedICE) { + if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) { Eval->CheckedICE = true; Eval->IsICE = Result && Notes.empty(); } @@ -1471,8 +1808,8 @@ bool VarDecl::checkInitIsICE() const { // In C++11, evaluate the initializer to check whether it's a constant // expression. - if (getASTContext().getLangOpts().CPlusPlus0x) { - llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + if (getASTContext().getLangOpts().CPlusPlus11) { + SmallVector<PartialDiagnosticAt, 8> Notes; evaluateValue(Notes); return Eval->IsICE; } @@ -1541,16 +1878,15 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten, - Expr *DefArg) { + StorageClass S, Expr *DefArg) { return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo, - S, SCAsWritten, DefArg); + S, DefArg); } ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl)); return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(), - 0, QualType(), 0, SC_None, SC_None, 0); + 0, QualType(), 0, SC_None, 0); } SourceRange ParmVarDecl::getSourceRange() const { @@ -1602,17 +1938,13 @@ unsigned ParmVarDecl::getParameterIndexLarge() const { // FunctionDecl Implementation //===----------------------------------------------------------------------===// -void FunctionDecl::getNameForDiagnostic(std::string &S, - const PrintingPolicy &Policy, - bool Qualified) const { - NamedDecl::getNameForDiagnostic(S, Policy, Qualified); +void FunctionDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); if (TemplateArgs) - S += TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs->data(), - TemplateArgs->size(), - Policy); - + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs->data(), TemplateArgs->size(), Policy); } bool FunctionDecl::isVariadic() const { @@ -1684,13 +2016,6 @@ void FunctionDecl::setPure(bool P) { Parent->markedVirtualFunctionPure(); } -void FunctionDecl::setConstexpr(bool IC) { - IsConstexpr = IC; - CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this); - if (IC && CD) - CD->getParent()->markedConstructorConstexpr(CD); -} - bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); @@ -1722,29 +2047,25 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } -bool FunctionDecl::isExternC() const { - if (getLinkage() != ExternalLinkage) - return false; - - if (getAttr<OverloadableAttr>()) - return false; - - const DeclContext *DC = getDeclContext(); - if (DC->isRecord()) - return false; +LanguageLinkage FunctionDecl::getLanguageLinkage() const { + // Users expect to be able to write + // extern "C" void *__builtin_alloca (size_t); + // so consider builtins as having C language linkage. + if (getBuiltinID()) + return CLanguageLinkage; - ASTContext &Context = getASTContext(); - if (!Context.getLangOpts().CPlusPlus) - return true; + return getLanguageLinkageTemplate(*this); +} - return isMain() || DC->isExternCContext(); +bool FunctionDecl::isExternC() const { + return isExternCTemplate(*this); } bool FunctionDecl::isGlobal() const { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) return Method->isStatic(); - if (getStorageClass() == SC_Static) + if (getCanonicalDecl()->getStorageClass() == SC_Static) return false; for (const DeclContext *DC = getDeclContext(); @@ -1760,6 +2081,12 @@ bool FunctionDecl::isGlobal() const { return true; } +bool FunctionDecl::isNoReturn() const { + return hasAttr<NoReturnAttr>() || hasAttr<CXX11NoReturnAttr>() || + hasAttr<C11NoReturnAttr>() || + getType()->getAs<FunctionType>()->getNoReturnAttr(); +} + void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDeclaration(PrevDecl); @@ -1783,14 +2110,6 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDeclaration(); } -void FunctionDecl::setStorageClass(StorageClass SC) { - assert(isLegalForFunction(SC)); - if (getStorageClass() != SC) - ClearLinkageCache(); - - SClass = SC; -} - /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -1851,7 +2170,7 @@ unsigned FunctionDecl::getNumParams() const { } void FunctionDecl::setParams(ASTContext &C, - llvm::ArrayRef<ParmVarDecl *> NewParamInfo) { + ArrayRef<ParmVarDecl *> NewParamInfo) { assert(ParamInfo == 0 && "Already has param info!"); assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!"); @@ -1862,13 +2181,13 @@ void FunctionDecl::setParams(ASTContext &C, } } -void FunctionDecl::setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) { +void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) { assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!"); if (!NewDecls.empty()) { NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()]; std::copy(NewDecls.begin(), NewDecls.end(), A); - DeclsInPrototypeScope = llvm::ArrayRef<NamedDecl*>(A, NewDecls.size()); + DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size()); } } @@ -1907,38 +2226,6 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -bool FunctionDecl::isInlined() const { - if (IsInline) - return true; - - if (isa<CXXMethodDecl>(this)) { - if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified()) - return true; - } - - switch (getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return false; - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - // Handle below. - break; - } - - const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); - bool HasPattern = false; - if (PatternDecl) - HasPattern = PatternDecl->hasBody(PatternDecl); - - if (HasPattern && PatternDecl) - return PatternDecl->isInlined(); - - return false; -} - static bool RedeclForcesDefC99(const FunctionDecl *Redecl) { // Only consider file-scope declarations in this test. if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) @@ -1973,7 +2260,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { // // FIXME: What happens if gnu_inline gets added on after the first // declaration? - if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern) + if (!isInlineSpecified() || getStorageClass() == SC_Extern) return false; const FunctionDecl *Prev = this; @@ -1985,10 +2272,10 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then it is always externally visible. if (!Prev->isInlineSpecified() || - Prev->getStorageClassAsWritten() != SC_Extern) + Prev->getStorageClass() != SC_Extern) return false; } else if (Prev->isInlineSpecified() && - Prev->getStorageClassAsWritten() != SC_Extern) { + Prev->getStorageClass() != SC_Extern) { return false; } } @@ -2014,8 +2301,8 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { return FoundBody; } -/// \brief For an inline function definition in C or C++, determine whether the -/// definition will be externally visible. +/// \brief For an inline function definition in C, or for a gnu_inline function +/// in C++, determine whether the definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. /// However, depending on the language dialect, declaration specifiers, and @@ -2043,7 +2330,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then this inline definition is // externally visible. - if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern)) + if (!(isInlineSpecified() && getStorageClass() == SC_Extern)) return true; // If any declaration is 'inline' but not 'extern', then this definition @@ -2052,13 +2339,17 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { Redecl != RedeclEnd; ++Redecl) { if (Redecl->isInlineSpecified() && - Redecl->getStorageClassAsWritten() != SC_Extern) + Redecl->getStorageClass() != SC_Extern) return true; } return false; } + // The rest of this function is C-only. + assert(!Context.getLangOpts().CPlusPlus && + "should not use C inline rules in C++"); + // C99 6.7.4p6: // [...] If all of the file scope declarations for a function in a // translation unit include the inline function specifier without extern, @@ -2118,10 +2409,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { return 0; } -MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { - return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); -} - void FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, @@ -2553,18 +2840,17 @@ TagDecl* TagDecl::getCanonicalDecl() { return getFirstDeclaration(); } -void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { - TypedefNameDeclOrQualifier = TDD; +void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { + TypedefNameDeclOrQualifier = TDD; if (TypeForDecl) - const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); - ClearLinkageCache(); + assert(TypeForDecl->isLinkageValid()); + assert(isLinkageValid()); } void TagDecl::startDefinition() { IsBeingDefined = true; - if (isa<CXXRecordDecl>(this)) { - CXXRecordDecl *D = cast<CXXRecordDecl>(this); + if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) { struct CXXRecordDecl::DefinitionData *Data = new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) @@ -2587,6 +2873,16 @@ void TagDecl::completeDefinition() { TagDecl *TagDecl::getDefinition() const { if (isCompleteDefinition()) return const_cast<TagDecl *>(this); + + // If it's possible for us to have an out-of-date definition, check now. + if (MayHaveOutOfDateDef) { + if (IdentifierInfo *II = getIdentifier()) { + if (II->isOutOfDate()) { + updateOutOfDate(*II); + } + } + } + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this)) return CXXRD->getDefinition(); @@ -2643,14 +2939,17 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, bool IsScopedUsingClassTag, bool IsFixed) { EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, IsScopedUsingClassTag, IsFixed); + Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; C.getTypeDeclType(Enum, PrevDecl); return Enum; } EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl)); - return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0, - false, false, false); + EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), + 0, 0, false, false, false); + Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules; + return Enum; } void EnumDecl::completeDefinition(QualType NewType, @@ -2708,6 +3007,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; HasObjectMember = false; + HasVolatileMember = false; LoadedFieldsFromExternalStorage = false; assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } @@ -2717,14 +3017,18 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, IdentifierInfo *Id, RecordDecl* PrevDecl) { RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id, PrevDecl); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; + C.getTypeDeclType(R, PrevDecl); return R; } RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl)); - return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), - SourceLocation(), 0, 0); + RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; + return R; } bool RecordDecl::isInjectedClassName() const { @@ -2793,7 +3097,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { // BlockDecl Implementation //===----------------------------------------------------------------------===// -void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) { +void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { assert(ParamInfo == 0 && "Already has param info!"); // Zero params -> null pointer. @@ -2871,6 +3175,14 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void ValueDecl::anchor() { } +bool ValueDecl::isWeak() const { + for (attr_iterator I = attr_begin(), E = attr_end(); I != E; ++I) + if (isa<WeakAttr>(*I) || isa<WeakRefAttr>(*I)) + return true; + + return isWeakImported(); +} + void ImplicitParamDecl::anchor() { } ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, @@ -2890,12 +3202,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, StorageClass SCAsWritten, + StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, bool isConstexprSpecified) { FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo, - T, TInfo, SC, SCAsWritten, + T, TInfo, SC, isInlineSpecified, isConstexprSpecified); New->HasWrittenPrototype = hasWrittenPrototype; @@ -2906,7 +3218,7 @@ FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl)); return new (Mem) FunctionDecl(Function, 0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, - SC_None, SC_None, false, false); + SC_None, false, false); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { @@ -3013,6 +3325,17 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C, return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation()); } +void EmptyDecl::anchor() {} + +EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) EmptyDecl(DC, L); +} + +EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl)); + return new (Mem) EmptyDecl(0, SourceLocation()); +} + //===----------------------------------------------------------------------===// // ImportDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 4400d503f263..bd6d99cd59ea 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -12,19 +12,21 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclBase.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" @@ -39,6 +41,10 @@ using namespace clang; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" +void Decl::updateOutOfDate(IdentifierInfo &II) const { + getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); +} + void *Decl::AllocateDeserializedDecl(const ASTContext &Context, unsigned ID, unsigned Size) { @@ -58,6 +64,11 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context, return Result; } +Module *Decl::getOwningModuleSlow() const { + assert(isFromASTFile() && "Not from AST file?"); + return getASTContext().getExternalSource()->getModule(getOwningModuleID()); +} + const char *Decl::getDeclKindName() const { switch (DeclKind) { default: llvm_unreachable("Declaration not in DeclNodes.inc!"); @@ -180,8 +191,11 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const { OS << Message; - if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) - OS << " '" << DN->getQualifiedNameAsString() << '\''; + if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) { + OS << " '"; + DN->printQualifiedName(OS); + OS << '\''; + } OS << '\n'; } @@ -253,6 +267,19 @@ ASTMutationListener *Decl::getASTMutationListener() const { return getASTContext().getASTMutationListener(); } +unsigned Decl::getMaxAlignment() const { + if (!hasAttrs()) + return 0; + + unsigned Align = 0; + const AttrVec &V = getAttrs(); + ASTContext &Ctx = getASTContext(); + specific_attr_iterator<AlignedAttr> I(V.begin()), E(V.end()); + for (; I != E; ++I) + Align = std::max(Align, I->getAlignment(Ctx)); + return Align; +} + bool Decl::isUsed(bool CheckUsedAttr) const { if (Used) return true; @@ -260,13 +287,7 @@ bool Decl::isUsed(bool CheckUsedAttr) const { // Check for used attribute. if (CheckUsedAttr && hasAttr<UsedAttr>()) return true; - - // Check redeclarations for used attribute. - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used) - return true; - } - + return false; } @@ -414,7 +435,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const { // Variables, if they aren't definitions. if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { - if (!Var->hasExternalStorage() || Var->getInit()) { + if (Var->isThisDeclarationADefinition()) { IsDefinition = true; return false; } @@ -541,6 +562,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCategory: case ObjCCategoryImpl: case Import: + case OMPThreadPrivate: + case Empty: // Never looked up by name. return 0; } @@ -789,6 +812,17 @@ bool DeclContext::isExternCContext() const { return false; } +bool DeclContext::isExternCXXContext() const { + const DeclContext *DC = this; + while (DC->DeclKind != Decl::TranslationUnit) { + if (DC->DeclKind == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() + == LinkageSpecDecl::lang_cxx; + DC = DC->getParent(); + } + return false; +} + bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -862,7 +896,7 @@ DeclContext *DeclContext::getPrimaryContext() { } void -DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){ +DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){ Contexts.clear(); if (DeclKind != Decl::Namespace) { @@ -900,6 +934,21 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls, return std::make_pair(FirstNewDecl, PrevDecl); } +/// \brief We have just acquired external visible storage, and we already have +/// built a lookup map. For every name in the map, pull in the new names from +/// the external storage. +void DeclContext::reconcileExternalVisibleStorage() { + assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer()); + NeedToReconcileExternalVisibleStorage = false; + + StoredDeclsMap &Map = *LookupPtr.getPointer(); + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) { + I->second.removeExternalDecls(); + Source->FindExternalVisibleDeclsByName(this, I->first); + } +} + /// \brief Load the declarations within this lexical storage from an /// external source. void @@ -950,9 +999,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, if (!(Map = DC->LookupPtr.getPointer())) Map = DC->CreateStoredDeclsMap(Context); - StoredDeclsList &List = (*Map)[Name]; - assert(List.isNull()); - (void) List; + // Add an entry to the map for this name, if it's not already present. + (*Map)[Name]; return DeclContext::lookup_result(); } @@ -962,7 +1010,6 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef<NamedDecl*> Decls) { ASTContext &Context = DC->getParentASTContext(); - StoredDeclsMap *Map; if (!(Map = DC->LookupPtr.getPointer())) Map = DC->CreateStoredDeclsMap(Context); @@ -973,6 +1020,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, if (List.isNull()) List.setOnlyValue(*I); else + // FIXME: Need declarationReplaces handling for redeclarations in modules. List.AddSubsequentDecl(*I); } @@ -1114,16 +1162,18 @@ static bool shouldBeHidden(NamedDecl *D) { StoredDeclsMap *DeclContext::buildLookup() { assert(this == getPrimaryContext() && "buildLookup called on non-primary DC"); + // FIXME: Should we keep going if hasExternalVisibleStorage? if (!LookupPtr.getInt()) return LookupPtr.getPointer(); - llvm::SmallVector<DeclContext *, 2> Contexts; + SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) buildLookupImpl(Contexts[I]); // We no longer have any lazy decls. LookupPtr.setInt(false); + NeedToReconcileExternalVisibleStorage = false; return LookupPtr.getPointer(); } @@ -1162,18 +1212,33 @@ DeclContext::lookup(DeclarationName Name) { return PrimaryContext->lookup(Name); if (hasExternalVisibleStorage()) { - // If a PCH has a result for this name, and we have a local declaration, we - // will have imported the PCH result when adding the local declaration. - // FIXME: For modules, we could have had more declarations added by module - // imoprts since we saw the declaration of the local name. - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { - StoredDeclsMap::iterator I = Map->find(Name); - if (I != Map->end()) - return I->second.getLookupResult(); - } + StoredDeclsMap *Map = LookupPtr.getPointer(); + if (LookupPtr.getInt()) + Map = buildLookup(); + else if (NeedToReconcileExternalVisibleStorage) + reconcileExternalVisibleStorage(); + + if (!Map) + Map = CreateStoredDeclsMap(getParentASTContext()); + + // If a PCH/module has a result for this name, and we have a local + // declaration, we will have imported the PCH/module result when adding the + // local declaration or when reconciling the module. + std::pair<StoredDeclsMap::iterator, bool> R = + Map->insert(std::make_pair(Name, StoredDeclsList())); + if (!R.second) + return R.first->second.getLookupResult(); ExternalASTSource *Source = getParentASTContext().getExternalSource(); - return Source->FindExternalVisibleDeclsByName(this, Name); + if (Source->FindExternalVisibleDeclsByName(this, Name)) { + if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + StoredDeclsMap::iterator I = Map->find(Name); + if (I != Map->end()) + return I->second.getLookupResult(); + } + } + + return lookup_result(lookup_iterator(0), lookup_iterator(0)); } StoredDeclsMap *Map = LookupPtr.getPointer(); @@ -1190,26 +1255,26 @@ DeclContext::lookup(DeclarationName Name) { return I->second.getLookupResult(); } -void DeclContext::localUncachedLookup(DeclarationName Name, - llvm::SmallVectorImpl<NamedDecl *> &Results) { +void DeclContext::localUncachedLookup(DeclarationName Name, + SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); // If there's no external storage, just perform a normal lookup and copy // the results. if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) { lookup_result LookupResults = lookup(Name); - Results.insert(Results.end(), LookupResults.first, LookupResults.second); + Results.insert(Results.end(), LookupResults.begin(), LookupResults.end()); return; } // If we have a lookup table, check there first. Maybe we'll get lucky. - if (Name) { + if (Name && !LookupPtr.getInt()) { if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator Pos = Map->find(Name); if (Pos != Map->end()) { Results.insert(Results.end(), - Pos->second.getLookupResult().first, - Pos->second.getLookupResult().second); + Pos->second.getLookupResult().begin(), + Pos->second.getLookupResult().end()); return; } } @@ -1361,8 +1426,8 @@ DeclContext::getUsingDirectives() const { // FIXME: Use something more efficient than normal lookup for using // directives. In C++, using directives are looked up more than anything else. lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); - return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), - reinterpret_cast<udir_iterator>(Result.second)); + return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.begin()), + reinterpret_cast<udir_iterator>(Result.end())); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 82e630acefba..ffad9ae93cc8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" @@ -36,28 +36,33 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { } CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) - : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), - UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false), - UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false), + : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasOnlyCMembers(true), - HasInClassInitializer(false), - HasTrivialDefaultConstructor(true), + HasInClassInitializer(false), HasUninitializedReferenceMember(false), + NeedOverloadResolutionForMoveConstructor(false), + NeedOverloadResolutionForMoveAssignment(false), + NeedOverloadResolutionForDestructor(false), + DefaultedMoveConstructorIsDeleted(false), + DefaultedMoveAssignmentIsDeleted(false), + DefaultedDestructorIsDeleted(false), + HasTrivialSpecialMembers(SMF_All), + DeclaredNonTrivialSpecialMembers(0), + HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), DefaultedDefaultConstructorIsConstexpr(true), - HasConstexprDefaultConstructor(false), HasTrivialCopyConstructor(true), - HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), - HasTrivialMoveAssignment(true), HasTrivialDestructor(true), - HasIrrelevantDestructor(true), + HasConstexprDefaultConstructor(false), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), - UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), - DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), - DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), - DeclaredDestructor(false), FailedImplicitMoveConstructor(false), - FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0), - NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) { + UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), + ImplicitCopyConstructorHasConstParam(true), + ImplicitCopyAssignmentHasConstParam(true), + HasDeclaredCopyConstructorWithConstParam(false), + HasDeclaredCopyAssignmentWithConstParam(false), + FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false), + IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(), + Definition(D), FirstFriend(0) { } CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { @@ -82,6 +87,7 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, bool DelayTypeCreation) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc, Id, PrevDecl); + R->MayHaveOutOfDateDef = C.getLangOpts().Modules; // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) @@ -96,6 +102,7 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, 0, 0); R->IsBeingDefined = true; R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); + R->MayHaveOutOfDateDef = false; C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -103,8 +110,11 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, CXXRecordDecl * CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl)); - return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), - SourceLocation(), 0, 0); + CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, + SourceLocation(), SourceLocation(), + 0, 0); + R->MayHaveOutOfDateDef = false; + return R; } void @@ -184,38 +194,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { // Add this base if it's not already in the list. - if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) + if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) { VBases.push_back(VBase); + + // C++11 [class.copy]p8: + // The implicitly-declared copy constructor for a class X will have + // the form 'X::X(const X&)' if each [...] virtual base class B of X + // has a copy constructor whose first parameter is of type + // 'const B&' or 'const volatile B&' [...] + if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl()) + if (!VBaseDecl->hasCopyConstructorWithConstParam()) + data().ImplicitCopyConstructorHasConstParam = false; + } } if (Base->isVirtual()) { // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) - VBases.push_back(Base); - + VBases.push_back(Base); + // C++0x [meta.unary.prop] is_empty: // T is a class type, but not a union type, with ... no virtual base // classes data().Empty = false; - - // C++ [class.ctor]p5: - // A default constructor is trivial [...] if: - // -- its class has [...] no virtual bases - data().HasTrivialDefaultConstructor = false; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is neither - // user-provided nor deleted and if - // -- class X has no virtual functions and no virtual base classes, and - data().HasTrivialCopyConstructor = false; - data().HasTrivialMoveConstructor = false; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted and if - // -- class X has no virtual functions and no virtual base classes, and - data().HasTrivialCopyAssignment = false; - data().HasTrivialMoveAssignment = false; + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor, copy/move constructor, or copy/move assignment + // operator for a class X] is trivial [...] if: + // -- class X has [...] no virtual base classes + data().HasTrivialSpecialMembers &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] @@ -232,36 +239,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // -- all the direct base classes of its class have trivial default // constructors. if (!BaseClassDecl->hasTrivialDefaultConstructor()) - data().HasTrivialDefaultConstructor = false; - + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; + // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] // [...] // -- the constructor selected to copy/move each direct base class // subobject is trivial, and - // FIXME: C++0x: We need to only consider the selected constructor - // instead of all of them. For now, we treat a move constructor as being - // non-trivial if it calls anything other than a trivial move constructor. if (!BaseClassDecl->hasTrivialCopyConstructor()) - data().HasTrivialCopyConstructor = false; - if (!BaseClassDecl->hasTrivialMoveConstructor() || - !(BaseClassDecl->hasDeclaredMoveConstructor() || - BaseClassDecl->needsImplicitMoveConstructor())) - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + // If the base class doesn't have a simple move constructor, we'll eagerly + // declare it and perform overload resolution to determine which function + // it actually calls. If it does have a simple move constructor, this + // check is correct. + if (!BaseClassDecl->hasTrivialMoveConstructor()) + data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] // [...] // -- the assignment operator selected to copy/move each direct base // class subobject is trivial, and - // FIXME: C++0x: We need to only consider the selected operator instead - // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) - data().HasTrivialCopyAssignment = false; - if (!BaseClassDecl->hasTrivialMoveAssignment() || - !(BaseClassDecl->hasDeclaredMoveAssignment() || - BaseClassDecl->needsImplicitMoveAssignment())) - data().HasTrivialMoveAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; + // If the base class doesn't have a simple move assignment, we'll eagerly + // declare it and perform overload resolution to determine which function + // it actually calls. If it does have a simple move assignment, this + // check is correct. + if (!BaseClassDecl->hasTrivialMoveAssignment()) + data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; // C++11 [class.ctor]p6: // If that user-written default constructor would satisfy the @@ -270,24 +276,48 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasConstexprDefaultConstructor()) data().DefaultedDefaultConstructorIsConstexpr = false; } - + // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. if (!BaseClassDecl->hasTrivialDestructor()) - data().HasTrivialDestructor = false; + data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!BaseClassDecl->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; + // C++11 [class.copy]p18: + // The implicitly-declared copy assignment oeprator for a class X will + // have the form 'X& X::operator=(const X&)' if each direct base class B + // of X has a copy assignment operator whose parameter is of type 'const + // B&', 'const volatile B&', or 'B' [...] + if (!BaseClassDecl->hasCopyAssignmentWithConstParam()) + data().ImplicitCopyAssignmentHasConstParam = false; + + // C++11 [class.copy]p8: + // The implicitly-declared copy constructor for a class X will have + // the form 'X::X(const X&)' if each direct [...] base class B of X + // has a copy constructor whose first parameter is of type + // 'const B&' or 'const volatile B&' [...] + if (!BaseClassDecl->hasCopyConstructorWithConstParam()) + data().ImplicitCopyConstructorHasConstParam = false; + // A class has an Objective-C object member if... or any of its bases // has an Objective-C object member. if (BaseClassDecl->hasObjectMember()) setHasObjectMember(true); + + if (BaseClassDecl->hasVolatileMember()) + setHasVolatileMember(true); // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; + + if (BaseClassDecl->hasUninitializedReferenceMember()) + data().HasUninitializedReferenceMember = true; + + addedClassSubobject(BaseClassDecl); } if (VBases.empty()) @@ -296,8 +326,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Create base specifier for any direct or indirect virtual bases. data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); - for (int I = 0, E = VBases.size(); I != E; ++I) + for (int I = 0, E = VBases.size(); I != E; ++I) { + QualType Type = VBases[I]->getType(); + if (!Type->isDependentType()) + addedClassSubobject(Type->getAsCXXRecordDecl()); data().getVBases()[I] = *VBases[I]; + } +} + +void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { + // C++11 [class.copy]p11: + // A defaulted copy/move constructor for a class X is defined as + // deleted if X has: + // -- a direct or virtual base class B that cannot be copied/moved [...] + // -- a non-static data member of class type M (or array thereof) + // that cannot be copied or moved [...] + if (!Subobj->hasSimpleMoveConstructor()) + data().NeedOverloadResolutionForMoveConstructor = true; + + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined as + // deleted if X has: + // -- a direct or virtual base class B that cannot be copied/moved [...] + // -- a non-static data member of class type M (or array thereof) + // that cannot be copied or moved [...] + if (!Subobj->hasSimpleMoveAssignment()) + data().NeedOverloadResolutionForMoveAssignment = true; + + // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5: + // A defaulted [ctor or dtor] for a class X is defined as + // deleted if X has: + // -- any direct or virtual base class [...] has a type with a destructor + // that is deleted or inaccessible from the defaulted [ctor or dtor]. + // -- any non-static data member has a type with a destructor + // that is deleted or inaccessible from the defaulted [ctor or dtor]. + if (!Subobj->hasSimpleDestructor()) { + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForDestructor = true; + } } /// Callback function for CXXRecordDecl::forallBases that acknowledges @@ -313,161 +379,29 @@ bool CXXRecordDecl::hasAnyDependentBases() const { return !forallBases(SawBase, 0); } -bool CXXRecordDecl::hasConstCopyConstructor() const { - return getCopyConstructor(Qualifiers::Const) != 0; -} - bool CXXRecordDecl::isTriviallyCopyable() const { // C++0x [class]p5: // A trivially copyable class is a class that: // -- has no non-trivial copy constructors, - if (!hasTrivialCopyConstructor()) return false; + if (hasNonTrivialCopyConstructor()) return false; // -- has no non-trivial move constructors, - if (!hasTrivialMoveConstructor()) return false; + if (hasNonTrivialMoveConstructor()) return false; // -- has no non-trivial copy assignment operators, - if (!hasTrivialCopyAssignment()) return false; + if (hasNonTrivialCopyAssignment()) return false; // -- has no non-trivial move assignment operators, and - if (!hasTrivialMoveAssignment()) return false; + if (hasNonTrivialMoveAssignment()) return false; // -- has a trivial destructor. if (!hasTrivialDestructor()) return false; return true; } -/// \brief Perform a simplistic form of overload resolution that only considers -/// cv-qualifiers on a single parameter, and return the best overload candidate -/// (if there is one). -static CXXMethodDecl * -GetBestOverloadCandidateSimple( - const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { - if (Cands.empty()) - return 0; - if (Cands.size() == 1) - return Cands[0].first; - - unsigned Best = 0, N = Cands.size(); - for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) - Best = I; - - for (unsigned I = 0; I != N; ++I) - if (I != Best && Cands[Best].second.compatiblyIncludes(Cands[I].second)) - return 0; - - return Cands[Best].first; -} - -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{ - ASTContext &Context = getASTContext(); - QualType ClassType - = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType)); - unsigned FoundTQs; - SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // C++ [class.copy]p2: - // A non-template constructor for class X is a copy constructor if [...] - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isCopyConstructor(FoundTQs)) { - if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || - (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) - Found.push_back(std::make_pair( - const_cast<CXXConstructorDecl *>(Constructor), - Qualifiers::fromCVRMask(FoundTQs))); - } - } - - return cast_or_null<CXXConstructorDecl>( - GetBestOverloadCandidateSimple(Found)); -} - -CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const { - for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I) - if (I->isMoveConstructor()) - return *I; - - return 0; -} - -CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { - ASTContext &Context = getASTContext(); - QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); - DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - - 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: - // A user-declared copy assignment operator is a non-static non-template - // member function of class X with exactly one parameter of type X, X&, - // const X&, volatile X& or const volatile X&. - const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); - if (!Method || Method->isStatic() || Method->getPrimaryTemplate()) - continue; - - const FunctionProtoType *FnType - = Method->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Overloaded operator has no prototype."); - // Don't assert on this; an invalid decl might have been left in the AST. - if (FnType->getNumArgs() != 1 || FnType->isVariadic()) - continue; - - QualType ArgType = FnType->getArgType(0); - Qualifiers Quals; - if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) { - ArgType = Ref->getPointeeType(); - // If we have a const argument and we have a reference to a non-const, - // this function does not match. - if (ArgIsConst && !ArgType.isConstQualified()) - continue; - - Quals = ArgType.getQualifiers(); - } else { - // By-value copy-assignment operators are treated like const X& - // copy-assignment operators. - Quals = Qualifiers::fromCVRMask(Qualifiers::Const); - } - - if (!Context.hasSameUnqualifiedType(ArgType, Class)) - continue; - - // Save this copy-assignment operator. It might be "the one". - Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals)); - } - - // Use a simplistic form of overload resolution to find the candidate. - return GetBestOverloadCandidateSimple(Found); -} - -CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const { - for (method_iterator I = method_begin(), E = method_end(); I != E; ++I) - if (I->isMoveAssignmentOperator()) - return *I; - - return 0; -} - void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. data().Abstract = true; } -void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) { - if (!CD->isCopyOrMoveConstructor()) - data().HasConstexprNonCopyMoveConstructor = true; - - if (CD->isDefaultConstructor()) - data().HasConstexprDefaultConstructor = true; -} - void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa<FieldDecl>(D) && @@ -502,75 +436,41 @@ void CXXRecordDecl::addedMember(Decl *D) { // A class that declares or inherits a virtual function is called a // polymorphic class. data().Polymorphic = true; - - // C++0x [class.ctor]p5 - // A default constructor is trivial [...] if: - // -- its class has no virtual functions [...] - data().HasTrivialDefaultConstructor = false; - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if [...] + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor, copy/move constructor, or copy/move + // assignment operator for a class X] is trivial [...] if: // -- class X has no virtual functions [...] - data().HasTrivialCopyConstructor = false; - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= SMF_Destructor; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if [...] - // -- class X has no virtual functions [...] - data().HasTrivialCopyAssignment = false; - data().HasTrivialMoveAssignment = false; - // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no virtual functions data().IsStandardLayout = false; } } - - if (D->isImplicit()) { - // Notify that an implicit member was added after the definition - // was completed. - if (!isBeingDefined()) - if (ASTMutationListener *L = getASTMutationListener()) - L->AddedCXXImplicitMember(data().Definition, D); - - // If this is a special member function, note that it was added and then - // return early. - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (Constructor->isDefaultConstructor()) { - data().DeclaredDefaultConstructor = true; - if (Constructor->isConstexpr()) { - data().HasConstexprDefaultConstructor = true; - data().HasConstexprNonCopyMoveConstructor = true; - } - } else if (Constructor->isCopyConstructor()) { - data().DeclaredCopyConstructor = true; - } else if (Constructor->isMoveConstructor()) { - data().DeclaredMoveConstructor = true; - } else - goto NotASpecialMember; - return; - } else if (isa<CXXDestructorDecl>(D)) { - data().DeclaredDestructor = true; - return; - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - if (Method->isCopyAssignmentOperator()) - data().DeclaredCopyAssignment = true; - else if (Method->isMoveAssignmentOperator()) - data().DeclaredMoveAssignment = true; - else - goto NotASpecialMember; - return; - } -NotASpecialMember:; - // Any other implicit declarations are handled like normal declarations. - } - - // Handle (user-declared) constructors. + // Notify the listener if an implicit member was added after the definition + // was completed. + if (!isBeingDefined() && D->isImplicit()) + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXImplicitMember(data().Definition, D); + + // The kind of special member this declaration is, if any. + unsigned SMKind = 0; + + // Handle constructors. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - // Note that we have a user-declared constructor. - data().UserDeclaredConstructor = true; + if (!Constructor->isImplicit()) { + // Note that we have a user-declared constructor. + data().UserDeclaredConstructor = true; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + // Since the POD bit is meant to be C++03 POD-ness, clear it even if the + // type is technically an aggregate in C++0x since it wouldn't be in 03. + data().PlainOldData = false; + } // Technically, "user-provided" is only defined for special member // functions, but the intent of the standard is clearly that it should apply @@ -578,47 +478,29 @@ NotASpecialMember:; bool UserProvided = Constructor->isUserProvided(); if (Constructor->isDefaultConstructor()) { - data().DeclaredDefaultConstructor = true; - if (UserProvided) { - // C++0x [class.ctor]p5: - // A default constructor is trivial if it is not user-provided [...] - data().HasTrivialDefaultConstructor = false; + SMKind |= SMF_DefaultConstructor; + + if (UserProvided) data().UserProvidedDefaultConstructor = true; - } - if (Constructor->isConstexpr()) { + if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; - data().HasConstexprNonCopyMoveConstructor = true; - } } - // Note when we have a user-declared copy or move constructor, which will - // suppress the implicit declaration of those constructors. if (!FunTmpl) { - if (Constructor->isCopyConstructor()) { - data().UserDeclaredCopyConstructor = true; - data().DeclaredCopyConstructor = true; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is not - // user-provided [...] - if (UserProvided) - data().HasTrivialCopyConstructor = false; - } else if (Constructor->isMoveConstructor()) { - data().UserDeclaredMoveConstructor = true; - data().DeclaredMoveConstructor = true; - - // C++0x [class.copy]p13: - // A copy/move constructor for class X is trivial if it is not - // user-provided [...] - if (UserProvided) - data().HasTrivialMoveConstructor = false; - } + unsigned Quals; + if (Constructor->isCopyConstructor(Quals)) { + SMKind |= SMF_CopyConstructor; + + if (Quals & Qualifiers::Const) + data().HasDeclaredCopyConstructorWithConstParam = true; + } else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; } - if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) { - // Record if we see any constexpr constructors which are neither copy - // nor move constructors. + + // Record if we see any constexpr constructors which are neither copy + // nor move constructors. + if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) data().HasConstexprNonCopyMoveConstructor = true; - } // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-declared @@ -626,106 +508,99 @@ NotASpecialMember:; // C++0x [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. - if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided) + if (getASTContext().getLangOpts().CPlusPlus11 + ? UserProvided : !Constructor->isImplicit()) data().Aggregate = false; - - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - // Since the POD bit is meant to be C++03 POD-ness, clear it even if the - // type is technically an aggregate in C++0x since it wouldn't be in 03. - data().PlainOldData = false; - - return; } - // Handle (user-declared) destructors. + // Handle destructors. if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) { - data().DeclaredDestructor = true; - data().UserDeclaredDestructor = true; - data().HasIrrelevantDestructor = false; - - // C++ [class]p4: - // A POD-struct is an aggregate class that has [...] no user-defined - // destructor. - // This bit is the C++03 POD bit, not the 0x one. - data().PlainOldData = false; - - // C++11 [class.dtor]p5: - // A destructor is trivial if it is not user-provided and if - // -- the destructor is not virtual. - if (DD->isUserProvided() || DD->isVirtual()) - data().HasTrivialDestructor = false; + SMKind |= SMF_Destructor; - return; + if (!DD->isImplicit()) + data().HasIrrelevantDestructor = false; + + // C++11 [class.dtor]p5: + // A destructor is trivial if [...] the destructor is not virtual. + if (DD->isVirtual()) + data().HasTrivialSpecialMembers &= ~SMF_Destructor; } - - // Handle (user-declared) member functions. + + // Handle member functions. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { if (Method->isCopyAssignmentOperator()) { - // C++ [class]p4: - // A POD-struct is an aggregate class that [...] has no user-defined - // copy assignment operator [...]. - // This is the C++03 bit only. - data().PlainOldData = false; + SMKind |= SMF_CopyAssignment; - // This is a copy assignment operator. - - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = true; - - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted [...] - if (Method->isUserProvided()) - data().HasTrivialCopyAssignment = false; - - return; + const ReferenceType *ParamTy = + Method->getParamDecl(0)->getType()->getAs<ReferenceType>(); + if (!ParamTy || ParamTy->getPointeeType().isConstQualified()) + data().HasDeclaredCopyAssignmentWithConstParam = true; } - - if (Method->isMoveAssignmentOperator()) { - // This is an extension in C++03 mode, but we'll keep consistency by - // taking a move assignment operator to induce non-POD-ness - data().PlainOldData = false; - - // This is a move assignment operator. - data().UserDeclaredMoveAssignment = true; - data().DeclaredMoveAssignment = true; - // C++0x [class.copy]p27: - // A copy/move assignment operator for class X is trivial if it is - // neither user-provided nor deleted [...] - if (Method->isUserProvided()) - data().HasTrivialMoveAssignment = false; - } + if (Method->isMoveAssignmentOperator()) + SMKind |= SMF_MoveAssignment; // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { - // We don't record specializations. - if (Conversion->getPrimaryTemplate()) - return; - // FIXME: We intentionally don't use the decl's access here because it // hasn't been set yet. That's really just a misdesign in Sema. - - if (FunTmpl) { + if (Conversion->getPrimaryTemplate()) { + // We don't record specializations. + } else if (FunTmpl) { if (FunTmpl->getPreviousDecl()) data().Conversions.replace(FunTmpl->getPreviousDecl(), FunTmpl); else - data().Conversions.addDecl(FunTmpl); + data().Conversions.addDecl(getASTContext(), FunTmpl); } else { if (Conversion->getPreviousDecl()) data().Conversions.replace(Conversion->getPreviousDecl(), Conversion); else - data().Conversions.addDecl(Conversion); + data().Conversions.addDecl(getASTContext(), Conversion); } } - + + if (SMKind) { + // If this is the first declaration of a special member, we no longer have + // an implicit trivial special member. + data().HasTrivialSpecialMembers &= + data().DeclaredSpecialMembers | ~SMKind; + + if (!Method->isImplicit() && !Method->isUserProvided()) { + // This method is user-declared but not user-provided. We can't work out + // whether it's trivial yet (not until we get to the end of the class). + // We'll handle this method in finishedDefaultedOrDeletedMember. + } else if (Method->isTrivial()) + data().HasTrivialSpecialMembers |= SMKind; + else + data().DeclaredNonTrivialSpecialMembers |= SMKind; + + // Note when we have declared a declared special member, and suppress the + // implicit declaration of this special member. + data().DeclaredSpecialMembers |= SMKind; + + if (!Method->isImplicit()) { + data().UserDeclaredSpecialMembers |= SMKind; + + // C++03 [class]p4: + // A POD-struct is an aggregate class that has [...] no user-defined + // copy assignment operator and no user-defined destructor. + // + // Since the POD bit is meant to be C++03 POD-ness, and in C++03, + // aggregates could not have any constructors, clear it even for an + // explicitly defaulted or deleted constructor. + // type is technically an aggregate in C++0x since it wouldn't be in 03. + // + // Also, a user-declared move assignment operator makes a class non-POD. + // This is an extension in C++03. + data().PlainOldData = false; + } + } + return; } - + // Handle non-static data members. if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // C++ [class.bit]p2: @@ -785,7 +660,8 @@ NotASpecialMember:; data().PlainOldData = false; if (T->isReferenceType()) { - data().HasTrivialDefaultConstructor = false; + if (!Field->hasInClassInitializer()) + data().HasUninitializedReferenceMember = true; // C++0x [class]p7: // A standard-layout class is a class that: @@ -803,7 +679,7 @@ NotASpecialMember:; // C++11 [class]p5: // A default constructor is trivial if [...] no non-static data member // of its class has a brace-or-equal-initializer. - data().HasTrivialDefaultConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no @@ -815,16 +691,39 @@ NotASpecialMember:; data().PlainOldData = false; } + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined + // as deleted if X has: + // -- a non-static data member of reference type + if (T->isReferenceType()) + data().DefaultedMoveAssignmentIsDeleted = true; + if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { + addedClassSubobject(FieldRec); + + // C++11 [class.ctor]p5, C++11 [class.copy]p11: + // A defaulted [special member] for a class X is defined as + // deleted if: + // -- X is a union-like class that has a variant member with a + // non-trivial [corresponding special member] + if (isUnion()) { + if (FieldRec->hasNonTrivialMoveConstructor()) + data().DefaultedMoveConstructorIsDeleted = true; + if (FieldRec->hasNonTrivialMoveAssignment()) + data().DefaultedMoveAssignmentIsDeleted = true; + if (FieldRec->hasNonTrivialDestructor()) + data().DefaultedDestructorIsDeleted = true; + } + // C++0x [class.ctor]p5: // A default constructor is trivial [...] if: // -- for all the non-static data members of its class that are of // class type (or array thereof), each such class has a trivial // default constructor. if (!FieldRec->hasTrivialDefaultConstructor()) - data().HasTrivialDefaultConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] @@ -832,13 +731,13 @@ NotASpecialMember:; // -- for each non-static data member of X that is of class type (or // an array thereof), the constructor selected to copy/move that // member is trivial; - // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) - data().HasTrivialCopyConstructor = false; - if (!FieldRec->hasTrivialMoveConstructor() || - !(FieldRec->hasDeclaredMoveConstructor() || - FieldRec->needsImplicitMoveConstructor())) - data().HasTrivialMoveConstructor = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + // If the field doesn't have a simple move constructor, we'll eagerly + // declare the move constructor for this class and we'll decide whether + // it's trivial then. + if (!FieldRec->hasTrivialMoveConstructor()) + data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] @@ -846,20 +745,22 @@ NotASpecialMember:; // -- for each non-static data member of X that is of class type (or // an array thereof), the assignment operator selected to // copy/move that member is trivial; - // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) - data().HasTrivialCopyAssignment = false; - if (!FieldRec->hasTrivialMoveAssignment() || - !(FieldRec->hasDeclaredMoveAssignment() || - FieldRec->needsImplicitMoveAssignment())) - data().HasTrivialMoveAssignment = false; + data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; + // If the field doesn't have a simple move assignment, we'll eagerly + // declare the move assignment for this class and we'll decide whether + // it's trivial then. + if (!FieldRec->hasTrivialMoveAssignment()) + data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; if (!FieldRec->hasTrivialDestructor()) - data().HasTrivialDestructor = false; + data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!FieldRec->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) setHasObjectMember(true); + if (FieldRec->hasVolatileMember()) + setHasVolatileMember(true); // C++0x [class]p7: // A standard-layout class is a class that: @@ -910,12 +811,42 @@ NotASpecialMember:; // The standard requires any in-class initializer to be a constant // expression. We consider this to be a defect. data().DefaultedDefaultConstructorIsConstexpr = false; + + // C++11 [class.copy]p8: + // The implicitly-declared copy constructor for a class X will have + // the form 'X::X(const X&)' if [...] for all the non-static data + // members of X that are of a class type M (or array thereof), each + // such class type has a copy constructor whose first parameter is + // of type 'const M&' or 'const volatile M&'. + if (!FieldRec->hasCopyConstructorWithConstParam()) + data().ImplicitCopyConstructorHasConstParam = false; + + // C++11 [class.copy]p18: + // The implicitly-declared copy assignment oeprator for a class X will + // have the form 'X& X::operator=(const X&)' if [...] for all the + // non-static data members of X that are of a class type M (or array + // thereof), each such class type has a copy assignment operator whose + // parameter is of type 'const M&', 'const volatile M&' or 'M'. + if (!FieldRec->hasCopyAssignmentWithConstParam()) + data().ImplicitCopyAssignmentHasConstParam = false; + + if (FieldRec->hasUninitializedReferenceMember() && + !Field->hasInClassInitializer()) + data().HasUninitializedReferenceMember = true; } } else { // Base element type of field is a non-class type. if (!T->isLiteralType() || (!Field->hasInClassInitializer() && !isUnion())) data().DefaultedDefaultConstructorIsConstexpr = false; + + // C++11 [class.copy]p23: + // A defaulted copy/move assignment operator for a class X is defined + // as deleted if X has: + // -- a non-static data member of const non-class type (or array + // thereof) + if (T.isConstQualified()) + data().DefaultedMoveAssignmentIsDeleted = true; } // C++0x [class]p7: @@ -943,7 +874,41 @@ NotASpecialMember:; if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) if (Shadow->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) - data().Conversions.addDecl(Shadow, Shadow->getAccess()); + data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess()); +} + +void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { + assert(!D->isImplicit() && !D->isUserProvided()); + + // The kind of special member this declaration is, if any. + unsigned SMKind = 0; + + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + if (Constructor->isDefaultConstructor()) { + SMKind |= SMF_DefaultConstructor; + if (Constructor->isConstexpr()) + data().HasConstexprDefaultConstructor = true; + } + if (Constructor->isCopyConstructor()) + SMKind |= SMF_CopyConstructor; + else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; + else if (Constructor->isConstexpr()) + // We may now know that the constructor is constexpr. + data().HasConstexprNonCopyMoveConstructor = true; + } else if (isa<CXXDestructorDecl>(D)) + SMKind |= SMF_Destructor; + else if (D->isCopyAssignmentOperator()) + SMKind |= SMF_CopyAssignment; + else if (D->isMoveAssignmentOperator()) + SMKind |= SMF_MoveAssignment; + + // Update which trivial / non-trivial special members we have. + // addedMember will have skipped this step for this member. + if (D->isTrivial()) + data().HasTrivialSpecialMembers |= SMKind; + else + data().DeclaredNonTrivialSpecialMembers |= SMKind; } bool CXXRecordDecl::isCLike() const { @@ -1004,7 +969,7 @@ static void CollectVisibleConversions(ASTContext &Context, bool InVirtual, AccessSpecifier Access, const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, - UnresolvedSetImpl &Output, + ASTUnresolvedSet &Output, UnresolvedSetImpl &VOutput, llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { // The set of types which have conversions in this class or its @@ -1015,12 +980,13 @@ static void CollectVisibleConversions(ASTContext &Context, // Collect the direct conversions and figure out which conversions // will be hidden in the subclasses. - UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); - if (!Cs.empty()) { + CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin(); + CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end(); + if (ConvI != ConvE) { HiddenTypesBuffer = ParentHiddenTypes; HiddenTypes = &HiddenTypesBuffer; - for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) { + for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) { CanQualType ConvType(GetConversionType(Context, I.getDecl())); bool Hidden = ParentHiddenTypes.count(ConvType); if (!Hidden) @@ -1039,7 +1005,7 @@ static void CollectVisibleConversions(ASTContext &Context, if (InVirtual) VOutput.addDecl(I.getDecl(), IAccess); else - Output.addDecl(I.getDecl(), IAccess); + Output.addDecl(Context, I.getDecl(), IAccess); } } } @@ -1066,7 +1032,7 @@ static void CollectVisibleConversions(ASTContext &Context, /// bases. It might be worth special-casing that, really. static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, - UnresolvedSetImpl &Output) { + ASTUnresolvedSet &Output) { // The collection of all conversions in virtual bases that we've // found. These will be added to the output as long as they don't // appear in the hidden-conversions set. @@ -1081,10 +1047,11 @@ static void CollectVisibleConversions(ASTContext &Context, // Go ahead and collect the direct conversions and add them to the // hidden-types set. - UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); - Output.append(Cs.begin(), Cs.end()); - for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) - HiddenTypes.insert(GetConversionType(Context, I.getDecl())); + CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin(); + CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end(); + Output.append(Context, ConvI, ConvE); + for (; ConvI != ConvE; ++ConvI) + HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl())); // Recursively collect conversions from base classes. for (CXXRecordDecl::base_class_iterator @@ -1101,22 +1068,24 @@ static void CollectVisibleConversions(ASTContext &Context, for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end(); I != E; ++I) { if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()))) - Output.addDecl(I.getDecl(), I.getAccess()); + Output.addDecl(Context, I.getDecl(), I.getAccess()); } } /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { +std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator> +CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) - return &data().Conversions; + return std::make_pair(data().Conversions.begin(), data().Conversions.end()); // If visible conversion list is already evaluated, return it. - if (data().ComputedVisibleConversions) - return &data().VisibleConversions; - CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); - data().ComputedVisibleConversions = true; - return &data().VisibleConversions; + if (!data().ComputedVisibleConversions) { + CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); + data().ComputedVisibleConversions = true; + } + return std::make_pair(data().VisibleConversions.begin(), + data().VisibleConversions.end()); } void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { @@ -1131,7 +1100,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { // with sufficiently large numbers of directly-declared conversions // that asymptotic behavior matters. - UnresolvedSetImpl &Convs = *getConversionFunctions(); + ASTUnresolvedSet &Convs = data().Conversions; for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); @@ -1151,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { return 0; } -MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { - return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>(); -} - void CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, TemplateSpecializationKind TSK) { @@ -1200,12 +1165,11 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); - DeclContext::lookup_const_iterator I, E; - llvm::tie(I, E) = lookup(Name); - if (I == E) + DeclContext::lookup_const_result R = lookup(Name); + if (R.empty()) return 0; - CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); + CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front()); return Dtor; } @@ -1225,12 +1189,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { // non-trivial. struct DefinitionData &Data = data(); Data.PlainOldData = false; - Data.HasTrivialDefaultConstructor = false; - Data.HasTrivialCopyConstructor = false; - Data.HasTrivialMoveConstructor = false; - Data.HasTrivialCopyAssignment = false; - Data.HasTrivialMoveAssignment = false; - Data.HasTrivialDestructor = false; + Data.HasTrivialSpecialMembers = 0; Data.HasIrrelevantDestructor = false; } @@ -1270,7 +1229,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { for (UnresolvedSetIterator I = data().Conversions.begin(), E = data().Conversions.end(); I != E; ++I) - data().Conversions.setAccess(I, (*I)->getAccess()); + I.setAccess((*I)->getAccess()); } bool CXXRecordDecl::mayBeAbstract() const { @@ -1292,6 +1251,42 @@ bool CXXRecordDecl::mayBeAbstract() const { void CXXMethodDecl::anchor() { } +bool CXXMethodDecl::isStatic() const { + const CXXMethodDecl *MD = this; + for (;;) { + const CXXMethodDecl *C = MD->getCanonicalDecl(); + if (C != MD) { + MD = C; + continue; + } + + FunctionTemplateSpecializationInfo *Info = + MD->getTemplateSpecializationInfo(); + if (!Info) + break; + MD = cast<CXXMethodDecl>(Info->getTemplate()->getTemplatedDecl()); + } + + if (MD->getStorageClass() == SC_Static) + return true; + + DeclarationName Name = getDeclName(); + // [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) + return 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) + return true; + + return false; +} + static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), @@ -1324,7 +1319,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, } lookup_const_result Candidates = RD->lookup(getDeclName()); - for (NamedDecl * const * I = Candidates.first; I != Candidates.second; ++I) { + for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) { CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I); if (!MD) continue; @@ -1353,10 +1348,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic, StorageClass SCAsWritten, bool isInline, + StorageClass SC, bool isInline, bool isConstexpr, SourceLocation EndLocation) { return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, - isStatic, SCAsWritten, isInline, isConstexpr, + SC, isInline, isConstexpr, EndLocation); } @@ -1364,7 +1359,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl)); return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(), DeclarationNameInfo(), QualType(), - 0, false, SC_None, false, false, + 0, SC_None, false, false, SourceLocation()); } @@ -1399,9 +1394,10 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { // This function is a usual deallocation function if there are no // single-parameter deallocation functions of the same kind. - for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); - R.first != R.second; ++R.first) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first)) + DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); + for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end(); + I != E; ++I) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) if (FD->getNumParams() == 1) return false; } diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 553d170fc3d5..37a812e71aae 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -27,7 +27,8 @@ FriendDecl *FriendDecl::getNextFriendSlowCase() { FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend, - SourceLocation FriendL) { + SourceLocation FriendL, + ArrayRef<TemplateParameterList*> FriendTypeTPLists) { #ifndef NDEBUG if (Friend.is<NamedDecl*>()) { NamedDecl *D = Friend.get<NamedDecl*>(); @@ -40,15 +41,25 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, // to the original declaration when instantiating members. assert(D->getFriendObjectKind() || (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); + // These template parameters are for friend types only. + assert(FriendTypeTPLists.size() == 0); } #endif - FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL); + std::size_t Size = sizeof(FriendDecl) + + FriendTypeTPLists.size() * sizeof(TemplateParameterList*); + void *Mem = C.Allocate(Size); + FriendDecl *FD = new (Mem) FriendDecl(DC, L, Friend, FriendL, + FriendTypeTPLists); cast<CXXRecordDecl>(DC)->pushFriendDecl(FD); return FD; } -FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendDecl)); - return new (Mem) FriendDecl(EmptyShell()); +FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned FriendTypeNumTPLists) { + std::size_t Size = sizeof(FriendDecl) + + FriendTypeNumTPLists * sizeof(TemplateParameterList*); + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists); } + diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index 036acc2d77a5..9861f2278f9a 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclGroup.h" -#include "clang/AST/Decl.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "llvm/Support/Allocator.h" using namespace clang; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 65a987836ff8..5f5ba52947d6 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -13,8 +13,9 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/Stmt.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Stmt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -53,8 +54,9 @@ void ObjCContainerDecl::anchor() { } /// ObjCIvarDecl * ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { - lookup_const_iterator Ivar, IvarEnd; - for (llvm::tie(Ivar, IvarEnd) = lookup(Id); Ivar != IvarEnd; ++Ivar) { + lookup_const_result R = lookup(Id); + for (lookup_const_iterator Ivar = R.begin(), IvarEnd = R.end(); + Ivar != IvarEnd; ++Ivar) { if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) return ivar; } @@ -63,7 +65,16 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { // Get the local instance/class method declared in this interface. ObjCMethodDecl * -ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { +ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, + bool AllowHidden) const { + // If this context is a hidden protocol definition, don't find any + // methods there. + if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { + if (const ObjCProtocolDecl *Def = Proto->getDefinition()) + if (Def->isHidden() && !AllowHidden) + return 0; + } + // Since instance & class methods can have the same name, the loop below // ensures we get the correct method. // @@ -72,8 +83,9 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { // + (float) class_method; // @end // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) { + lookup_const_result R = lookup(Sel); + for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); + Meth != MethEnd; ++Meth) { ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); if (MD && MD->isInstanceMethod() == isInstance) return MD; @@ -81,13 +93,86 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { return 0; } +/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter +/// method was found in the class, its protocols, its super classes or categories. +/// It also returns 'true' if one of its categories has declared a 'readwrite' property. +/// This is because, user must provide a setter method for the category's 'readwrite' +/// property. +bool +ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const { + Selector Sel = Property->getSetterName(); + lookup_const_result R = lookup(Sel); + for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() && !MD->isImplicit()) + return true; + } + + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) { + // Also look into categories, including class extensions, looking + // for a user declared instance method. + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ID->visible_categories_begin(), + CatEnd = ID->visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel)) + if (!MD->isImplicit()) + return true; + if (Cat->IsClassExtension()) + continue; + // Also search through the categories looking for a 'readwrite' declaration + // of this property. If one found, presumably a setter will be provided + // (properties declared in categories will not get auto-synthesized). + for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(), + E = Cat->prop_end(); P != E; ++P) + if (P->getIdentifier() == Property->getIdentifier()) { + if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) + return true; + break; + } + } + + // Also look into protocols, for a user declared instance method. + for (ObjCInterfaceDecl::all_protocol_iterator P = + ID->all_referenced_protocol_begin(), + PE = ID->all_referenced_protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + if (Proto->HasUserDeclaredSetterMethod(Property)) + return true; + } + // And in its super class. + ObjCInterfaceDecl *OSC = ID->getSuperClass(); + while (OSC) { + if (OSC->HasUserDeclaredSetterMethod(Property)) + return true; + OSC = OSC->getSuperClass(); + } + } + if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this)) + for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(), + E = PD->protocol_end(); PI != E; ++PI) { + if ((*PI)->HasUserDeclaredSetterMethod(Property)) + return true; + } + return false; +} + ObjCPropertyDecl * ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, IdentifierInfo *propertyID) { + // If this context is a hidden protocol definition, don't find any + // property. + if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) { + if (const ObjCProtocolDecl *Def = Proto->getDefinition()) + if (Def->isHidden()) + return 0; + } - DeclContext::lookup_const_iterator I, E; - llvm::tie(I, E) = DC->lookup(propertyID); - for ( ; I != E; ++I) + DeclContext::lookup_const_result R = DC->lookup(propertyID); + for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E; + ++I) if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) return PD; @@ -108,6 +193,12 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { /// in 'PropertyId' and returns it. It returns 0, if not found. ObjCPropertyDecl * ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { + // Don't find properties within hidden protocol definitions. + if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { + if (const ObjCProtocolDecl *Def = Proto->getDefinition()) + if (Def->isHidden()) + return 0; + } if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) @@ -126,12 +217,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { } case Decl::ObjCInterface: { const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this); - // Look through categories. - for (ObjCCategoryDecl *Cat = OID->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory()) + // Look through categories (but not extensions). + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = OID->visible_categories_begin(), + CatEnd = OID->visible_categories_end(); + Cat != CatEnd; ++Cat) { if (!Cat->IsClassExtension()) if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId)) return P; + } // Look through protocols. for (ObjCInterfaceDecl::all_protocol_iterator @@ -190,21 +284,43 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( return 0; } -void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const { +void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM, + PropertyDeclOrder &PO) const { for (ObjCContainerDecl::prop_iterator P = prop_begin(), E = prop_end(); P != E; ++P) { ObjCPropertyDecl *Prop = *P; PM[Prop->getIdentifier()] = Prop; + PO.push_back(Prop); } for (ObjCInterfaceDecl::all_protocol_iterator PI = all_referenced_protocol_begin(), E = all_referenced_protocol_end(); PI != E; ++PI) - (*PI)->collectPropertiesToImplement(PM); + (*PI)->collectPropertiesToImplement(PM, PO); // Note, the properties declared only in class extensions are still copied // into the main @interface's property list, and therefore we don't // explicitly, have to search class extension properties. } +bool ObjCInterfaceDecl::isArcWeakrefUnavailable() const { + const ObjCInterfaceDecl *Class = this; + while (Class) { + if (Class->hasAttr<ArcWeakrefUnavailableAttr>()) + return true; + Class = Class->getSuperClass(); + } + return false; +} + +const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const { + const ObjCInterfaceDecl *Class = this; + while (Class) { + if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>()) + return Class; + Class = Class->getSuperClass(); + } + return 0; +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) @@ -254,8 +370,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( void ObjCInterfaceDecl::allocateDefinitionData() { assert(!hasDefinition() && "ObjC class already has a definition"); - Data = new (getASTContext()) DefinitionData(); - Data->Definition = this; + Data.setPointer(new (getASTContext()) DefinitionData()); + Data.getPointer()->Definition = this; // Make the type point at the definition, now that we have one. if (TypeForDecl) @@ -273,24 +389,6 @@ void ObjCInterfaceDecl::startDefinition() { } } -/// getFirstClassExtension - Find first class extension of the given class. -ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const { - for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->IsClassExtension()) - return CDecl; - return 0; -} - -/// getNextClassCategory - Find next class extension in list of categories. -const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const { - for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->IsClassExtension()) - return CDecl; - return 0; -} - ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { // FIXME: Should make sure no callers ever do this. @@ -306,9 +404,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, clsDeclared = ClassDecl; return I; } - for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); - CDecl; CDecl = CDecl->getNextClassExtension()) { - if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { + + for (ObjCInterfaceDecl::visible_extensions_iterator + Ext = ClassDecl->visible_extensions_begin(), + ExtEnd = ClassDecl->visible_extensions_end(); + Ext != ExtEnd; ++Ext) { + if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) { clsDeclared = ClassDecl; return I; } @@ -367,21 +468,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, return MethodDecl; // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getMethod(Sel, isInstance))) + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = ClassDecl->visible_categories_begin(), + CatEnd = ClassDecl->visible_categories_end(); + Cat != CatEnd; ++Cat) { + if ((MethodDecl = Cat->getMethod(Sel, isInstance))) return MethodDecl; if (!shallowCategoryLookup) { // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = - CatDecl->getReferencedProtocols(); + Cat->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; } - CatDecl = CatDecl->getNextClassCategory(); } ClassDecl = ClassDecl->getSuperClass(); @@ -753,7 +855,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, if (MovedToSuper) if (ObjCMethodDecl * Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) if (Method != Overridden) { // We found an override at this category; there is no need to look // into its protocols. @@ -771,7 +874,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, // Check whether we have a matching method at this level. if (const ObjCMethodDecl * Overridden = Container->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) if (Method != Overridden) { // We found an override at this level; there is no need to look // into other protocols or categories. @@ -793,10 +897,13 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, P != PEnd; ++P) CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); - for (const ObjCCategoryDecl *Category = Interface->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - CollectOverriddenMethodsRecurse(Category, Method, Methods, + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Interface->known_categories_begin(), + CatEnd = Interface->known_categories_end(); + Cat != CatEnd; ++Cat) { + CollectOverriddenMethodsRecurse(*Cat, Method, Methods, MovedToSuper); + } if (const ObjCInterfaceDecl *Super = Interface->getSuperClass()) return CollectOverriddenMethodsRecurse(Super, Method, Methods, @@ -827,7 +934,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, // Start searching for overridden methods using the method from the // interface as starting point. if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) Method = IFaceMeth; CollectOverriddenMethods(ID, Method, overridden); @@ -839,7 +947,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, // Start searching for overridden methods using the method from the // interface as starting point. if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), - Method->isInstanceMethod())) + Method->isInstanceMethod(), + /*AllowHidden=*/true)) Method = IFaceMeth; CollectOverriddenMethods(ID, Method, overridden); @@ -858,11 +967,14 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc, if (!Class) return; - for (const ObjCCategoryDecl *Category = Class->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) - CollectOverriddenMethodsRecurse(Category, Method, Methods, true); - + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Class->known_categories_begin(), + CatEnd = Class->known_categories_end(); + Cat != CatEnd; ++Cat) { + if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation())) + CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true); + } + collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, Method, Methods); } @@ -924,6 +1036,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { if (isPropertyAccessor()) { const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent()); + // If container is class extension, find its primary class. + if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(Container)) + if (CatDecl->IsClassExtension()) + Container = CatDecl->getClassInterface(); + bool IsGetter = (NumArgs == 0); for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(), @@ -967,6 +1084,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, bool isInternal){ ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, PrevDecl, isInternal); + Result->Data.setInt(!C.getLangOpts().Modules); C.getObjCInterfaceType(Result, PrevDecl); return Result; } @@ -974,8 +1092,11 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl)); - return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(), - 0, false); + ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(), + 0, SourceLocation(), + 0, false); + Result->Data.setInt(!C.getLangOpts().Modules); + return Result; } ObjCInterfaceDecl:: @@ -1026,49 +1147,96 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { getASTContext().setObjCImplementation(getDefinition(), ImplD); } +namespace { + struct SynthesizeIvarChunk { + uint64_t Size; + ObjCIvarDecl *Ivar; + SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar) + : Size(size), Ivar(ivar) {} + }; + + bool operator<(const SynthesizeIvarChunk & LHS, + const SynthesizeIvarChunk &RHS) { + return LHS.Size < RHS.Size; + } +} + /// all_declared_ivar_begin - return first ivar declared in this class, /// its extensions and its implementation. Lazily build the list on first /// access. +/// +/// Caveat: The list returned by this method reflects the current +/// state of the parser. The cache will be updated for every ivar +/// added by an extension or the implementation when they are +/// encountered. +/// See also ObjCIvarDecl::Create(). ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; - if (data().IvarList) - return data().IvarList; - ObjCIvarDecl *curIvar = 0; - if (!ivar_empty()) { - ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end(); - data().IvarList = *I; ++I; - for (curIvar = data().IvarList; I != E; curIvar = *I, ++I) - curIvar->setNextIvar(*I); - } - - for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) { - if (!CDecl->ivar_empty()) { - ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); - if (!data().IvarList) { - data().IvarList = *I; ++I; - curIvar = data().IvarList; - } - for ( ;I != E; curIvar = *I, ++I) + if (!data().IvarList) { + if (!ivar_empty()) { + ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end(); + data().IvarList = *I; ++I; + for (curIvar = data().IvarList; I != E; curIvar = *I, ++I) curIvar->setNextIvar(*I); } + + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = known_extensions_begin(), + ExtEnd = known_extensions_end(); + Ext != ExtEnd; ++Ext) { + if (!Ext->ivar_empty()) { + ObjCCategoryDecl::ivar_iterator + I = Ext->ivar_begin(), + E = Ext->ivar_end(); + if (!data().IvarList) { + data().IvarList = *I; ++I; + curIvar = data().IvarList; + } + for ( ;I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + } + data().IvarListMissingImplementation = true; } + + // cached and complete! + if (!data().IvarListMissingImplementation) + return data().IvarList; if (ObjCImplementationDecl *ImplDecl = getImplementation()) { + data().IvarListMissingImplementation = false; if (!ImplDecl->ivar_empty()) { - ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); - if (!data().IvarList) { - data().IvarList = *I; ++I; - curIvar = data().IvarList; + SmallVector<SynthesizeIvarChunk, 16> layout; + for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), + E = ImplDecl->ivar_end(); I != E; ++I) { + ObjCIvarDecl *IV = *I; + if (IV->getSynthesize() && !IV->isInvalidDecl()) { + layout.push_back(SynthesizeIvarChunk( + IV->getASTContext().getTypeSize(IV->getType()), IV)); + continue; + } + if (!data().IvarList) + data().IvarList = *I; + else + curIvar->setNextIvar(*I); + curIvar = *I; + } + + if (!layout.empty()) { + // Order synthesized ivars by their size. + std::stable_sort(layout.begin(), layout.end()); + unsigned Ix = 0, EIx = layout.size(); + if (!data().IvarList) { + data().IvarList = layout[0].Ivar; Ix++; + curIvar = data().IvarList; + } + for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++) + curIvar->setNextIvar(layout[Ix].Ivar); } - for ( ;I != E; curIvar = *I, ++I) - curIvar->setNextIvar(*I); } } return data().IvarList; @@ -1087,29 +1255,41 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { if (data().ExternallyCompleted) LoadExternalDefinition(); - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (Category->getIdentifier() == CategoryId) - return Category; + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (Cat->getIdentifier() == CategoryId) + return *Cat; + } + return 0; } ObjCMethodDecl * ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const { - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCCategoryImplDecl *Impl = Cat->getImplementation()) if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel)) return MD; + } + return 0; } ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const { - for (ObjCCategoryDecl *Category = getCategoryList(); - Category; Category = Category->getNextClassCategory()) - if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + if (ObjCCategoryImplDecl *Impl = Cat->getImplementation()) if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel)) return MD; + } + return 0; } @@ -1141,10 +1321,13 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, // 2nd, look up the category. if (lookupCategory) - for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) { - for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), - E = CDecl->protocol_end(); PI != E; ++PI) + for (visible_categories_iterator Cat = visible_categories_begin(), + CatEnd = visible_categories_end(); + Cat != CatEnd; + ++Cat) { + for (ObjCCategoryDecl::protocol_iterator PI = Cat->protocol_begin(), + E = Cat->protocol_end(); + PI != E; ++PI) if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) return true; } @@ -1274,15 +1457,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, ObjCProtocolDecl *PrevDecl) { ObjCProtocolDecl *Result = new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl); - + Result->Data.setInt(!C.getLangOpts().Modules); return Result; } ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl)); - return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(), - 0); + ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), + SourceLocation(), 0); + Result->Data.setInt(!C.getLangOpts().Modules); + return Result; } ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { @@ -1304,6 +1489,12 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, bool isInstance) const { ObjCMethodDecl *MethodDecl = NULL; + // If there is no definition or the definition is hidden, we don't find + // anything. + const ObjCProtocolDecl *Def = getDefinition(); + if (!Def || Def->isHidden()) + return NULL; + if ((MethodDecl = getMethod(Sel, isInstance))) return MethodDecl; @@ -1314,9 +1505,9 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, } void ObjCProtocolDecl::allocateDefinitionData() { - assert(!Data && "Protocol already has a definition!"); - Data = new (getASTContext()) DefinitionData; - Data->Definition = this; + assert(!Data.getPointer() && "Protocol already has a definition!"); + Data.setPointer(new (getASTContext()) DefinitionData); + Data.getPointer()->Definition = this; } void ObjCProtocolDecl::startDefinition() { @@ -1328,17 +1519,22 @@ void ObjCProtocolDecl::startDefinition() { RD->Data = this->Data; } -void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const { - for (ObjCProtocolDecl::prop_iterator P = prop_begin(), - E = prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = *P; - // Insert into PM if not there already. - PM.insert(std::make_pair(Prop->getIdentifier(), Prop)); +void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM, + PropertyDeclOrder &PO) const { + + if (const ObjCProtocolDecl *PDecl = getDefinition()) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + // Insert into PM if not there already. + PM.insert(std::make_pair(Prop->getIdentifier(), Prop)); + PO.push_back(Prop); + } + // Scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + (*PI)->collectPropertiesToImplement(PM, PO); } - // Scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(), - E = protocol_end(); PI != E; ++PI) - (*PI)->collectPropertiesToImplement(PM); } @@ -1362,9 +1558,9 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, IvarLBraceLoc, IvarRBraceLoc); if (IDecl) { // Link this category into its class's category list. - CatDecl->NextClassCategory = IDecl->getCategoryList(); + CatDecl->NextClassCategory = IDecl->getCategoryListRaw(); if (IDecl->hasDefinition()) { - IDecl->setCategoryList(CatDecl); + IDecl->setCategoryListRaw(CatDecl); if (ASTMutationListener *L = C.getASTMutationListener()) L->AddedObjCCategoryToInterface(CatDecl, IDecl); } @@ -1450,7 +1646,7 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { } /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of -/// properties implemented in this category \@implementation block and returns +/// properties implemented in this \@implementation block and returns /// the implemented property that uses it. /// ObjCPropertyImplDecl *ObjCImplDecl:: diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp new file mode 100644 index 000000000000..c0d10a0f418c --- /dev/null +++ b/lib/AST/DeclOpenMP.cpp @@ -0,0 +1,60 @@ +//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements OMPThreadPrivateDecl class. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// OMPThreadPrivateDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPThreadPrivateDecl::anchor() { } + +OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + ArrayRef<DeclRefExpr *> VL) { + unsigned Size = sizeof(OMPThreadPrivateDecl) + + (VL.size() * sizeof(DeclRefExpr *)); + + void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); + OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, + DC, L); + D->NumVars = VL.size(); + D->setVars(VL); + return D; +} + +OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned N) { + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + + void *Mem = AllocateDeserializedDecl(C, ID, Size); + OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, + 0, SourceLocation()); + D->NumVars = N; + return D; +} + +void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + std::copy(VL.begin(), VL.end(), Vars); +} diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 386ad66c9917..c3bf8f89b297 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -7,15 +7,16 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Decl::dump method, which pretty print the +// This file implements the Decl::print method, which pretty prints the // AST back out to C/Objective-C/C++/Objective-C++ code. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" @@ -50,7 +51,9 @@ namespace { void VisitEnumDecl(EnumDecl *D); void VisitRecordDecl(RecordDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); + void VisitEmptyDecl(EmptyDecl *D); void VisitFunctionDecl(FunctionDecl *D); + void VisitFriendDecl(FriendDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitLabelDecl(LabelDecl *D); @@ -79,9 +82,10 @@ namespace { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, - const TemplateArgumentList *Args); + const TemplateArgumentList *Args = 0); void prettyPrintAttributes(Decl *D); }; } @@ -174,16 +178,6 @@ void DeclContext::dumpDeclContext() const { Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); } -void Decl::dump() const { - dump(llvm::errs()); -} - -void Decl::dump(raw_ostream &Out) const { - PrintingPolicy Policy = getASTContext().getPrintingPolicy(); - Policy.DumpSourceManager = &getASTContext().getSourceManager(); - print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true); -} - raw_ostream& DeclPrinter::Indent(unsigned Indentation) { for (unsigned i = 0; i != Indentation; ++i) Out << " "; @@ -191,7 +185,7 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { } void DeclPrinter::prettyPrintAttributes(Decl *D) { - if (Policy.SuppressAttributes) + if (Policy.PolishForDeclaration) return; if (D->hasAttrs()) { @@ -240,18 +234,18 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (isa<ObjCIvarDecl>(*D)) continue; - if (!Policy.DumpSourceManager) { - // Skip over implicit declarations in pretty-printing mode. - if (D->isImplicit()) continue; - // FIXME: Ugly hack so we don't pretty-print the builtin declaration - // of __builtin_va_list or __[u]int128_t. There should be some other way - // to check that. - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { - if (IdentifierInfo *II = ND->getIdentifier()) { - if (II->isStr("__builtin_va_list") || - II->isStr("__int128_t") || II->isStr("__uint128_t")) - continue; - } + // Skip over implicit declarations in pretty-printing mode. + if (D->isImplicit()) + continue; + + // FIXME: Ugly hack so we don't pretty-print the builtin declaration + // of __builtin_va_list or __[u]int128_t. There should be some other way + // to check that. + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { + if (IdentifierInfo *II = ND->getIdentifier()) { + if (II->isStr("__builtin_va_list") || + II->isStr("__int128_t") || II->isStr("__uint128_t")) + continue; } } @@ -298,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = 0; - if (isa<FunctionDecl>(*D) && - cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) + if (isa<OMPThreadPrivateDecl>(*D)) + Terminator = 0; + else if (isa<FunctionDecl>(*D) && + cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) Terminator = 0; else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) Terminator = 0; @@ -395,8 +391,9 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { } void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { + CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D); if (!Policy.SuppressSpecifiers) { - switch (D->getStorageClassAsWritten()) { + switch (D->getStorageClass()) { case SC_None: break; case SC_Extern: Out << "extern "; break; case SC_Static: Out << "static "; break; @@ -408,6 +405,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->isInlineSpecified()) Out << "inline "; if (D->isVirtualAsWritten()) Out << "virtual "; if (D->isModulePrivate()) Out << "__module_private__ "; + if (CDecl && CDecl->isExplicitSpecified()) + Out << "explicit "; } PrintingPolicy SubPolicy(Policy); @@ -483,7 +482,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } - if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { + if (CDecl) { bool HasInitializerList = false; for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), E = CDecl->init_end(); @@ -545,9 +544,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Out << ")"; } - } - else + if (!Proto.empty()) + Out << Proto; + } else { + if (FT && FT->hasTrailingReturn()) { + Out << "auto " << Proto << " -> "; + Proto.clear(); + } AFT->getResultType().print(Out, Policy, Proto); + } } else { Ty.print(Out, Policy, Proto); } @@ -558,6 +563,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << " = 0"; else if (D->isDeletedAsWritten()) Out << " = delete"; + else if (D->isExplicitlyDefaulted()) + Out << " = default"; else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) { if (!D->hasPrototype() && D->getNumParams()) { // This is a K&R function definition, so we need to print the @@ -579,6 +586,31 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } +void DeclPrinter::VisitFriendDecl(FriendDecl *D) { + if (TypeSourceInfo *TSI = D->getFriendType()) { + unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists(); + for (unsigned i = 0; i < NumTPLists; ++i) + PrintTemplateParameters(D->getFriendTypeTemplateParameterList(i)); + Out << "friend "; + Out << " " << TSI->getType().getAsString(Policy); + } + else if (FunctionDecl *FD = + dyn_cast<FunctionDecl>(D->getFriendDecl())) { + Out << "friend "; + VisitFunctionDecl(FD); + } + else if (FunctionTemplateDecl *FTD = + dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) { + Out << "friend "; + VisitFunctionTemplateDecl(FTD); + } + else if (ClassTemplateDecl *CTD = + dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) { + Out << "friend "; + VisitRedeclarableTemplateDecl(CTD); + } +} + void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (!Policy.SuppressSpecifiers && D->isMutable()) Out << "mutable "; @@ -609,9 +641,9 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { - StorageClass SCAsWritten = D->getStorageClassAsWritten(); - if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None) - Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " "; + StorageClass SC = D->getStorageClass(); + if (!Policy.SuppressSpecifiers && SC != SC_None) + Out << VarDecl::getStorageClassSpecifierString(SC) << " "; if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) Out << "__thread "; @@ -625,9 +657,14 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; - if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) - ImplicitInit = D->getInitStyle() == VarDecl::CallInit && - Construct->getNumArgs() == 0 && !Construct->isListInitialization(); + if (CXXConstructExpr *Construct = + dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) { + if (D->getInitStyle() == VarDecl::CallInit && + !Construct->isListInitialization()) { + ImplicitInit = Construct->getNumArgs() == 0 || + Construct->getArg(0)->isDefaultArgument(); + } + } if (!ImplicitInit) { if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << "("; @@ -653,7 +690,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { } void DeclPrinter::VisitImportDecl(ImportDecl *D) { - Out << "@__experimental_modules_import " << D->getImportedModule()->getFullModuleName() + Out << "@import " << D->getImportedModule()->getFullModuleName() << ";\n"; } @@ -690,6 +727,10 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { Out << *D->getAliasedNamespace(); } +void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) { + prettyPrintAttributes(D); +} + void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; @@ -746,8 +787,8 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { Visit(*D->decls_begin()); } -void DeclPrinter::PrintTemplateParameters( - const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) { +void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params, + const TemplateArgumentList *Args) { assert(Params); assert(!Args || Params->size() == Args->size()); @@ -882,6 +923,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { OMD->getBody()->printPretty(Out, 0, Policy); Out << '\n'; } + else if (Policy.PolishForDeclaration) + Out << ';'; } void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { @@ -892,7 +935,17 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { Out << "@implementation " << I << " : " << *SID; else Out << "@implementation " << I; - Out << "\n"; + + if (OID->ivar_size() > 0) { + Out << "{\n"; + Indentation += Policy.Indentation; + for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(), + E = OID->ivar_end(); I != E; ++I) { + Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + } + Indentation -= Policy.Indentation; + Out << "}\n"; + } VisitDeclContext(OID, false); Out << "@end"; } @@ -905,7 +958,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Out << "@class " << I << ";"; return; } - + bool eolnOut = false; if (SID) Out << "@interface " << I << " : " << *SID; else @@ -917,13 +970,12 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) Out << (I == Protocols.begin() ? '<' : ',') << **I; - } - - if (!Protocols.empty()) Out << "> "; + } if (OID->ivar_size() > 0) { Out << "{\n"; + eolnOut = true; Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { @@ -932,19 +984,33 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation -= Policy.Indentation; Out << "}\n"; } + else if (SID) { + Out << "\n"; + eolnOut = true; + } VisitDeclContext(OID, false); + if (!eolnOut) + Out << ' '; Out << "@end"; // FIXME: implement the rest... } void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { if (!PID->isThisDeclarationADefinition()) { - Out << "@protocol " << PID->getIdentifier() << ";\n"; + Out << "@protocol " << *PID << ";\n"; return; } - - Out << "@protocol " << *PID << '\n'; + // Protocols? + const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols(); + if (!Protocols.empty()) { + Out << "@protocol " << *PID; + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) + Out << (I == Protocols.begin() ? '<' : ',') << **I; + Out << ">\n"; + } else + Out << "@protocol " << *PID << '\n'; VisitDeclContext(PID, false); Out << "@end"; } @@ -959,6 +1025,17 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n"; + if (PID->ivar_size() > 0) { + Out << "{\n"; + Indentation += Policy.Indentation; + for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(), + E = PID->ivar_end(); I != E; ++I) { + Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + } + Indentation -= Policy.Indentation; + Out << "}\n"; + } + VisitDeclContext(PID, false); Out << "@end"; @@ -1040,6 +1117,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { Out << " )"; } Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl; + if (Policy.PolishForDeclaration) + Out << ';'; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { @@ -1068,9 +1147,23 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getQualifier()->print(Out, Policy); - Out << D->getDeclName(); + Out << D->getName(); } void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { // ignore } + +void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + Out << "#pragma omp threadprivate"; + if (!D->varlist_empty()) { + for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) { + Out << (I == D->varlist_begin() ? '(' : ',') + << *cast<NamedDecl>((*I)->getDecl()); + } + Out << ")"; + } +} + diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a70983f4c962..0b94f7d2c49b 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -11,13 +11,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/TypeLoc.h" -#include "clang/AST/ASTMutationListener.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" #include <memory> @@ -128,12 +128,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, // RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// -RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() { +RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { if (!Common) { // Walk the previous-declaration chain until we either find a declaration // with a common pointer or we run out of previous declarations. - llvm::SmallVector<RedeclarableTemplateDecl *, 2> PrevDecls; - for (RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; + SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; + for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { if (Prev->Common) { Common = Prev->Common; @@ -184,9 +184,8 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context, if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { QualType ArgType = Context.getTypeDeclType(TTP); if (TTP->isParameterPack()) - ArgType = Context.getPackExpansionType(ArgType, - llvm::Optional<unsigned>()); - + ArgType = Context.getPackExpansionType(ArgType, None); + Arg = TemplateArgument(ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { @@ -197,13 +196,12 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context, if (NTTP->isParameterPack()) E = new (Context) PackExpansionExpr(Context.DependentTy, E, - NTTP->getLocation(), - llvm::Optional<unsigned>()); + NTTP->getLocation(), None); Arg = TemplateArgument(E); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); if (TTP->isParameterPack()) - Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); + Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>()); else Arg = TemplateArgument(TemplateName(TTP)); } @@ -241,7 +239,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C, } RedeclarableTemplateDecl::CommonBase * -FunctionTemplateDecl::newCommon(ASTContext &C) { +FunctionTemplateDecl::newCommon(ASTContext &C) const { Common *CommonPtr = new (C) Common; C.AddDeallocation(DeallocateCommon, CommonPtr); return CommonPtr; @@ -304,7 +302,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, return new (Mem) ClassTemplateDecl(EmptyShell()); } -void ClassTemplateDecl::LoadLazySpecializations() { +void ClassTemplateDecl::LoadLazySpecializations() const { Common *CommonPtr = getCommonPtr(); if (CommonPtr->LazySpecializations) { ASTContext &Context = getASTContext(); @@ -316,7 +314,7 @@ void ClassTemplateDecl::LoadLazySpecializations() { } llvm::FoldingSetVector<ClassTemplateSpecializationDecl> & -ClassTemplateDecl::getSpecializations() { +ClassTemplateDecl::getSpecializations() const { LoadLazySpecializations(); return getCommonPtr()->Specializations; } @@ -328,7 +326,7 @@ ClassTemplateDecl::getPartialSpecializations() { } RedeclarableTemplateDecl::CommonBase * -ClassTemplateDecl::newCommon(ASTContext &C) { +ClassTemplateDecl::newCommon(ASTContext &C) const { Common *CommonPtr = new (C) Common; C.AddDeallocation(DeallocateCommon, CommonPtr); return CommonPtr; @@ -620,7 +618,7 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, TemplateParameterList *Params, - llvm::ArrayRef<TemplateParameterList*> Expansions) { + ArrayRef<TemplateParameterList *> Expansions) { void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) + sizeof(TemplateParameterList*) * Expansions.size()); return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params, @@ -728,6 +726,8 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, SpecializedTemplate, Args, NumArgs, PrevDecl); + Result->MayHaveOutOfDateDef = false; + Context.getTypeDeclType(Result, PrevDecl); return Result; } @@ -737,20 +737,19 @@ ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplateSpecializationDecl)); - return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization); + ClassTemplateSpecializationDecl *Result = + new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization); + Result->MayHaveOutOfDateDef = false; + return Result; } -void -ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, - const PrintingPolicy &Policy, - bool Qualified) const { - NamedDecl::getNameForDiagnostic(S, Policy, Qualified); +void ClassTemplateSpecializationDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); const TemplateArgumentList &TemplateArgs = getTemplateArgs(); - S += TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.data(), - TemplateArgs.size(), - Policy); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); } ClassTemplateDecl * @@ -857,6 +856,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, PrevDecl, SequenceNumber); Result->setSpecializationKind(TSK_ExplicitSpecialization); + Result->MayHaveOutOfDateDef = false; Context.getInjectedClassNameType(Result, CanonInjectedType); return Result; @@ -867,7 +867,10 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplatePartialSpecializationDecl)); - return new (Mem) ClassTemplatePartialSpecializationDecl(); + ClassTemplatePartialSpecializationDecl *Result + = new (Mem) ClassTemplatePartialSpecializationDecl(); + Result->MayHaveOutOfDateDef = false; + return Result; } //===----------------------------------------------------------------------===// @@ -919,7 +922,7 @@ void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) { static_cast<Common *>(Ptr)->~Common(); } RedeclarableTemplateDecl::CommonBase * -TypeAliasTemplateDecl::newCommon(ASTContext &C) { +TypeAliasTemplateDecl::newCommon(ASTContext &C) const { Common *CommonPtr = new (C) Common; C.AddDeallocation(DeallocateCommon, CommonPtr); return CommonPtr; diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 28188d91c10a..e4a41b6ffb50 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -364,6 +364,21 @@ DeclarationNameTable::~DeclarationNameTable() { delete LiteralNames; } +DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConstructorName, + Ty.getUnqualifiedType()); +} + +DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXDestructorName, + Ty.getUnqualifiedType()); +} + +DeclarationName +DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty); +} + DeclarationName DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, CanQualType Ty) { diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 5f43fbc251a0..be22ae450b62 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -17,6 +17,7 @@ // Only pay for this in code size in assertions-enabled builds. #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" @@ -37,8 +38,6 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/TypeVisitor.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -500,8 +499,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) dispatch(*I); - for (llvm::ArrayRef<NamedDecl*>::iterator - I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end(); + for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(), + E = D->getDeclsInPrototypeScope().end(); I != E; ++I) dispatch(*I); if (D->doesThisDeclarationHaveABody()) @@ -749,14 +748,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, visitDeclContext(D); } - // ObjCInterfaceDecl - void visitCategoryList(ObjCCategoryDecl *D) { - if (!D) return; - - TemporaryContainer C(*this, "categories"); - for (; D; D = D->getNextClassCategory()) - visitDeclRef(D); - } void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { setPointer("typeptr", D->getTypeForDecl()); setFlag("forward_decl", !D->isThisDeclarationADefinition()); @@ -771,7 +762,17 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) visitDeclRef(*I); } - visitCategoryList(D->getCategoryList()); + + if (!D->visible_categories_empty()) { + TemporaryContainer C(*this, "categories"); + + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = D->visible_categories_begin(), + CatEnd = D->visible_categories_end(); + Cat != CatEnd; ++Cat) { + visitDeclRef(*Cat); + } + } } void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { visitDeclContext(D); @@ -923,6 +924,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, case CC_AAPCS: return set("cc", "aapcs"); case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); case CC_PnaclCall: return set("cc", "pnaclcall"); + case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc"); } } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f3a2e0563872..b97f4d1d3a9a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -11,22 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclObjC.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Lex/LiteralSupport.h" -#include "clang/Lex/Lexer.h" -#include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -277,7 +279,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, // - an entity with reference type and is initialized with an // expression that is value-dependent [C++11] if (VarDecl *Var = dyn_cast<VarDecl>(D)) { - if ((Ctx.getLangOpts().CPlusPlus0x ? + if ((Ctx.getLangOpts().CPlusPlus11 ? Var->getType()->isLiteralType() : Var->getType()->isIntegralOrEnumerationType()) && (Var->getType().isConstQualified() || @@ -444,14 +446,6 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, return new (Mem) DeclRefExpr(EmptyShell()); } -SourceRange DeclRefExpr::getSourceRange() const { - SourceRange R = getNameInfo().getSourceRange(); - if (hasQualifier()) - R.setBegin(getQualifierLoc().getBeginLoc()); - if (hasExplicitTemplateArgs()) - R.setEnd(getRAngleLoc()); - return R; -} SourceLocation DeclRefExpr::getLocStart() const { if (hasQualifier()) return getQualifierLoc().getBeginLoc(); @@ -483,8 +477,9 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { } PrintingPolicy Policy(Context.getLangOpts()); - std::string Proto = FD->getQualifiedNameAsString(Policy); + std::string Proto; llvm::raw_string_ostream POut(Proto); + FD->printQualifiedName(POut, Policy); const FunctionDecl *Decl = FD; if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern()) @@ -509,7 +504,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { POut << ")"; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - const FunctionType *FT = cast<FunctionType>(MD->getType().getTypePtr()); + const FunctionType *FT = MD->getType()->castAs<FunctionType>(); if (FT->isConst()) POut << " const"; if (FT->isVolatile()) @@ -653,16 +648,14 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, false, false), Loc(L) { - FloatingLiteralBits.IsIEEE = - &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad; + setSemantics(V.getSemantics()); FloatingLiteralBits.IsExact = isexact; setValue(C, V); } FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { - FloatingLiteralBits.IsIEEE = - &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad; + setRawSemantics(IEEEhalf); FloatingLiteralBits.IsExact = false; } @@ -677,6 +670,41 @@ FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } +const llvm::fltSemantics &FloatingLiteral::getSemantics() const { + switch(FloatingLiteralBits.Semantics) { + case IEEEhalf: + return llvm::APFloat::IEEEhalf; + case IEEEsingle: + return llvm::APFloat::IEEEsingle; + case IEEEdouble: + return llvm::APFloat::IEEEdouble; + case x87DoubleExtended: + return llvm::APFloat::x87DoubleExtended; + case IEEEquad: + return llvm::APFloat::IEEEquad; + case PPCDoubleDouble: + return llvm::APFloat::PPCDoubleDouble; + } + llvm_unreachable("Unrecognised floating semantics"); +} + +void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) { + if (&Sem == &llvm::APFloat::IEEEhalf) + FloatingLiteralBits.Semantics = IEEEhalf; + else if (&Sem == &llvm::APFloat::IEEEsingle) + FloatingLiteralBits.Semantics = IEEEsingle; + else if (&Sem == &llvm::APFloat::IEEEdouble) + FloatingLiteralBits.Semantics = IEEEdouble; + else if (&Sem == &llvm::APFloat::x87DoubleExtended) + FloatingLiteralBits.Semantics = x87DoubleExtended; + else if (&Sem == &llvm::APFloat::IEEEquad) + FloatingLiteralBits.Semantics = IEEEquad; + else if (&Sem == &llvm::APFloat::PPCDoubleDouble) + FloatingLiteralBits.Semantics = PPCDoubleDouble; + else + llvm_unreachable("Unknown floating semantics"); +} + /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. @@ -745,7 +773,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { return SL; } -void StringLiteral::outputString(raw_ostream &OS) { +void StringLiteral::outputString(raw_ostream &OS) const { switch (getKind()) { case Ascii: break; // no prefix. case Wide: OS << 'L'; break; @@ -818,7 +846,7 @@ void StringLiteral::outputString(raw_ostream &OS) { assert(Char <= 0xff && "Characters above 0xff should already have been handled."); - if (isprint(Char)) + if (isPrintable(Char)) OS << (char)Char; else // Output anything hard as an octal escape. OS << '\\' @@ -1144,6 +1172,12 @@ unsigned CallExpr::isBuiltinCall() const { return FDecl->getBuiltinID(); } +bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const { + if (unsigned BI = isBuiltinCall()) + return Ctx.BuiltinInfo.isUnevaluated(BI); + return false; +} + QualType CallExpr::getCallReturnType() const { QualType CalleeType = getCallee()->getType(); if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>()) @@ -1158,21 +1192,9 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } -SourceRange CallExpr::getSourceRange() const { - if (isa<CXXOperatorCallExpr>(this)) - return cast<CXXOperatorCallExpr>(this)->getSourceRange(); - - SourceLocation begin = getCallee()->getLocStart(); - if (begin.isInvalid() && getNumArgs() > 0) - begin = getArg(0)->getLocStart(); - SourceLocation end = getRParenLoc(); - if (end.isInvalid() && getNumArgs() > 0) - end = getArg(getNumArgs() - 1)->getLocEnd(); - return SourceRange(begin, end); -} SourceLocation CallExpr::getLocStart() const { if (isa<CXXOperatorCallExpr>(this)) - return cast<CXXOperatorCallExpr>(this)->getSourceRange().getBegin(); + return cast<CXXOperatorCallExpr>(this)->getLocStart(); SourceLocation begin = getCallee()->getLocStart(); if (begin.isInvalid() && getNumArgs() > 0) @@ -1181,7 +1203,7 @@ SourceLocation CallExpr::getLocStart() const { } SourceLocation CallExpr::getLocEnd() const { if (isa<CXXOperatorCallExpr>(this)) - return cast<CXXOperatorCallExpr>(this)->getSourceRange().getEnd(); + return cast<CXXOperatorCallExpr>(this)->getLocEnd(); SourceLocation end = getRParenLoc(); if (end.isInvalid() && getNumArgs() > 0) @@ -1309,9 +1331,6 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, return E; } -SourceRange MemberExpr::getSourceRange() const { - return SourceRange(getLocStart(), getLocEnd()); -} SourceLocation MemberExpr::getLocStart() const { if (isImplicitAccess()) { if (hasQualifier()) @@ -1416,6 +1435,7 @@ void CastExpr::CheckCastConsistency() const { case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: + case CK_ZeroToOCLEvent: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; @@ -1547,6 +1567,8 @@ const char *CastExpr::getCastKindName() const { return "CopyAndAutoreleaseBlockObject"; case CK_BuiltinFnToFnPtr: return "BuiltinFnToFnPtr"; + case CK_ZeroToOCLEvent: + return "ZeroToOCLEvent"; } llvm_unreachable("Unhandled cast kind!"); @@ -1807,10 +1829,10 @@ bool InitListExpr::isStringLiteralInit() const { return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init); } -SourceRange InitListExpr::getSourceRange() const { +SourceLocation InitListExpr::getLocStart() const { if (InitListExpr *SyntacticForm = getSyntacticForm()) - return SyntacticForm->getSourceRange(); - SourceLocation Beg = LBraceLoc, End = RBraceLoc; + return SyntacticForm->getLocStart(); + SourceLocation Beg = LBraceLoc; if (Beg.isInvalid()) { // Find the first non-null initializer. for (InitExprsTy::const_iterator I = InitExprs.begin(), @@ -1822,18 +1844,25 @@ SourceRange InitListExpr::getSourceRange() const { } } } + return Beg; +} + +SourceLocation InitListExpr::getLocEnd() const { + if (InitListExpr *SyntacticForm = getSyntacticForm()) + return SyntacticForm->getLocEnd(); + SourceLocation End = RBraceLoc; if (End.isInvalid()) { // Find the first non-null initializer from the end. for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(), - E = InitExprs.rend(); - I != E; ++I) { + E = InitExprs.rend(); + I != E; ++I) { if (Stmt *S = *I) { - End = S->getSourceRange().getEnd(); + End = S->getLocEnd(); break; - } + } } } - return SourceRange(Beg, End); + return End; } /// getFunctionType - Return the underlying function type for this block. @@ -2115,10 +2144,6 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; } - // Ignore casts within macro expansions. - if (getExprLoc().isMacroID()) - return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); - // If this is a cast to a constructor conversion, check the operand. // Otherwise, the result of the cast is unused. if (CE->getCastKind() == CK_ConstructorConversion) @@ -2581,7 +2606,7 @@ bool Expr::isImplicitCXXThis() const { /// hasAnyTypeDependentArguments - Determines if any of the expressions /// in Exprs is type-dependent. -bool Expr::hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs) { +bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) { for (unsigned I = 0; I < Exprs.size(); ++I) if (Exprs[I]->isTypeDependent()) return true; @@ -3025,9 +3050,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return Source->isNullPointerConstant(Ctx, NPC); } - // C++0x nullptr_t is always a null pointer constant. + // C++11 nullptr_t is always a null pointer constant. if (getType()->isNullPtrType()) - return NPCK_CXX0X_nullptr; + return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) @@ -3045,7 +3070,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx, // test for the value 0. Don't use the C++11 constant expression semantics // for this, for now; once the dust settles on core issue 903, we might only // allow a literal 0 here in C++11 mode. - if (Ctx.getLangOpts().CPlusPlus0x) { + if (Ctx.getLangOpts().CPlusPlus11) { if (!isCXX98IntegralConstantExpr(Ctx)) return NPCK_NotNull; } else { @@ -3683,11 +3708,11 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const { DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this); if (size() == 1) return DIE->getDesignator(0)->getSourceRange(); - return SourceRange(DIE->getDesignator(0)->getStartLocation(), - DIE->getDesignator(size()-1)->getEndLocation()); + return SourceRange(DIE->getDesignator(0)->getLocStart(), + DIE->getDesignator(size()-1)->getLocEnd()); } -SourceRange DesignatedInitExpr::getSourceRange() const { +SourceLocation DesignatedInitExpr::getLocStart() const { SourceLocation StartLoc; Designator &First = *const_cast<DesignatedInitExpr*>(this)->designators_begin(); @@ -3699,30 +3724,37 @@ SourceRange DesignatedInitExpr::getSourceRange() const { } else StartLoc = SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc); - return SourceRange(StartLoc, getInit()->getSourceRange().getEnd()); + return StartLoc; +} + +SourceLocation DesignatedInitExpr::getLocEnd() const { + return getInit()->getLocEnd(); } -Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) { +Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const { assert(D.Kind == Designator::ArrayDesignator && "Requires array designator"); - char* Ptr = static_cast<char*>(static_cast<void *>(this)); + char *Ptr = static_cast<char *>( + const_cast<void *>(static_cast<const void *>(this))); Ptr += sizeof(DesignatedInitExpr); Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); } -Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { +Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const { assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); - char* Ptr = static_cast<char*>(static_cast<void *>(this)); + char *Ptr = static_cast<char *>( + const_cast<void *>(static_cast<const void *>(this))); Ptr += sizeof(DesignatedInitExpr); Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); } -Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { +Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const { assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); - char* Ptr = static_cast<char*>(static_cast<void *>(this)); + char *Ptr = static_cast<char *>( + const_cast<void *>(static_cast<const void *>(this))); Ptr += sizeof(DesignatedInitExpr); Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2)); @@ -3895,7 +3927,7 @@ Stmt::child_range ObjCMessageExpr::children() { reinterpret_cast<Stmt **>(getArgs() + getNumArgs())); } -ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements, +ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements, QualType T, ObjCMethodDecl *Method, SourceRange SR) : Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary, @@ -3916,7 +3948,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements, } ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C, - llvm::ArrayRef<Expr *> Elements, + ArrayRef<Expr *> Elements, QualType T, ObjCMethodDecl * Method, SourceRange SR) { void *Mem = C.Allocate(sizeof(ObjCArrayLiteral) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 55722a2a99af..12a47fcd7829 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -11,12 +11,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/IdentifierTable.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/IdentifierTable.h" using namespace clang; @@ -72,11 +73,8 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) { } // CXXScalarValueInitExpr -SourceRange CXXScalarValueInitExpr::getSourceRange() const { - SourceLocation Start = RParenLoc; - if (TypeInfo) - Start = TypeInfo->getTypeLoc().getBeginLoc(); - return SourceRange(Start, RParenLoc); +SourceLocation CXXScalarValueInitExpr::getLocStart() const { + return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc; } // CXXNewExpr @@ -180,7 +178,8 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, + Context.getPointerType(Context.getFunctionType(Context.VoidTy, + ArrayRef<QualType>(), FunctionProtoType::ExtProtoInfo())), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || @@ -217,11 +216,11 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const { return QualType(); } -SourceRange CXXPseudoDestructorExpr::getSourceRange() const { +SourceLocation CXXPseudoDestructorExpr::getLocEnd() const { SourceLocation End = DestroyedType.getLocation(); if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) End = TInfo->getTypeLoc().getLocalSourceRange().getEnd(); - return SourceRange(Base->getLocStart(), End); + return End; } // UnresolvedLookupExpr @@ -419,12 +418,18 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, return E; } -SourceRange CXXConstructExpr::getSourceRange() const { +SourceLocation CXXConstructExpr::getLocStart() const { if (isa<CXXTemporaryObjectExpr>(this)) - return cast<CXXTemporaryObjectExpr>(this)->getSourceRange(); + return cast<CXXTemporaryObjectExpr>(this)->getLocStart(); + return Loc; +} + +SourceLocation CXXConstructExpr::getLocEnd() const { + if (isa<CXXTemporaryObjectExpr>(this)) + return cast<CXXTemporaryObjectExpr>(this)->getLocEnd(); if (ParenRange.isValid()) - return SourceRange(Loc, ParenRange.getEnd()); + return ParenRange.getEnd(); SourceLocation End = Loc; for (unsigned I = getNumArgs(); I > 0; --I) { @@ -438,7 +443,7 @@ SourceRange CXXConstructExpr::getSourceRange() const { } } - return SourceRange(Loc, End); + return End; } SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const { @@ -522,13 +527,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXStaticCastExpr *E = new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc); + RParenLoc, AngleBrackets); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -546,13 +552,14 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXDynamicCastExpr *E = new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc); + RParenLoc, AngleBrackets); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -602,13 +609,14 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXReinterpretCastExpr *E = new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc); |