diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | bfef399519ca9b8a4b4c6b563253bad7e0eeffe0 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /lib | |
parent | 6a0372513edbc473b538d2f724efac50405d6fef (diff) | |
download | src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.tar.gz src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.zip |
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):vendor/clang/clang-release_34-r197841
Notes
Notes:
svn path=/vendor/clang/dist/; revision=259701
svn path=/vendor/clang/clang-release_34-r197841/; revision=259703; tag=vendor/clang/clang-release_34-r197841
Diffstat (limited to 'lib')
397 files changed, 67004 insertions, 28930 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index a6d48762fe55..3e429beded5d 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -150,7 +150,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) { // and avoid unrelated complications. llvm::Triple triple(origCI.getTargetOpts().Triple); - if (triple.getOS() == llvm::Triple::IOS) + if (triple.isiOS()) return triple.getOSMajorVersion() >= 5; if (triple.getOS() == llvm::Triple::Darwin) @@ -321,10 +321,6 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, DiagClient->EndSourceFile(); errRec.FinishCapture(); - // If we are migrating code that gets the '-fobjc-arc' flag, make sure - // to remove it so that we don't get errors from normal compilation. - origCI.getLangOpts()->ObjCAutoRefCount = false; - return capturedDiags.hasErrors() || testAct.hasReportedErrors(); } @@ -374,9 +370,6 @@ static bool applyTransforms(CompilerInvocation &origCI, origCI.getLangOpts()->ObjCAutoRefCount = true; return migration.getRemapper().overwriteOriginal(*Diags); } else { - // If we are migrating code that gets the '-fobjc-arc' flag, make sure - // to remove it so that we don't get errors from normal compilation. - origCI.getLangOpts()->ObjCAutoRefCount = false; return migration.getRemapper().flushToDisk(outputDir, *Diags); } } @@ -545,7 +538,7 @@ MigrationProcess::RewriteListener::~RewriteListener() { } MigrationProcess::MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient, StringRef outputDir) - : OrigCI(CI), DiagClient(diagClient) { + : OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) { if (!outputDir.empty()) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( @@ -588,6 +581,8 @@ bool MigrationProcess::applyTransform(TransformFn trans, } Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. + HadARCErrors = HadARCErrors || capturedDiags.hasErrors(); + // Don't filter diagnostics anymore. Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt index da51d6db83b8..c55261277dd1 100644 --- a/lib/ARCMigrate/CMakeLists.txt +++ b/lib/ARCMigrate/CMakeLists.txt @@ -40,4 +40,5 @@ target_link_libraries(clangARCMigrate clangFrontend clangRewriteCore clangRewriteFrontend + clangStaticAnalyzerCheckers ) diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp index 6a8686c4ff0f..a14226e43fe0 100644 --- a/lib/ARCMigrate/FileRemapper.cpp +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -43,10 +43,9 @@ void FileRemapper::clear(StringRef outputDir) { std::string FileRemapper::getRemapInfoFile(StringRef outputDir) { assert(!outputDir.empty()); - llvm::sys::Path dir(outputDir); - llvm::sys::Path infoFile = dir; - infoFile.appendComponent("remap"); - return infoFile.str(); + SmallString<128> InfoFile = outputDir; + llvm::sys::path::append(InfoFile, "remap"); + return InfoFile.str(); } bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, @@ -127,7 +126,7 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) { std::string errMsg; std::string infoFile = outputPath; llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, - llvm::raw_fd_ostream::F_Binary); + llvm::sys::fs::F_Binary); if (!errMsg.empty()) return report(errMsg, Diag); @@ -147,11 +146,10 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) { } else { SmallString<64> tempPath; - tempPath = path::filename(origFE->getName()); - tempPath += "-%%%%%%%%"; - tempPath += path::extension(origFE->getName()); int fd; - if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success) + if (fs::createTemporaryFile(path::filename(origFE->getName()), + path::extension(origFE->getName()), fd, + tempPath)) return report("Could not create file: " + tempPath.str(), Diag); llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true); @@ -176,29 +174,22 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag, for (MappingsTy::iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { const FileEntry *origFE = I->first; - if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) { - if (fs::copy_file(newFE->getName(), origFE->getName(), - fs::copy_option::overwrite_if_exists) != llvm::errc::success) - return report(StringRef("Could not copy file '") + newFE->getName() + - "' to file '" + origFE->getName() + "'", Diag); - } else { - - bool fileExists = false; - fs::exists(origFE->getName(), fileExists); - if (!fileExists) - return report(StringRef("File does not exist: ") + origFE->getName(), - Diag); + assert(I->second.is<llvm::MemoryBuffer *>()); + bool fileExists = false; + fs::exists(origFE->getName(), fileExists); + if (!fileExists) + return report(StringRef("File does not exist: ") + origFE->getName(), + Diag); - std::string errMsg; - llvm::raw_fd_ostream Out(origFE->getName(), errMsg, - llvm::raw_fd_ostream::F_Binary); - if (!errMsg.empty()) - return report(errMsg, Diag); + std::string errMsg; + llvm::raw_fd_ostream Out(origFE->getName(), errMsg, + llvm::sys::fs::F_Binary); + if (!errMsg.empty()) + return report(errMsg, Diag); - llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>(); - Out.write(mem->getBufferStart(), mem->getBufferSize()); - Out.close(); - } + llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>(); + Out.write(mem->getBufferStart(), mem->getBufferSize()); + Out.close(); } clear(outputDir); @@ -239,12 +230,6 @@ void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) { remap(getOriginalFile(filePath), memBuf); } -void FileRemapper::remap(StringRef filePath, StringRef newPath) { - const FileEntry *file = getOriginalFile(filePath); - const FileEntry *newfile = FileMgr->getFile(newPath); - remap(file, newfile); -} - void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) { assert(file); Target &targ = FromToMappings[file]; diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 57fac0389fc3..cac0fb0aed1b 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "Transforms.h" #include "clang/ARCMigrate/ARCMTActions.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -23,46 +24,101 @@ #include "clang/Lex/PPConditionalDirectiveRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" +#include "clang/AST/Attr.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" using namespace clang; using namespace arcmt; +using namespace ento::objc_retain; namespace { class ObjCMigrateASTConsumer : public ASTConsumer { + enum CF_BRIDGING_KIND { + CF_BRIDGING_NONE, + CF_BRIDGING_ENABLE, + CF_BRIDGING_MAY_INCLUDE + }; + void migrateDecl(Decl *D); - + void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D); + void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl); + void migrateProtocolConformance(ASTContext &Ctx, + const ObjCImplementationDecl *ImpDecl); + void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl); + bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, + const TypedefDecl *TypedefDcl); + void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl); + void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl, + ObjCMethodDecl *OM); + bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM); + void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM); + void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P); + void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl, + ObjCMethodDecl *OM, + ObjCInstanceTypeFamily OIT_Family = OIT_None); + + void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); + void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + const FunctionDecl *FuncDecl, bool ResultAnnotated); + void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); + + void AnnotateImplicitBridging(ASTContext &Ctx); + + CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx, + const FunctionDecl *FuncDecl); + + void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl); + + void migrateAddMethodAnnotation(ASTContext &Ctx, + const ObjCMethodDecl *MethodDecl); public: std::string MigrateDir; - bool MigrateLiterals; - bool MigrateSubscripting; + unsigned ASTMigrateActions; + FileID FileId; + const TypedefDecl *NSIntegerTypedefed; + const TypedefDecl *NSUIntegerTypedefed; OwningPtr<NSAPI> NSAPIObj; OwningPtr<edit::EditedSource> Editor; FileRemapper &Remapper; FileManager &FileMgr; const PPConditionalDirectiveRecord *PPRec; + Preprocessor &PP; bool IsOutputFile; - + llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls; + llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; + llvm::StringMap<char> WhiteListFilenames; + ObjCMigrateASTConsumer(StringRef migrateDir, - bool migrateLiterals, - bool migrateSubscripting, + unsigned astMigrateActions, FileRemapper &remapper, FileManager &fileMgr, const PPConditionalDirectiveRecord *PPRec, - bool isOutputFile = false) + Preprocessor &PP, + bool isOutputFile, + ArrayRef<std::string> WhiteList) : MigrateDir(migrateDir), - MigrateLiterals(migrateLiterals), - MigrateSubscripting(migrateSubscripting), - Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), - IsOutputFile(isOutputFile) { } + ASTMigrateActions(astMigrateActions), + NSIntegerTypedefed(0), NSUIntegerTypedefed(0), + Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), + IsOutputFile(isOutputFile) { + + for (ArrayRef<std::string>::iterator + I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) { + WhiteListFilenames.GetOrCreateValue(*I); + } + } protected: virtual void Initialize(ASTContext &Context) { NSAPIObj.reset(new NSAPI(Context)); Editor.reset(new edit::EditedSource(Context.getSourceManager(), Context.getLangOpts(), - PPRec)); + PPRec, false)); } virtual bool HandleTopLevelDecl(DeclGroupRef DG) { @@ -78,16 +134,22 @@ protected: } virtual void HandleTranslationUnit(ASTContext &Ctx); + + bool canModifyFile(StringRef Path) { + if (WhiteListFilenames.empty()) + return true; + return WhiteListFilenames.find(llvm::sys::path::filename(Path)) + != WhiteListFilenames.end(); + } }; } ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, - StringRef migrateDir, - bool migrateLiterals, - bool migrateSubscripting) + StringRef migrateDir, + unsigned migrateAction) : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), - MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting), + ObjCMigAction(migrateAction), CompInst(0) { if (MigrateDir.empty()) MigrateDir = "."; // user current directory if none is given. @@ -101,11 +163,13 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer * WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, - MigrateLiterals, - MigrateSubscripting, + ObjCMigAction, Remapper, CompInst->getFileManager(), - PPRec); + PPRec, + CompInst->getPreprocessor(), + false, + ArrayRef<std::string>()); ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; return new MultiplexConsumer(Consumers); } @@ -131,13 +195,13 @@ public: bool shouldWalkTypesOfTypeLocs() const { return false; } bool VisitObjCMessageExpr(ObjCMessageExpr *E) { - if (Consumer.MigrateLiterals) { + if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) { edit::Commit commit(*Consumer.Editor); edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap); Consumer.Editor->commit(commit); } - if (Consumer.MigrateSubscripting) { + if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) { edit::Commit commit(*Consumer.Editor); edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); Consumer.Editor->commit(commit); @@ -184,6 +248,1322 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { BodyMigrator(*this).TraverseDecl(D); } +static void append_attr(std::string &PropertyString, const char *attr, + bool &LParenAdded) { + if (!LParenAdded) { + PropertyString += "("; + LParenAdded = true; + } + else + PropertyString += ", "; + PropertyString += attr; +} + +static +void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString, + const std::string& TypeString, + const char *name) { + const char *argPtr = TypeString.c_str(); + int paren = 0; + while (*argPtr) { + switch (*argPtr) { + case '(': + PropertyString += *argPtr; + paren++; + break; + case ')': + PropertyString += *argPtr; + paren--; + break; + case '^': + case '*': + PropertyString += (*argPtr); + if (paren == 1) { + PropertyString += name; + name = ""; + } + break; + default: + PropertyString += *argPtr; + break; + } + argPtr++; + } +} + +static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) { + Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); + bool RetainableObject = ArgType->isObjCRetainableType(); + if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) { + if (const ObjCObjectPointerType *ObjPtrTy = + ArgType->getAs<ObjCObjectPointerType>()) { + ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); + if (IDecl && + IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) + return "copy"; + else + return "retain"; + } + else if (ArgType->isBlockPointerType()) + return "copy"; + } else if (propertyLifetime == Qualifiers::OCL_Weak) + // TODO. More precise determination of 'weak' attribute requires + // looking into setter's implementation for backing weak ivar. + return "weak"; + else if (RetainableObject) + return ArgType->isBlockPointerType() ? "copy" : "retain"; + return 0; +} + +static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, + const ObjCMethodDecl *Setter, + const NSAPI &NS, edit::Commit &commit, + unsigned LengthOfPrefix, + bool Atomic, bool UseNsIosOnlyMacro, + bool AvailabilityArgsMatch) { + ASTContext &Context = NS.getASTContext(); + bool LParenAdded = false; + std::string PropertyString = "@property "; + if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) { + PropertyString += "(NS_NONATOMIC_IOSONLY"; + LParenAdded = true; + } else if (!Atomic) { + PropertyString += "(nonatomic"; + LParenAdded = true; + } + + std::string PropertyNameString = Getter->getNameAsString(); + StringRef PropertyName(PropertyNameString); + if (LengthOfPrefix > 0) { + if (!LParenAdded) { + PropertyString += "(getter="; + LParenAdded = true; + } + else + PropertyString += ", getter="; + PropertyString += PropertyNameString; + } + // Property with no setter may be suggested as a 'readonly' property. + if (!Setter) { + append_attr(PropertyString, "readonly", LParenAdded); + QualType ResType = Context.getCanonicalType(Getter->getResultType()); + if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType)) + append_attr(PropertyString, MemoryManagementAttr, LParenAdded); + } + + // Short circuit 'delegate' properties that contain the name "delegate" or + // "dataSource", or have exact name "target" to have 'assign' attribute. + if (PropertyName.equals("target") || + (PropertyName.find("delegate") != StringRef::npos) || + (PropertyName.find("dataSource") != StringRef::npos)) { + QualType QT = Getter->getResultType(); + if (!QT->isRealType()) + append_attr(PropertyString, "assign", LParenAdded); + } + else if (Setter) { + const ParmVarDecl *argDecl = *Setter->param_begin(); + QualType ArgType = Context.getCanonicalType(argDecl->getType()); + if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType)) + append_attr(PropertyString, MemoryManagementAttr, LParenAdded); + } + if (LParenAdded) + PropertyString += ')'; + QualType RT = Getter->getResultType(); + if (!isa<TypedefType>(RT)) { + // strip off any ARC lifetime qualifier. + QualType CanResultTy = Context.getCanonicalType(RT); + if (CanResultTy.getQualifiers().hasObjCLifetime()) { + Qualifiers Qs = CanResultTy.getQualifiers(); + Qs.removeObjCLifetime(); + RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); + } + } + PropertyString += " "; + PrintingPolicy SubPolicy(Context.getPrintingPolicy()); + SubPolicy.SuppressStrongLifetime = true; + SubPolicy.SuppressLifetimeQualifiers = true; + std::string TypeString = RT.getAsString(SubPolicy); + if (LengthOfPrefix > 0) { + // property name must strip off "is" and lower case the first character + // after that; e.g. isContinuous will become continuous. + StringRef PropertyNameStringRef(PropertyNameString); + PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix); + PropertyNameString = PropertyNameStringRef; + bool NoLowering = (isUppercase(PropertyNameString[0]) && + PropertyNameString.size() > 1 && + isUppercase(PropertyNameString[1])); + if (!NoLowering) + PropertyNameString[0] = toLowercase(PropertyNameString[0]); + } + if (RT->isBlockPointerType() || RT->isFunctionPointerType()) + MigrateBlockOrFunctionPointerTypeVariable(PropertyString, + TypeString, + PropertyNameString.c_str()); + else { + char LastChar = TypeString[TypeString.size()-1]; + PropertyString += TypeString; + if (LastChar != '*') + PropertyString += ' '; + PropertyString += PropertyNameString; + } + SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc(); + Selector GetterSelector = Getter->getSelector(); + + SourceLocation EndGetterSelectorLoc = + StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size()); + commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), + EndGetterSelectorLoc), + PropertyString); + if (Setter && AvailabilityArgsMatch) { + SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); + // Get location past ';' + EndLoc = EndLoc.getLocWithOffset(1); + SourceLocation BeginOfSetterDclLoc = Setter->getLocStart(); + // FIXME. This assumes that setter decl; is immediately preceeded by eoln. + // It is trying to remove the setter method decl. line entirely. + BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1); + commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc)); + } +} + +void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, + ObjCContainerDecl *D) { + if (D->isDeprecated()) + return; + + for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = (*M); + if (Method->isDeprecated()) + continue; + bool PropertyInferred = migrateProperty(Ctx, D, Method); + // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to + // the getter method as it ends up on the property itself which we don't want + // to do unless -objcmt-returns-innerpointer-property option is on. + if (!PropertyInferred || + (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty)) + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + migrateNsReturnsInnerPointer(Ctx, Method); + } + if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty)) + return; + + for (ObjCContainerDecl::prop_iterator P = D->prop_begin(), + E = D->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) && + !Prop->isDeprecated()) + migratePropertyNsReturnsInnerPointer(Ctx, Prop); + } +} + +void ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx, + ObjCCategoryDecl *CatDecl) { + StringRef Name = CatDecl->getName(); + if (!Name.endswith("Deprecated")) + return; + + if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition()) + return; + + ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl); + + for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = (*M); + if (Method->isDeprecated() || Method->isImplicit()) + continue; + // Annotate with DEPRECATED + edit::Commit commit(*Editor); + commit.insertBefore(Method->getLocEnd(), " DEPRECATED"); + Editor->commit(commit); + } + for (ObjCContainerDecl::prop_iterator P = D->prop_begin(), + E = D->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + if (Prop->isDeprecated()) + continue; + // Annotate with DEPRECATED + edit::Commit commit(*Editor); + commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED"); + Editor->commit(commit); + } +} + +static bool +ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, + const ObjCImplementationDecl *ImpDecl, + const ObjCInterfaceDecl *IDecl, + ObjCProtocolDecl *Protocol) { + // In auto-synthesis, protocol properties are not synthesized. So, + // a conforming protocol must have its required properties declared + // in class interface. + bool HasAtleastOneRequiredProperty = false; + if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Property = *P; + if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) + continue; + HasAtleastOneRequiredProperty = true; + DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); + if (R.size() == 0) { + // Relax the rule and look into class's implementation for a synthesize + // or dynamic declaration. Class is implementing a property coming from + // another protocol. This still makes the target protocol as conforming. + if (!ImpDecl->FindPropertyImplDecl( + Property->getDeclName().getAsIdentifierInfo())) + return false; + } + else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) { + if ((ClassProperty->getPropertyAttributes() + != Property->getPropertyAttributes()) || + !Ctx.hasSameType(ClassProperty->getType(), Property->getType())) + return false; + } + else + return false; + } + + // At this point, all required properties in this protocol conform to those + // declared in the class. + // Check that class implements the required methods of the protocol too. + bool HasAtleastOneRequiredMethod = false; + if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) { + if (PDecl->meth_begin() == PDecl->meth_end()) + return HasAtleastOneRequiredProperty; + for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), + MEnd = PDecl->meth_end(); M != MEnd; ++M) { + ObjCMethodDecl *MD = (*M); + if (MD->isImplicit()) + continue; + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) + continue; + DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); + if (R.size() == 0) + return false; + bool match = false; + HasAtleastOneRequiredMethod = true; + for (unsigned I = 0, N = R.size(); I != N; ++I) + if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0])) + if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { + match = true; + break; + } + if (!match) + return false; + } + } + if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod) + return true; + return false; +} + +static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, + llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols, + const NSAPI &NS, edit::Commit &commit) { + const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols(); + std::string ClassString; + SourceLocation EndLoc = + IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation(); + + if (Protocols.empty()) { + ClassString = '<'; + for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { + ClassString += ConformingProtocols[i]->getNameAsString(); + if (i != (e-1)) + ClassString += ", "; + } + ClassString += "> "; + } + else { + ClassString = ", "; + for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { + ClassString += ConformingProtocols[i]->getNameAsString(); + if (i != (e-1)) + ClassString += ", "; + } + ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1; + EndLoc = *PL; + } + + commit.insertAfterToken(EndLoc, ClassString); + return true; +} + +static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, + const TypedefDecl *TypedefDcl, + const NSAPI &NS, edit::Commit &commit, + bool IsNSIntegerType, + bool NSOptions) { + std::string ClassString; + if (NSOptions) + ClassString = "typedef NS_OPTIONS(NSUInteger, "; + else + ClassString = + IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " + : "typedef NS_ENUM(NSUInteger, "; + + ClassString += TypedefDcl->getIdentifier()->getName(); + ClassString += ')'; + SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); + commit.replace(R, ClassString); + SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd(); + EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc, + NS.getASTContext(), /*IsDecl*/true); + if (!EndOfEnumDclLoc.isInvalid()) { + SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc); + commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange); + } + else + return false; + + SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd(); + EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc, + NS.getASTContext(), /*IsDecl*/true); + if (!EndTypedefDclLoc.isInvalid()) { + SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc); + commit.remove(TDRange); + } + else + return false; + + EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(), + /*IsDecl*/true); + if (!EndOfEnumDclLoc.isInvalid()) { + SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart(); + // FIXME. This assumes that enum decl; is immediately preceeded by eoln. + // It is trying to remove the enum decl. lines entirely. + BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1); + commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc)); + return true; + } + return false; +} + +static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl, + const TypedefDecl *TypedefDcl, + const NSAPI &NS, edit::Commit &commit, + bool IsNSIntegerType) { + std::string ClassString = + IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, "; + ClassString += TypedefDcl->getIdentifier()->getName(); + ClassString += ')'; + SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); + commit.replace(R, ClassString); + SourceLocation TypedefLoc = TypedefDcl->getLocEnd(); + commit.remove(SourceRange(TypedefLoc, TypedefLoc)); +} + +static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, + const EnumDecl *EnumDcl) { + bool PowerOfTwo = true; + bool AllHexdecimalEnumerator = true; + uint64_t MaxPowerOfTwoVal = 0; + for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(), + EE = EnumDcl->enumerator_end(); EI != EE; ++EI) { + EnumConstantDecl *Enumerator = (*EI); + const Expr *InitExpr = Enumerator->getInitExpr(); + if (!InitExpr) { + PowerOfTwo = false; + AllHexdecimalEnumerator = false; + continue; + } + InitExpr = InitExpr->IgnoreParenCasts(); + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) + if (BO->isShiftOp() || BO->isBitwiseOp()) + return true; + + uint64_t EnumVal = Enumerator->getInitVal().getZExtValue(); + if (PowerOfTwo && EnumVal) { + if (!llvm::isPowerOf2_64(EnumVal)) + PowerOfTwo = false; + else if (EnumVal > MaxPowerOfTwoVal) + MaxPowerOfTwoVal = EnumVal; + } + if (AllHexdecimalEnumerator && EnumVal) { + bool FoundHexdecimalEnumerator = false; + SourceLocation EndLoc = Enumerator->getLocEnd(); + Token Tok; + if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true)) + if (Tok.isLiteral() && Tok.getLength() > 2) { + if (const char *StringLit = Tok.getLiteralData()) + FoundHexdecimalEnumerator = + (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x')); + } + if (!FoundHexdecimalEnumerator) + AllHexdecimalEnumerator = false; + } + } + return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2)); +} + +void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, + const ObjCImplementationDecl *ImpDecl) { + const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface(); + if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated()) + return; + // Find all implicit conforming protocols for this class + // and make them explicit. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols; + Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols); + llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols; + + for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I = + ObjCProtocolDecls.begin(), + E = ObjCProtocolDecls.end(); I != E; ++I) + if (!ExplicitProtocols.count(*I)) + PotentialImplicitProtocols.push_back(*I); + + if (PotentialImplicitProtocols.empty()) + return; + + // go through list of non-optional methods and properties in each protocol + // in the PotentialImplicitProtocols list. If class implements every one of the + // methods and properties, then this class conforms to this protocol. + llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols; + for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++) + if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl, + PotentialImplicitProtocols[i])) + ConformingProtocols.push_back(PotentialImplicitProtocols[i]); + + if (ConformingProtocols.empty()) + return; + + // Further reduce number of conforming protocols. If protocol P1 is in the list + // protocol P2 (P2<P1>), No need to include P1. + llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols; + for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { + bool DropIt = false; + ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i]; + for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) { + ObjCProtocolDecl *PDecl = ConformingProtocols[i1]; + if (PDecl == TargetPDecl) + continue; + if (PDecl->lookupProtocolNamed( + TargetPDecl->getDeclName().getAsIdentifierInfo())) { + DropIt = true; + break; + } + } + if (!DropIt) + MinimalConformingProtocols.push_back(TargetPDecl); + } + edit::Commit commit(*Editor); + rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols, + *NSAPIObj, commit); + Editor->commit(commit); +} + +void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed( + const TypedefDecl *TypedefDcl) { + + QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); + if (NSAPIObj->isObjCNSIntegerType(qt)) + NSIntegerTypedefed = TypedefDcl; + else if (NSAPIObj->isObjCNSUIntegerType(qt)) + NSUIntegerTypedefed = TypedefDcl; +} + +bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, + const EnumDecl *EnumDcl, + const TypedefDecl *TypedefDcl) { + if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || + EnumDcl->isDeprecated()) + return false; + if (!TypedefDcl) { + if (NSIntegerTypedefed) { + TypedefDcl = NSIntegerTypedefed; + NSIntegerTypedefed = 0; + } + else if (NSUIntegerTypedefed) { + TypedefDcl = NSUIntegerTypedefed; + NSUIntegerTypedefed = 0; + } + else + return false; + FileID FileIdOfTypedefDcl = + PP.getSourceManager().getFileID(TypedefDcl->getLocation()); + FileID FileIdOfEnumDcl = + PP.getSourceManager().getFileID(EnumDcl->getLocation()); + if (FileIdOfTypedefDcl != FileIdOfEnumDcl) + return false; + } + if (TypedefDcl->isDeprecated()) + return false; + + QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); + bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt); + bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt); + + if (!IsNSIntegerType && !IsNSUIntegerType) { + // Also check for typedef enum {...} TD; + if (const EnumType *EnumTy = qt->getAs<EnumType>()) { + if (EnumTy->getDecl() == EnumDcl) { + bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); + if (NSOptions) { + if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) + return false; + } + else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) + return false; + edit::Commit commit(*Editor); + rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); + Editor->commit(commit); + return true; + } + } + return false; + } + + // We may still use NS_OPTIONS based on what we find in the enumertor list. + bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); + // NS_ENUM must be available. + if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) + return false; + // NS_OPTIONS must be available. + if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) + return false; + edit::Commit commit(*Editor); + bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, + commit, IsNSIntegerType, NSOptions); + Editor->commit(commit); + return Res; +} + +static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC, + ObjCMethodDecl *OM) { + SourceRange R; + std::string ClassString; + if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); + ClassString = "instancetype"; + } + else { + R = SourceRange(OM->getLocStart(), OM->getLocStart()); + ClassString = OM->isInstanceMethod() ? '-' : '+'; + ClassString += " (instancetype)"; + } + edit::Commit commit(*ASTC.Editor); + commit.replace(R, ClassString); + ASTC.Editor->commit(commit); +} + +static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, + ObjCMethodDecl *OM) { + ObjCInterfaceDecl *IDecl = OM->getClassInterface(); + SourceRange R; + std::string ClassString; + if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); { + ClassString = IDecl->getName(); + ClassString += "*"; + } + } + else { + R = SourceRange(OM->getLocStart(), OM->getLocStart()); + ClassString = "+ ("; + ClassString += IDecl->getName(); ClassString += "*)"; + } + edit::Commit commit(*ASTC.Editor); + commit.replace(R, ClassString); + ASTC.Editor->commit(commit); +} + +void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx, + ObjCContainerDecl *CDecl, + ObjCMethodDecl *OM) { + ObjCInstanceTypeFamily OIT_Family = + Selector::getInstTypeMethodFamily(OM->getSelector()); + + std::string ClassName; + switch (OIT_Family) { + case OIT_None: + migrateFactoryMethod(Ctx, CDecl, OM); + return; + case OIT_Array: + ClassName = "NSArray"; + break; + case OIT_Dictionary: + ClassName = "NSDictionary"; + break; + case OIT_Singleton: + migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton); + return; + case OIT_Init: + if (OM->getResultType()->isObjCIdType()) + ReplaceWithInstancetype(*this, OM); + return; + case OIT_ReturnsSelf: + migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf); + return; + } + if (!OM->getResultType()->isObjCIdType()) + return; + + ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); + if (!IDecl) { + if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) + IDecl = CatDecl->getClassInterface(); + else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) + IDecl = ImpDecl->getClassInterface(); + } + if (!IDecl || + !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) { + migrateFactoryMethod(Ctx, CDecl, OM); + return; + } + ReplaceWithInstancetype(*this, OM); +} + +static bool TypeIsInnerPointer(QualType T) { + if (!T->isAnyPointerType()) + return false; + if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() || + T->isBlockPointerType() || T->isFunctionPointerType() || + ento::coreFoundation::isCFObjectRef(T)) + return false; + // Also, typedef-of-pointer-to-incomplete-struct is something that we assume + // is not an innter pointer type. + QualType OrigT = T; + while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) + T = TD->getDecl()->getUnderlyingType(); + if (OrigT == T || !T->isPointerType()) + return true; + const PointerType* PT = T->getAs<PointerType>(); + QualType UPointeeT = PT->getPointeeType().getUnqualifiedType(); + if (UPointeeT->isRecordType()) { + const RecordType *RecordTy = UPointeeT->getAs<RecordType>(); + if (!RecordTy->getDecl()->isCompleteDefinition()) + return false; + } + return true; +} + +/// \brief Check whether the two versions match. +static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) { + return (X == Y); +} + +/// AvailabilityAttrsMatch - This routine checks that if comparing two +/// availability attributes, all their components match. It returns +/// true, if not dealing with availability or when all components of +/// availability attributes match. This routine is only called when +/// the attributes are of the same kind. +static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) { + const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1); + if (!AA1) + return true; + const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2); + + VersionTuple Introduced1 = AA1->getIntroduced(); + VersionTuple Deprecated1 = AA1->getDeprecated(); + VersionTuple Obsoleted1 = AA1->getObsoleted(); + bool IsUnavailable1 = AA1->getUnavailable(); + VersionTuple Introduced2 = AA2->getIntroduced(); + VersionTuple Deprecated2 = AA2->getDeprecated(); + VersionTuple Obsoleted2 = AA2->getObsoleted(); + bool IsUnavailable2 = AA2->getUnavailable(); + return (versionsMatch(Introduced1, Introduced2) && + versionsMatch(Deprecated1, Deprecated2) && + versionsMatch(Obsoleted1, Obsoleted2) && + IsUnavailable1 == IsUnavailable2); + +} + +static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2, + bool &AvailabilityArgsMatch) { + // This list is very small, so this need not be optimized. + for (unsigned i = 0, e = Attrs1.size(); i != e; i++) { + bool match = false; + for (unsigned j = 0, f = Attrs2.size(); j != f; j++) { + // Matching attribute kind only. Except for Availabilty attributes, + // we are not getting into details of the attributes. For all practical purposes + // this is sufficient. + if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) { + if (AvailabilityArgsMatch) + AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]); + match = true; + break; + } + } + if (!match) + return false; + } + return true; +} + +/// AttributesMatch - This routine checks list of attributes for two +/// decls. It returns false, if there is a mismatch in kind of +/// attributes seen in the decls. It returns true if the two decls +/// have list of same kind of attributes. Furthermore, when there +/// are availability attributes in the two decls, it sets the +/// AvailabilityArgsMatch to false if availability attributes have +/// different versions, etc. +static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, + bool &AvailabilityArgsMatch) { + if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) { + AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs()); + return true; + } + AvailabilityArgsMatch = true; + const AttrVec &Attrs1 = Decl1->getAttrs(); + const AttrVec &Attrs2 = Decl2->getAttrs(); + bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch); + if (match && (Attrs2.size() > Attrs1.size())) + return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch); + return match; +} + +static bool IsValidIdentifier(ASTContext &Ctx, + const char *Name) { + if (!isIdentifierHead(Name[0])) + return false; + std::string NameString = Name; + NameString[0] = toLowercase(NameString[0]); + IdentifierInfo *II = &Ctx.Idents.get(NameString); + return II->getTokenID() == tok::identifier; +} + +bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, + ObjCContainerDecl *D, + ObjCMethodDecl *Method) { + if (Method->isPropertyAccessor() || !Method->isInstanceMethod() || + Method->param_size() != 0) + return false; + // Is this method candidate to be a getter? + QualType GRT = Method->getResultType(); + if (GRT->isVoidType()) + return false; + + Selector GetterSelector = Method->getSelector(); + ObjCInstanceTypeFamily OIT_Family = + Selector::getInstTypeMethodFamily(GetterSelector); + + if (OIT_Family != OIT_None) + return false; + + IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); + Selector SetterSelector = + SelectorTable::constructSetterSelector(PP.getIdentifierTable(), + PP.getSelectorTable(), + getterName); + ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector); + unsigned LengthOfPrefix = 0; + if (!SetterMethod) { + // try a different naming convention for getter: isXxxxx + StringRef getterNameString = getterName->getName(); + bool IsPrefix = getterNameString.startswith("is"); + // Note that we don't want to change an isXXX method of retainable object + // type to property (readonly or otherwise). + if (IsPrefix && GRT->isObjCRetainableType()) + return false; + if (IsPrefix || getterNameString.startswith("get")) { + LengthOfPrefix = (IsPrefix ? 2 : 3); + const char *CGetterName = getterNameString.data() + LengthOfPrefix; + // Make sure that first character after "is" or "get" prefix can + // start an identifier. + if (!IsValidIdentifier(Ctx, CGetterName)) + return false; + if (CGetterName[0] && isUppercase(CGetterName[0])) { + getterName = &Ctx.Idents.get(CGetterName); + SetterSelector = + SelectorTable::constructSetterSelector(PP.getIdentifierTable(), + PP.getSelectorTable(), + getterName); + SetterMethod = D->getInstanceMethod(SetterSelector); + } + } + } + + if (SetterMethod) { + if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0) + return false; + bool AvailabilityArgsMatch; + if (SetterMethod->isDeprecated() || + !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch)) + return false; + + // Is this a valid setter, matching the target getter? + QualType SRT = SetterMethod->getResultType(); + if (!SRT->isVoidType()) + return false; + const ParmVarDecl *argDecl = *SetterMethod->param_begin(); + QualType ArgType = argDecl->getType(); + if (!Ctx.hasSameUnqualifiedType(ArgType, GRT)) + return false; + edit::Commit commit(*Editor); + rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit, + LengthOfPrefix, + (ASTMigrateActions & + FrontendOptions::ObjCMT_AtomicProperty) != 0, + (ASTMigrateActions & + FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0, + AvailabilityArgsMatch); + Editor->commit(commit); + return true; + } + else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) { + // Try a non-void method with no argument (and no setter or property of same name + // as a 'readonly' property. + edit::Commit commit(*Editor); + rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit, + LengthOfPrefix, + (ASTMigrateActions & + FrontendOptions::ObjCMT_AtomicProperty) != 0, + (ASTMigrateActions & + FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0, + /*AvailabilityArgsMatch*/false); + Editor->commit(commit); + return true; + } + return false; +} + +void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, + ObjCMethodDecl *OM) { + if (OM->isImplicit() || + !OM->isInstanceMethod() || + OM->hasAttr<ObjCReturnsInnerPointerAttr>()) + return; + + QualType RT = OM->getResultType(); + if (!TypeIsInnerPointer(RT) || + !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) + return; + + edit::Commit commit(*Editor); + commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER"); + Editor->commit(commit); +} + +void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, + ObjCPropertyDecl *P) { + QualType T = P->getType(); + + if (!TypeIsInnerPointer(T) || + !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) + return; + edit::Commit commit(*Editor); + commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER "); + Editor->commit(commit); +} + +void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx, + ObjCContainerDecl *CDecl) { + if (CDecl->isDeprecated()) + return; + + // migrate methods which can have instancetype as their result type. + for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), + MEnd = CDecl->meth_end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = (*M); + if (Method->isDeprecated()) + continue; + migrateMethodInstanceType(Ctx, CDecl, Method); + } +} + +void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, + ObjCContainerDecl *CDecl, + ObjCMethodDecl *OM, + ObjCInstanceTypeFamily OIT_Family) { + if (OM->isInstanceMethod() || + OM->getResultType() == Ctx.getObjCInstanceType() || + !OM->getResultType()->isObjCIdType()) + return; + + // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class + // NSYYYNamE with matching names be at least 3 characters long. + ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); + if (!IDecl) { + if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) + IDecl = CatDecl->getClassInterface(); + else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl)) + IDecl = ImpDecl->getClassInterface(); + } + if (!IDecl) + return; + + std::string StringClassName = IDecl->getName(); + StringRef LoweredClassName(StringClassName); + std::string StringLoweredClassName = LoweredClassName.lower(); + LoweredClassName = StringLoweredClassName; + + IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0); + // Handle method with no name at its first selector slot; e.g. + (id):(int)x. + if (!MethodIdName) + return; + + std::string MethodName = MethodIdName->getName(); + if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) { + StringRef STRefMethodName(MethodName); + size_t len = 0; + if (STRefMethodName.startswith("standard")) + len = strlen("standard"); + else if (STRefMethodName.startswith("shared")) + len = strlen("shared"); + else if (STRefMethodName.startswith("default")) + len = strlen("default"); + else + return; + MethodName = STRefMethodName.substr(len); + } + std::string MethodNameSubStr = MethodName.substr(0, 3); + StringRef MethodNamePrefix(MethodNameSubStr); + std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower(); + MethodNamePrefix = StringLoweredMethodNamePrefix; + size_t Ix = LoweredClassName.rfind(MethodNamePrefix); + if (Ix == StringRef::npos) + return; + std::string ClassNamePostfix = LoweredClassName.substr(Ix); + StringRef LoweredMethodName(MethodName); + std::string StringLoweredMethodName = LoweredMethodName.lower(); + LoweredMethodName = StringLoweredMethodName; + if (!LoweredMethodName.startswith(ClassNamePostfix)) + return; + if (OIT_Family == OIT_ReturnsSelf) + ReplaceWithClasstype(*this, OM); + else + ReplaceWithInstancetype(*this, OM); +} + +static bool IsVoidStarType(QualType Ty) { + if (!Ty->isPointerType()) + return false; + + while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr())) + Ty = TD->getDecl()->getUnderlyingType(); + + // Is the type void*? + const PointerType* PT = Ty->getAs<PointerType>(); + if (PT->getPointeeType().getUnqualifiedType()->isVoidType()) + return true; + return IsVoidStarType(PT->getPointeeType()); +} + +/// AuditedType - This routine audits the type AT and returns false if it is one of known +/// CF object types or of the "void *" variety. It returns true if we don't care about the type +/// such as a non-pointer or pointers which have no ownership issues (such as "int *"). +static bool AuditedType (QualType AT) { + if (!AT->isAnyPointerType() && !AT->isBlockPointerType()) + return true; + // FIXME. There isn't much we can say about CF pointer type; or is there? + if (ento::coreFoundation::isCFObjectRef(AT) || + IsVoidStarType(AT) || + // If an ObjC object is type, assuming that it is not a CF function and + // that it is an un-audited function. + AT->isObjCObjectPointerType() || AT->isObjCBuiltinType()) + return false; + // All other pointers are assumed audited as harmless. + return true; +} + +void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) { + if (CFFunctionIBCandidates.empty()) + return; + if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) { + CFFunctionIBCandidates.clear(); + FileId = FileID(); + return; + } + // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED + const Decl *FirstFD = CFFunctionIBCandidates[0]; + const Decl *LastFD = + CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1]; + const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n"; + edit::Commit commit(*Editor); + commit.insertBefore(FirstFD->getLocStart(), PragmaString); + PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n"; + SourceLocation EndLoc = LastFD->getLocEnd(); + // get location just past end of function location. + EndLoc = PP.getLocForEndOfToken(EndLoc); + if (isa<FunctionDecl>(LastFD)) { + // For Methods, EndLoc points to the ending semcolon. So, + // not of these extra work is needed. + Token Tok; + // get locaiton of token that comes after end of function. + bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true); + if (!Failed) + EndLoc = Tok.getLocation(); + } + commit.insertAfterToken(EndLoc, PragmaString); + Editor->commit(commit); + FileId = FileID(); + CFFunctionIBCandidates.clear(); +} + +void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) { + if (Decl->isDeprecated()) + return; + + if (Decl->hasAttr<CFAuditedTransferAttr>()) { + assert(CFFunctionIBCandidates.empty() && + "Cannot have audited functions/methods inside user " + "provided CF_IMPLICIT_BRIDGING_ENABLE"); + return; + } + + // Finction must be annotated first. + if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) { + CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl); + if (AuditKind == CF_BRIDGING_ENABLE) { + CFFunctionIBCandidates.push_back(Decl); + if (FileId.isInvalid()) + FileId = PP.getSourceManager().getFileID(Decl->getLocation()); + } + else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) { + if (!CFFunctionIBCandidates.empty()) { + CFFunctionIBCandidates.push_back(Decl); + if (FileId.isInvalid()) + FileId = PP.getSourceManager().getFileID(Decl->getLocation()); + } + } + else + AnnotateImplicitBridging(Ctx); + } + else { + migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl)); + AnnotateImplicitBridging(Ctx); + } +} + +void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, + const CallEffects &CE, + const FunctionDecl *FuncDecl, + bool ResultAnnotated) { + // Annotate function. + if (!ResultAnnotated) { + RetEffect Ret = CE.getReturnValue(); + const char *AnnotationString = 0; + if (Ret.getObjKind() == RetEffect::CF) { + if (Ret.isOwned() && + Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) + AnnotationString = " CF_RETURNS_RETAINED"; + else if (Ret.notOwned() && + Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) + AnnotationString = " CF_RETURNS_NOT_RETAINED"; + } + else if (Ret.getObjKind() == RetEffect::ObjC) { + if (Ret.isOwned() && + Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) + AnnotationString = " NS_RETURNS_RETAINED"; + } + + if (AnnotationString) { + edit::Commit commit(*Editor); + commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString); + Editor->commit(commit); + } + } + llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); + unsigned i = 0; + for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), + pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() && + Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); + Editor->commit(commit); + } + else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() && + Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(pd->getLocation(), "NS_CONSUMED "); + Editor->commit(commit); + } + } +} + + +ObjCMigrateASTConsumer::CF_BRIDGING_KIND + ObjCMigrateASTConsumer::migrateAddFunctionAnnotation( + ASTContext &Ctx, + const FunctionDecl *FuncDecl) { + if (FuncDecl->hasBody()) + return CF_BRIDGING_NONE; + + CallEffects CE = CallEffects::getEffect(FuncDecl); + bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() || + FuncDecl->getAttr<CFReturnsNotRetainedAttr>() || + FuncDecl->getAttr<NSReturnsRetainedAttr>() || + FuncDecl->getAttr<NSReturnsNotRetainedAttr>() || + FuncDecl->getAttr<NSReturnsAutoreleasedAttr>()); + + // Trivial case of when funciton is annotated and has no argument. + if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0) + return CF_BRIDGING_NONE; + + bool ReturnCFAudited = false; + if (!FuncIsReturnAnnotated) { + RetEffect Ret = CE.getReturnValue(); + if (Ret.getObjKind() == RetEffect::CF && + (Ret.isOwned() || Ret.notOwned())) + ReturnCFAudited = true; + else if (!AuditedType(FuncDecl->getResultType())) + return CF_BRIDGING_NONE; + } + + // At this point result type is audited for potential inclusion. + // Now, how about argument types. + llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); + unsigned i = 0; + bool ArgCFAudited = false; + for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), + pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) { + if (AE == DecRef && !pd->getAttr<CFConsumedAttr>()) + ArgCFAudited = true; + else if (AE == IncRef) + ArgCFAudited = true; + } + else { + QualType AT = pd->getType(); + if (!AuditedType(AT)) { + AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); + return CF_BRIDGING_NONE; + } + } + } + if (ReturnCFAudited || ArgCFAudited) + return CF_BRIDGING_ENABLE; + + return CF_BRIDGING_MAY_INCLUDE; +} + +void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, + ObjCContainerDecl *CDecl) { + if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated()) + return; + + // migrate methods which can have instancetype as their result type. + for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(), + MEnd = CDecl->meth_end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = (*M); + migrateCFAnnotation(Ctx, Method); + } +} + +void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, + const CallEffects &CE, + const ObjCMethodDecl *MethodDecl, + bool ResultAnnotated) { + // Annotate function. + if (!ResultAnnotated) { + RetEffect Ret = CE.getReturnValue(); + const char *AnnotationString = 0; + if (Ret.getObjKind() == RetEffect::CF) { + if (Ret.isOwned() && + Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) + AnnotationString = " CF_RETURNS_RETAINED"; + else if (Ret.notOwned() && + Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) + AnnotationString = " CF_RETURNS_NOT_RETAINED"; + } + else if (Ret.getObjKind() == RetEffect::ObjC) { + ObjCMethodFamily OMF = MethodDecl->getMethodFamily(); + switch (OMF) { + case clang::OMF_alloc: + case clang::OMF_new: + case clang::OMF_copy: + case clang::OMF_init: + case clang::OMF_mutableCopy: + break; + + default: + if (Ret.isOwned() && + Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) + AnnotationString = " NS_RETURNS_RETAINED"; + break; + } + } + + if (AnnotationString) { + edit::Commit commit(*Editor); + commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString); + Editor->commit(commit); + } + } + llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); + unsigned i = 0; + for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), + pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() && + Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); + Editor->commit(commit); + } + } +} + +void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( + ASTContext &Ctx, + const ObjCMethodDecl *MethodDecl) { + if (MethodDecl->hasBody() || MethodDecl->isImplicit()) + return; + + CallEffects CE = CallEffects::getEffect(MethodDecl); + bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() || + MethodDecl->getAttr<CFReturnsNotRetainedAttr>() || + MethodDecl->getAttr<NSReturnsRetainedAttr>() || + MethodDecl->getAttr<NSReturnsNotRetainedAttr>() || + MethodDecl->getAttr<NSReturnsAutoreleasedAttr>()); + + if (CE.getReceiver() == DecRefMsg && + !MethodDecl->getAttr<NSConsumesSelfAttr>() && + MethodDecl->getMethodFamily() != OMF_init && + MethodDecl->getMethodFamily() != OMF_release && + Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) { + edit::Commit commit(*Editor); + commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF"); + Editor->commit(commit); + } + + // Trivial case of when funciton is annotated and has no argument. + if (MethodIsReturnAnnotated && + (MethodDecl->param_begin() == MethodDecl->param_end())) + return; + + if (!MethodIsReturnAnnotated) { + RetEffect Ret = CE.getReturnValue(); + if ((Ret.getObjKind() == RetEffect::CF || + Ret.getObjKind() == RetEffect::ObjC) && + (Ret.isOwned() || Ret.notOwned())) { + AddCFAnnotations(Ctx, CE, MethodDecl, false); + return; + } + else if (!AuditedType(MethodDecl->getResultType())) + return; + } + + // At this point result type is either annotated or audited. + // Now, how about argument types. + llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs(); + unsigned i = 0; + for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), + pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { + const ParmVarDecl *pd = *pi; + ArgEffect AE = AEArgs[i]; + if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef || + !AuditedType(pd->getType())) { + AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); + return; + } + } + return; +} + namespace { class RewritesReceiver : public edit::EditsReceiver { @@ -202,7 +1582,114 @@ public: } +static bool +IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) { + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = + Ctx.getSourceManager().getSLocEntry(FID, &Invalid); + if (!Invalid && SEntry.isFile()) { + const SrcMgr::FileInfo &FI = SEntry.getFile(); + if (!FI.hasLineDirectives()) { + if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem) + return true; + if (FI.getFileCharacteristic() == SrcMgr::C_System) { + // This file is in a system header directory. Continue with commiting change + // only if it is a user specified system directory because user put a + // .system_framework file in the framework directory. + StringRef Directory(file->getDir()->getName()); + size_t Ix = Directory.rfind(".framework"); + if (Ix == StringRef::npos) + return true; + std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework")); + PatchToSystemFramework += ".system_framework"; + if (!llvm::sys::fs::exists(PatchToSystemFramework.data())) + return true; + } + } + } + return false; +} + void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { + + TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); + if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) { + for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end(); + D != DEnd; ++D) { + FileID FID = PP.getSourceManager().getFileID((*D)->getLocation()); + if (!FID.isInvalid()) + if (!FileId.isInvalid() && FileId != FID) { + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + AnnotateImplicitBridging(Ctx); + } + + if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D)) + migrateObjCInterfaceDecl(Ctx, CDecl); + if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) { + migrateObjCInterfaceDecl(Ctx, CatDecl); + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + migrateDeprecatedAnnotation(Ctx, CatDecl); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) + ObjCProtocolDecls.insert(PDecl); + else if (const ObjCImplementationDecl *ImpDecl = + dyn_cast<ObjCImplementationDecl>(*D)) { + if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) + migrateProtocolConformance(Ctx, ImpDecl); + } + else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) { + if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) + continue; + DeclContext::decl_iterator N = D; + if (++N != DEnd) { + const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N); + if (migrateNSEnumDecl(Ctx, ED, TD) && TD) + D++; + } + else + migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0); + } + else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) { + if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros)) + continue; + DeclContext::decl_iterator N = D; + if (++N == DEnd) + continue; + if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) { + if (++N != DEnd) + if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) { + // prefer typedef-follows-enum to enum-follows-typedef pattern. + if (migrateNSEnumDecl(Ctx, ED, TDF)) { + ++D; ++D; + CacheObjCNSIntegerTypedefed(TD); + continue; + } + } + if (migrateNSEnumDecl(Ctx, ED, TD)) { + ++D; + continue; + } + } + CacheObjCNSIntegerTypedefed(TD); + } + else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) { + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + migrateCFAnnotation(Ctx, FD); + } + + if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) { + // migrate methods which can have instancetype as their result type. + if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) + migrateAllMethodInstaceType(Ctx, CDecl); + // annotate methods with CF annotations. + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + migrateARCSafeAnnotation(Ctx, CDecl); + } + } + if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) + AnnotateImplicitBridging(Ctx); + } + Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); RewritesReceiver Rec(rewriter); Editor->applyRewrites(Rec); @@ -213,6 +1700,10 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { RewriteBuffer &buf = I->second; const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); assert(file); + if (IsReallyASystemHeader(Ctx, file, FID)) + continue; + if (!canModifyFile(file->getName())) + continue; SmallString<512> newText; llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); @@ -236,16 +1727,49 @@ bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { return true; } +static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) { + using namespace llvm::sys::fs; + using namespace llvm::sys::path; + + std::vector<std::string> Filenames; + if (DirPath.empty() || !is_directory(DirPath)) + return Filenames; + + llvm::error_code EC; + directory_iterator DI = directory_iterator(DirPath, EC); + directory_iterator DE; + for (; !EC && DI != DE; DI = DI.increment(EC)) { + if (is_regular_file(DI->path())) + Filenames.push_back(filename(DI->path())); + } + + return Filenames; +} + ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); + unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction; + unsigned ObjCMTOpts = ObjCMTAction; + // These are companion flags, they do not enable transformations. + ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty | + FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty); + if (ObjCMTOpts == FrontendOptions::ObjCMT_None) { + // If no specific option was given, enable literals+subscripting transforms + // by default. + ObjCMTAction |= FrontendOptions::ObjCMT_Literals | + FrontendOptions::ObjCMT_Subscripting; + } CI.getPreprocessor().addPPCallbacks(PPRec); + std::vector<std::string> WhiteList = + getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath); return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, - /*MigrateLiterals=*/true, - /*MigrateSubscripting=*/true, + ObjCMTAction, Remapper, CI.getFileManager(), PPRec, - /*isOutputFile=*/true); + CI.getPreprocessor(), + /*isOutputFile=*/true, + WhiteList); } diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index fc4a75fdb838..7b360c640cfd 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -77,6 +77,13 @@ public: TraverseStmt(body); } + bool TraverseBlockDecl(BlockDecl *D) { + // ParentMap does not enter into a BlockDecl to record its stmts, so use a + // new UnbridgedCastRewriter to handle the block. + UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D); + return true; + } + bool VisitCastExpr(CastExpr *E) { if (E->getCastKind() != CK_CPointerToObjCPointerCast && E->getCastKind() != CK_BitCast && @@ -148,7 +155,7 @@ private: if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) { + FD->isExternallyVisible()) { Expr *Arg = callE->getArg(0); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { const Expr *sub = ICE->getSubExpr(); @@ -413,7 +420,7 @@ private: FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) + FD->isExternallyVisible()) return true; return false; diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 087219535a18..679b924ba009 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -49,7 +49,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type, return false; // iOS is always safe to use 'weak'. - if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS) + if (Ctx.getTargetInfo().getTriple().isiOS()) AllowOnUnknownClass = true; while (const PointerType *ptr = T->getAs<PointerType>()) @@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) { if (FD->isGlobal() && FD->getIdentifier() && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage() && + FD->isExternallyVisible() && ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); @@ -122,8 +122,8 @@ bool trans::isPlusOne(const Expr *E) { /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. SourceLocation trans::findLocationAfterSemi(SourceLocation loc, - ASTContext &Ctx) { - SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); + ASTContext &Ctx, bool IsDecl) { + SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl); if (SemiLoc.isInvalid()) return SourceLocation(); return SemiLoc.getLocWithOffset(1); @@ -134,7 +134,8 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc, /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. SourceLocation trans::findSemiAfterLocation(SourceLocation loc, - ASTContext &Ctx) { + ASTContext &Ctx, + bool IsDecl) { SourceManager &SM = Ctx.getSourceManager(); if (loc.isMacroID()) { if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc)) @@ -159,8 +160,13 @@ SourceLocation trans::findSemiAfterLocation(SourceLocation loc, file.begin(), tokenBegin, file.end()); Token tok; lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::semi)) - return SourceLocation(); + if (tok.isNot(tok::semi)) { + if (!IsDecl) + return SourceLocation(); + // Declaration may be followed with other tokens; such as an __attribute, + // before ending with a semicolon. + return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true); + } return tok.getLocation(); } @@ -198,7 +204,7 @@ bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return DRE->getDecl()->getDeclContext()->isFileContext() && - DRE->getDecl()->hasExternalLinkage(); + DRE->getDecl()->isExternallyVisible(); if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index e20fe5927f39..eab5e85d56b7 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -167,13 +167,15 @@ bool isPlusOne(const Expr *E); /// immediately after the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. -SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); +SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx, + bool IsDecl = false); /// \brief 'Loc' is the end of a statement range. This returns the location /// of the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. -SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx); +SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, + bool IsDecl = false); bool hasSideEffects(Expr *E, ASTContext &Ctx); bool isGlobalVar(Expr *E); diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 98e825b3bafb..541836b21b70 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -212,6 +212,40 @@ void APValue::DestroyDataAndMakeUninit() { Kind = Uninitialized; } +bool APValue::needsCleanup() const { + switch (getKind()) { + case Uninitialized: + case AddrLabelDiff: + return false; + case Struct: + case Union: + case Array: + case Vector: + return true; + case Int: + return getInt().needsCleanup(); + case Float: + return getFloat().needsCleanup(); + case ComplexFloat: + assert(getComplexFloatImag().needsCleanup() == + getComplexFloatReal().needsCleanup() && + "In _Complex float types, real and imaginary values always have the " + "same size."); + return getComplexFloatReal().needsCleanup(); + case ComplexInt: + assert(getComplexIntImag().needsCleanup() == + getComplexIntReal().needsCleanup() && + "In _Complex int types, real and imaginary values must have the " + "same size."); + return getComplexIntReal().needsCleanup(); + case LValue: + return reinterpret_cast<const LV *>(Data)->hasPathPtr(); + case MemberPointer: + return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr(); + } + llvm_unreachable("Unknown APValue kind!"); +} + void APValue::swap(APValue &RHS) { std::swap(Kind, RHS.Kind); char TmpData[MaxSize]; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 176aec53a252..a03cf9e7d47b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -25,13 +25,16 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.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/ADT/Triple.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -132,8 +135,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { isa<RedeclarableTemplateDecl>(D) || isa<ClassTemplateSpecializationDecl>(D)) DeclLoc = D->getLocStart(); - else + else { DeclLoc = D->getLocation(); + // If location of the typedef name is in a macro, it is because being + // declared via a macro. Try using declaration's starting location + // as the "declaration location". + if (DeclLoc.isMacroID() && isa<TypedefDecl>(D)) + DeclLoc = D->getLocStart(); + } // If the declaration doesn't map directly to a location in a file, we // can't find the comment. @@ -175,7 +184,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // First check whether we have a trailing comment. if (Comment != RawComments.end() && (*Comment)->isDocumentation() && (*Comment)->isTrailingComment() && - (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D))) { + (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) || + isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) { std::pair<FileID, unsigned> CommentBeginDecomp = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin()); // Check that Doxygen trailing comment comes after the declaration, starts @@ -220,7 +230,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // There should be no other declarations or preprocessor directives between // comment and declaration. - if (Text.find_first_of(",;{}#@") != StringRef::npos) + if (Text.find_first_of(";{}#@") != StringRef::npos) return NULL; return *Comment; @@ -406,9 +416,16 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, } +comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const { + const RawComment *RC = getRawCommentForDeclNoCache(D); + return RC ? RC->parse(*this, 0, D) : 0; +} + comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { + if (D->isInvalidDecl()) + return NULL; D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); @@ -679,6 +696,19 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, } } +static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI, + const LangOptions &LangOpts) { + switch (LangOpts.getAddressSpaceMapMangling()) { + case LangOptions::ASMM_Target: + return TI.useAddressSpaceMapMangling(); + case LangOptions::ASMM_On: + return true; + case LangOptions::ASMM_Off: + return false; + } + llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything."); +} + ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t, IdentifierTable &idents, SelectorTable &sels, @@ -690,7 +720,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, DependentTemplateSpecializationTypes(this_()), SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(0), - Int128Decl(0), UInt128Decl(0), + Int128Decl(0), UInt128Decl(0), Float128StubDecl(0), BuiltinVaListDecl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0), BOOLDecl(0), @@ -709,8 +739,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), - LastSDM(0, 0), - UniqueBlockByRefTypeID(0) + LastSDM(0, 0) { if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); @@ -726,10 +755,12 @@ ASTContext::~ASTContext() { // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); - // Call all of the deallocation functions. - for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) - Deallocations[I].first(Deallocations[I].second); - + // Call all of the deallocation functions on all of their targets. + for (DeallocationMap::const_iterator I = Deallocations.begin(), + E = Deallocations.end(); I != E; ++I) + for (unsigned J = 0, N = I->second.size(); J != N; ++J) + (I->first)((I->second)[J]); + // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed // because they can contain DenseMaps. for (llvm::DenseMap<const ObjCContainerDecl*, @@ -750,10 +781,16 @@ ASTContext::~ASTContext() { AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + + for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator + I = MangleNumberingContexts.begin(), + E = MangleNumberingContexts.end(); + I != E; ++I) + delete I->second; } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { - Deallocations.push_back(std::make_pair(Callback, Data)); + Deallocations[Callback].push_back(Data); } void @@ -848,6 +885,20 @@ TypedefDecl *ASTContext::getUInt128Decl() const { return UInt128Decl; } +TypeDecl *ASTContext::getFloat128StubType() const { + assert(LangOpts.CPlusPlus && "should only be called for c++"); + if (!Float128StubDecl) { + Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this), + TTK_Struct, + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("__float128")); + } + + return Float128StubDecl; +} + void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); R = CanQualType::CreateUnsafe(QualType(Ty, 0)); @@ -863,6 +914,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); + AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts); // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); @@ -897,13 +949,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); - if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5 - if (TargetInfo::isTypeSigned(Target.getWCharType())) - InitBuiltinType(WCharTy, BuiltinType::WChar_S); - else // -fshort-wchar makes wchar_t be unsigned. - InitBuiltinType(WCharTy, BuiltinType::WChar_U); - } else // C99 (or C++ using -fno-wchar) - WCharTy = getFromTargetType(Target.getWCharType()); + // C++ 3.9.1p5 + if (TargetInfo::isTypeSigned(Target.getWCharType())) + InitBuiltinType(WCharTy, BuiltinType::WChar_S); + else // -fshort-wchar makes wchar_t be unsigned. + InitBuiltinType(WCharTy, BuiltinType::WChar_U); + if (LangOpts.CPlusPlus && LangOpts.WChar) + WideCharTy = WCharTy; + else { + // C99 (or C++ using -fno-wchar). + WideCharTy = getFromTargetType(Target.getWCharType()); + } WIntTy = getFromTargetType(Target.getWIntType()); @@ -1008,13 +1064,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } +// FIXME: Remove ? MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos - = InstantiatedFromStaticDataMember.find(Var); - if (Pos == InstantiatedFromStaticDataMember.end()) - return 0; + return getTemplateOrSpecializationInfo(Var) + .dyn_cast<MemberSpecializationInfo *>(); +} + +ASTContext::TemplateOrSpecializationInfo +ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos = + TemplateOrInstantiation.find(Var); + if (Pos == TemplateOrInstantiation.end()) + return TemplateOrSpecializationInfo(); return Pos->second; } @@ -1025,10 +1088,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, SourceLocation PointOfInstantiation) { assert(Inst->isStaticDataMember() && "Not a static data member"); assert(Tmpl->isStaticDataMember() && "Not a static data member"); - assert(!InstantiatedFromStaticDataMember[Inst] && - "Already noted what static data member was instantiated from"); - InstantiatedFromStaticDataMember[Inst] - = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); + setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo( + Tmpl, TSK, PointOfInstantiation)); +} + +void +ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI) { + assert(!TemplateOrInstantiation[Inst] && + "Already noted what the variable was instantiated from"); + TemplateOrInstantiation[Inst] = TSI; } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( @@ -1105,38 +1174,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } -bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidthValue(*this) == 0); -} - -bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidthValue(*this) == 0 && - LastFD->getBitWidthValue(*this) != 0); -} - -bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidthValue(*this) && - LastFD->getBitWidthValue(*this)); -} - -bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (!FD->isBitField() && LastFD && LastFD->isBitField() && - LastFD->getBitWidthValue(*this)); -} - -bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidthValue(*this)); -} - ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos @@ -1224,12 +1261,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlign - Return a conservative estimate of the alignment of the -/// specified decl. Note that bitfields do not have a valid alignment, so -/// this method will assert on them. -/// If @p RefAsPointee, references are treated like their underlying type -/// (for alignof), else they're treated like pointers (for CodeGen). -CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { +CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { unsigned Align = Target->getCharWidth(); bool UseAlignAttrOnly = false; @@ -1262,7 +1294,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { - if (RefAsPointee) + if (ForAlignof) T = RT->getPointeeType(); else T = getPointerType(RT->getPointeeType()); @@ -1270,14 +1302,15 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { if (!T->isIncompleteType() && !T->isFunctionType()) { // Adjust alignments of declarations with array type by the // large-array alignment on the target. - unsigned MinWidth = Target->getLargeArrayMinWidth(); - const ArrayType *arrayType; - if (MinWidth && (arrayType = getAsArrayType(T))) { - if (isa<VariableArrayType>(arrayType)) - Align = std::max(Align, Target->getLargeArrayAlign()); - else if (isa<ConstantArrayType>(arrayType) && - MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) - Align = std::max(Align, Target->getLargeArrayAlign()); + if (const ArrayType *arrayType = getAsArrayType(T)) { + unsigned MinWidth = Target->getLargeArrayMinWidth(); + if (!ForAlignof && MinWidth) { + if (isa<VariableArrayType>(arrayType)) + Align = std::max(Align, Target->getLargeArrayAlign()); + else if (isa<ConstantArrayType>(arrayType) && + MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) + Align = std::max(Align, Target->getLargeArrayAlign()); + } // Walk through any array types while we're at it. T = getBaseElementType(arrayType); @@ -1294,24 +1327,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { // a max-field-alignment constraint (#pragma pack). So calculate // the actual alignment of the field within the struct, and then // (as we're expected to) constrain that by the alignment of the type. - if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { - // So calculate the alignment of the field. - const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); - - // Start with the record's overall alignment. - unsigned fieldAlign = toBits(layout.getAlignment()); - - // Use the GCD of that and the offset within the record. - uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); - if (offset > 0) { - // Alignment is always a power of 2, so the GCD will be a power of 2, - // which means we get to do this crazy thing instead of Euclid's. - uint64_t lowBitOfOffset = offset & (~offset + 1); - if (lowBitOfOffset < fieldAlign) - fieldAlign = static_cast<unsigned>(lowBitOfOffset); - } + if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) { + const RecordDecl *Parent = Field->getParent(); + // We can only produce a sensible answer if the record is valid. + if (!Parent->isInvalidDecl()) { + const ASTRecordLayout &Layout = getASTRecordLayout(Parent); + + // Start with the record's overall alignment. + unsigned FieldAlign = toBits(Layout.getAlignment()); + + // Use the GCD of that and the offset within the record. + uint64_t Offset = Layout.getFieldOffset(Field->getFieldIndex()); + if (Offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t LowBitOfOffset = Offset & (~Offset + 1); + if (LowBitOfOffset < FieldAlign) + FieldAlign = static_cast<unsigned>(LowBitOfOffset); + } - Align = std::min(Align, fieldAlign); + Align = std::min(Align, FieldAlign); + } } } @@ -1339,8 +1375,30 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { return sizeAndAlign; } +/// getConstantArrayInfoInChars - Performing the computation in CharUnits +/// instead of in bits prevents overflowing the uint64_t for some large arrays. +std::pair<CharUnits, CharUnits> +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair<CharUnits, CharUnits> EltInfo = + Context.getTypeInfoInChars(CAT->getElementType()); + uint64_t Size = CAT->getSize().getZExtValue(); + assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <= + (uint64_t)(-1)/Size) && + "Overflow in array type char size evaluation"); + uint64_t Width = EltInfo.first.getQuantity() * Size; + unsigned Align = EltInfo.second.getQuantity(); + if (!Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getPointerWidth(0) == 64) + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(CharUnits::fromQuantity(Width), + CharUnits::fromQuantity(Align)); +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair<uint64_t, unsigned> Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); @@ -1376,6 +1434,10 @@ ASTContext::getTypeInfoImpl(const Type *T) const { #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \ + case Type::Class: \ + assert(!T->isDependentType() && "should not see dependent types here"); \ + return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr()); #include "clang/AST/TypeNodes.def" llvm_unreachable("Should not see dependent types"); @@ -1401,7 +1463,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const { "Overflow in array type bit size evaluation"); Width = EltInfo.first*Size; Align = EltInfo.second; - Width = llvm::RoundUpToAlignment(Width, Align); + if (!getTargetInfo().getCXXABI().isMicrosoft() || + getTargetInfo().getPointerWidth(0) == 64) + Width = llvm::RoundUpToAlignment(Width, Align); break; } case Type::ExtVector: @@ -1568,6 +1632,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::ObjCObject: return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr()); + case Type::Decayed: + return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -1624,20 +1690,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const { break; } - case Type::TypeOfExpr: - return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType() - .getTypePtr()); - - case Type::TypeOf: - return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr()); - - case Type::Decltype: - return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType() - .getTypePtr()); - - case Type::UnaryTransform: - return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType()); - case Type::Elaborated: return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); @@ -1645,18 +1697,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const { return getTypeInfo( cast<AttributedType>(T)->getEquivalentType().getTypePtr()); - case Type::TemplateSpecialization: { - assert(getCanonicalType(T) != T && - "Cannot request the size of a dependent type"); - const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); - // A type alias template specialization may refer to a typedef with the - // aligned attribute on it. - if (TST->isTypeAlias()) - return getTypeInfo(TST->getAliasedType().getTypePtr()); - else - return getTypeInfo(getCanonicalType(T)); - } - case Type::Atomic: { // Start with the base type information. std::pair<uint64_t, unsigned> Info @@ -1696,10 +1736,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in @@ -1718,6 +1758,9 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { unsigned ABIAlign = getTypeAlign(T); + if (Target->getTriple().getArch() == llvm::Triple::xcore) + return ABIAlign; // Never overalign on XCore. + // Double and long long should be naturally aligned if possible. if (const ComplexType* CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); @@ -2042,10 +2085,7 @@ 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(), - ArrayRef<QualType>(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI); + Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI); } return cast<FunctionType>(Result.getTypePtr()); @@ -2053,12 +2093,18 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType) { - // FIXME: Need to inform serialization code about this! - for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) { + FD = FD->getMostRecentDecl(); + while (true) { const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI)); + if (FunctionDecl *Next = FD->getPreviousDecl()) + FD = Next; + else + break; } + if (ASTMutationListener *L = getASTMutationListener()) + L->DeducedReturnType(FD, ResultType); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -2117,6 +2163,45 @@ QualType ASTContext::getPointerType(QualType T) const { return QualType(New, 0); } +QualType ASTContext::getDecayedType(QualType T) const { + assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); + + llvm::FoldingSetNodeID ID; + DecayedType::Profile(ID, T); + void *InsertPos = 0; + if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(DT, 0); + + QualType Decayed; + + // C99 6.7.5.3p7: + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) + Decayed = getArrayDecayedType(T); + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) + Decayed = getPointerType(T); + + QualType Canonical = getCanonicalType(Decayed); + + // Get the new insert position for the node we care about. + DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; + + DecayedType *New = + new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); + Types.push_back(New); + DecayedTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) const { @@ -2676,9 +2761,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { - const CallingConv DefaultCC = Info.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; + const CallingConv CallConv = Info.getCC(); + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -2690,11 +2774,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical() || - getCanonicalCallConv(CallConv) != CallConv) { - Canonical = - getFunctionNoProtoType(getCanonicalType(ResultTy), - Info.withCallingConv(getCanonicalCallConv(CallConv))); + if (!ResultTy.isCanonical()) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -2743,14 +2824,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; - const CallingConv DefaultCC = EPI.ExtInfo.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; - // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { + if (!isCanonical) { SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2760,8 +2837,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, CanonicalEPI.HasTrailingReturn = false; CanonicalEPI.ExceptionSpecType = EST_None; CanonicalEPI.NumExceptions = 0; - CanonicalEPI.ExtInfo - = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); // Result types do not have ARC lifetime qualifiers. QualType CanResultTy = getCanonicalType(ResultTy); @@ -2803,7 +2878,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; - newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); @@ -2856,13 +2930,11 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { "Template type parameter types are always available."); if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { - assert(!Record->getPreviousDecl() && - "struct/union has previous declaration"); + assert(Record->isFirstDecl() && "struct/union has previous declaration"); assert(!NeedsInjectedClassNameType(Record)); return getRecordType(Record); } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { - assert(!Enum->getPreviousDecl() && - "enum has previous declaration"); + assert(Enum->isFirstDecl() && "enum has previous declaration"); return getEnumType(Enum); } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { @@ -4104,22 +4176,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } QualType ASTContext::getAdjustedParameterType(QualType T) const { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - if (T->isArrayType()) - return getArrayDecayedType(T); - - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. - if (T->isFunctionType()) - return getPointerType(T); - - return T; + if (T->isArrayType() || T->isFunctionType()) + return getDecayedType(T); + return T; } QualType ASTContext::getSignatureParameterType(QualType T) const { @@ -4364,12 +4423,27 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { return Qualifiers::OCL_None; } +static const Type *getIntegerTypeForEnum(const EnumType *ET) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) + return ET->getDecl()->getIntegerType().getTypePtr(); + return NULL; +} + /// getIntegerTypeOrder - Returns the highest ranked integer type: /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If /// LHS < RHS, return -1. int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const { const Type *LHSC = getCanonicalType(LHS).getTypePtr(); const Type *RHSC = getCanonicalType(RHS).getTypePtr(); + + // Unwrap enums to their underlying type. + if (const EnumType *ET = dyn_cast<EnumType>(LHSC)) + LHSC = getIntegerTypeForEnum(ET); + if (const EnumType *ET = dyn_cast<EnumType>(RHSC)) + RHSC = getIntegerTypeForEnum(ET); + if (LHSC == RHSC) return 0; bool LHSUnsigned = LHSC->isUnsignedIntegerType(); @@ -4484,7 +4558,7 @@ QualType ASTContext::getBlockDescriptorType() const { UnsignedLongTy, }; - const char *FieldNames[] = { + static const char *const FieldNames[] = { "reserved", "Size" }; @@ -4525,7 +4599,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { getPointerType(VoidPtrTy) }; - const char *FieldNames[] = { + static const char *const FieldNames[] = { "reserved", "Size", "CopyFuncPtr", @@ -4910,6 +4984,10 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, if (PD->isReadOnly()) { S += ",R"; + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) + S += ",C"; + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) + S += ",&"; } else { switch (PD->getSetterKind()) { case ObjCPropertyDecl::Assign: break; @@ -5200,12 +5278,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '['; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { - if (getTypeSize(CAT->getElementType()) == 0) - S += '0'; - else - S += llvm::utostr(CAT->getSize().getZExtValue()); - } else { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else { //Variable length arrays are encoded as a regular array with 0 elements. assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) && "Unknown array type!"); @@ -5384,6 +5459,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // We encode the underlying type which comes out as // {...}; S += '^'; + if (FD && OPT->getInterfaceDecl()) { + // Prevent recursive encoding of fields in some rare cases. + ObjCInterfaceDecl *OI = OPT->getInterfaceDecl(); + SmallVector<const ObjCIvarDecl*, 32> Ivars; + DeepCollectObjCIvars(OI, true, Ivars); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { + if (cast<FieldDecl>(Ivars[i]) == FD) { + S += '{'; + S += OI->getIdentifier()->getName(); + S += '}'; + return; + } + } + } getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, NULL, @@ -5484,7 +5573,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (base->isEmpty()) continue; uint64_t offs = toBits(layout.getVBaseClassOffset(base)); - if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end()) + if (offs >= uint64_t(toBits(layout.getNonVirtualSize())) && + FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end()) FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(), std::make_pair(offs, base)); } @@ -6267,6 +6357,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, CanQualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { case TargetInfo::NoInt: return CanQualType(); + case TargetInfo::SignedChar: return SignedCharTy; + case TargetInfo::UnsignedChar: return UnsignedCharTy; case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -6369,15 +6461,6 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, return false; } -/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...> -/// return true if lhs's protocols conform to rhs's protocol; false -/// otherwise. -bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { - if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) - return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); - return false; -} - /// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and /// Class<pr1, ...>. bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, @@ -6890,7 +6973,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); // Compatible functions must have compatible calling conventions - if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC())) + if (lbaseInfo.getCC() != rbaseInfo.getCC()) return QualType(); // Regparm is part of the calling convention. @@ -7000,10 +7083,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); EPI.ExtInfo = einfo; - return getFunctionType(retType, - ArrayRef<QualType>(proto->arg_type_begin(), - proto->getNumArgs()), - EPI); + return getFunctionType(retType, proto->getArgTypes(), EPI); } if (allLTypes) return lhs; @@ -7351,11 +7431,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = getFunctionExtInfo(LHS); - QualType ResultType - = getFunctionType(OldReturnType, - ArrayRef<QualType>(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI); + QualType ResultType = + getFunctionType(OldReturnType, FPT->getArgTypes(), EPI); return ResultType; } } @@ -7407,7 +7484,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) const { - if (const EnumType *ET = dyn_cast<EnumType>(T)) + if (const EnumType *ET = T->getAs<EnumType>()) T = ET->getDecl()->getIntegerType(); if (T->isBooleanType()) return 1; @@ -7450,6 +7527,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { ASTMutationListener::~ASTMutationListener() { } +void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD, + QualType ReturnType) {} //===----------------------------------------------------------------------===// // Builtin Type Computation @@ -7507,6 +7586,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, "Bad modifiers used with 'v'!"); Type = Context.VoidTy; break; + case 'h': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'f'!"); + Type = Context.HalfTy; + break; case 'f': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); @@ -7734,7 +7818,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - FunctionType::ExtInfo EI; + FunctionType::ExtInfo EI(CC_C); if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); bool Variadic = (TypeStr[0] == '.'); @@ -7751,36 +7835,30 @@ QualType ASTContext::GetBuiltinType(unsigned Id, } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { - GVALinkage External = GVA_StrongExternal; - - Linkage L = FD->getLinkage(); - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!FD->isExternallyVisible()) return GVA_Internal; - - case ExternalLinkage: - switch (FD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - External = GVA_StrongExternal; - break; - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + GVALinkage External = GVA_StrongExternal; + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; - case TSK_ExplicitInstantiationDeclaration: - case TSK_ImplicitInstantiation: - External = GVA_TemplateInstantiation; - break; - } + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; } if (!FD->isInlined()) return External; - - if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { + + if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) || + FD->hasAttr<GNUInlineAttr>()) { // GNU or C99 inline semantics. Determine whether this symbol should be // externally visible. if (FD->isInlineDefinitionExternallyVisible()) @@ -7804,37 +7882,23 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { - // If this is a static data member, compute the kind of template - // specialization. Otherwise, this variable is not part of a - // template. - TemplateSpecializationKind TSK = TSK_Undeclared; - if (VD->isStaticDataMember()) - TSK = VD->getTemplateSpecializationKind(); - - Linkage L = VD->getLinkage(); - - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!VD->isExternallyVisible()) return GVA_Internal; - case ExternalLinkage: - switch (TSK) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return GVA_StrongExternal; + switch (VD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; - case TSK_ExplicitInstantiationDeclaration: - llvm_unreachable("Variable should not be instantiated"); - // Fall through to treat this like any other instantiation. - - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. - case TSK_ImplicitInstantiation: - return GVA_TemplateInstantiation; - } + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; } llvm_unreachable("Invalid Linkage!"); @@ -7918,16 +7982,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; } -CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) { +CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, + bool IsCXXMethod) const { // Pass through to the C++ ABI object - return ABI->getDefaultMethodCallConv(isVariadic); -} + if (IsCXXMethod) + return ABI->getDefaultMethodCallConv(IsVariadic); -CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const { - if (CC == CC_C && !LangOpts.MRTD && - getTargetInfo().getCXXABI().isMemberFunctionCCDefault()) - return CC_Default; - return CC; + return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C; } bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { @@ -7941,9 +8002,9 @@ MangleContext *ASTContext::createMangleContext() { case TargetCXXABI::GenericItanium: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: - return createItaniumMangleContext(*this, getDiagnostics()); + return ItaniumMangleContext::create(*this, getDiagnostics()); case TargetCXXABI::Microsoft: - return createMicrosoftMangleContext(*this, getDiagnostics()); + return MicrosoftMangleContext::create(*this, getDiagnostics()); } llvm_unreachable("Unsupported ABI"); } @@ -7951,45 +8012,77 @@ MangleContext *ASTContext::createMangleContext() { CXXABI::~CXXABI() {} size_t ASTContext::getSideTableAllocatedMemory() const { - return ASTRecordLayouts.getMemorySize() - + llvm::capacity_in_bytes(ObjCLayouts) - + llvm::capacity_in_bytes(KeyFunctions) - + llvm::capacity_in_bytes(ObjCImpls) - + llvm::capacity_in_bytes(BlockVarCopyInits) - + llvm::capacity_in_bytes(DeclAttrs) - + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember) - + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) - + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) - + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) - + llvm::capacity_in_bytes(OverriddenMethods) - + llvm::capacity_in_bytes(Types) - + llvm::capacity_in_bytes(VariableArrayTypes) - + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); -} - -void ASTContext::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; + return ASTRecordLayouts.getMemorySize() + + llvm::capacity_in_bytes(ObjCLayouts) + + llvm::capacity_in_bytes(KeyFunctions) + + llvm::capacity_in_bytes(ObjCImpls) + + llvm::capacity_in_bytes(BlockVarCopyInits) + + llvm::capacity_in_bytes(DeclAttrs) + + llvm::capacity_in_bytes(TemplateOrInstantiation) + + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) + + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) + + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + + llvm::capacity_in_bytes(OverriddenMethods) + + llvm::capacity_in_bytes(Types) + + llvm::capacity_in_bytes(VariableArrayTypes) + + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); +} + +/// getIntTypeForBitwidth - +/// sets integer QualTy according to specified details: +/// bitwidth, signed/unsigned. +/// Returns empty type if there is no appropriate target types. +QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth, + unsigned Signed) const { + TargetInfo::IntType Ty = getTargetInfo().getIntTypeByWidth(DestWidth, Signed); + CanQualType QualTy = getFromTargetType(Ty); + if (!QualTy && DestWidth == 128) + return Signed ? Int128Ty : UnsignedInt128Ty; + return QualTy; +} + +/// getRealTypeForBitwidth - +/// sets floating point QualTy according to specified bitwidth. +/// Returns empty type if there is no appropriate target types. +QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const { + TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth); + switch (Ty) { + case TargetInfo::Float: + return FloatTy; + case TargetInfo::Double: + return DoubleTy; + case TargetInfo::LongDouble: + return LongDoubleTy; + case TargetInfo::NoFloat: + return QualType(); + } - 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++)); + llvm_unreachable("Unhandled TargetInfo::RealType value"); } -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; +void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) { + if (Number > 1) + MangleNumbers[ND] = Number; } -unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { - CXXRecordDecl *Lambda = CallOperator->getParent(); - return LambdaMangleContexts[Lambda->getDeclContext()] - .getManglingNumber(CallOperator); +unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const { + llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I = + MangleNumbers.find(ND); + return I != MangleNumbers.end() ? I->second : 1; } +MangleNumberingContext & +ASTContext::getManglingNumberContext(const DeclContext *DC) { + assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. + MangleNumberingContext *&MCtx = MangleNumberingContexts[DC]; + if (!MCtx) + MCtx = createMangleNumberingContext(); + return *MCtx; +} + +MangleNumberingContext *ASTContext::createMangleNumberingContext() const { + return ABI->createMangleNumberingContext(); +} void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; @@ -8001,3 +8094,160 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const { "ParmIndices lacks entry set by ParmVarDecl"); return I->second; } + +APValue * +ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, + bool MayCreate) { + assert(E && E->getStorageDuration() == SD_Static && + "don't need to cache the computed value for this temporary"); + if (MayCreate) + return &MaterializedTemporaryValues[E]; + + llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I = + MaterializedTemporaryValues.find(E); + return I == MaterializedTemporaryValues.end() ? 0 : &I->second; +} + +bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { + const llvm::Triple &T = getTargetInfo().getTriple(); + if (!T.isOSDarwin()) + return false; + + if (!(T.isiOS() && T.isOSVersionLT(7)) && + !(T.isMacOSX() && T.isOSVersionLT(10, 9))) + return false; + + QualType AtomicTy = E->getPtr()->getType()->getPointeeType(); + CharUnits sizeChars = getTypeSizeInChars(AtomicTy); + uint64_t Size = sizeChars.getQuantity(); + CharUnits alignChars = getTypeAlignInChars(AtomicTy); + unsigned Align = alignChars.getQuantity(); + unsigned MaxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth(); + return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits); +} + +namespace { + + /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their + /// parents as defined by the \c RecursiveASTVisitor. + /// + /// Note that the relationship described here is purely in terms of AST + /// traversal - there are other relationships (for example declaration context) + /// in the AST that are better modeled by special matchers. + /// + /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes. + class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> { + + public: + /// \brief Builds and returns the translation unit's parent map. + /// + /// The caller takes ownership of the returned \c ParentMap. + static ASTContext::ParentMap *buildMap(TranslationUnitDecl &TU) { + ParentMapASTVisitor Visitor(new ASTContext::ParentMap); + Visitor.TraverseDecl(&TU); + return Visitor.Parents; + } + + private: + typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase; + + ParentMapASTVisitor(ASTContext::ParentMap *Parents) : Parents(Parents) { + } + + bool shouldVisitTemplateInstantiations() const { + return true; + } + bool shouldVisitImplicitCode() const { + return true; + } + // Disables data recursion. We intercept Traverse* methods in the RAV, which + // are not triggered during data recursion. + bool shouldUseDataRecursionFor(clang::Stmt *S) const { + return false; + } + + template <typename T> + bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) { + if (Node == NULL) + return true; + if (ParentStack.size() > 0) + // FIXME: Currently we add the same parent multiple times, for example + // when we visit all subexpressions of template instantiations; this is + // suboptimal, bug benign: the only way to visit those is with + // hasAncestor / hasParent, and those do not create new matches. + // The plan is to enable DynTypedNode to be storable in a map or hash + // map. The main problem there is to implement hash functions / + // comparison operators for all types that DynTypedNode supports that + // do not have pointer identity. + (*Parents)[Node].push_back(ParentStack.back()); + ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node)); + bool Result = (this ->* traverse) (Node); + ParentStack.pop_back(); + return Result; + } + + bool TraverseDecl(Decl *DeclNode) { + return TraverseNode(DeclNode, &VisitorBase::TraverseDecl); + } + + bool TraverseStmt(Stmt *StmtNode) { + return TraverseNode(StmtNode, &VisitorBase::TraverseStmt); + } + + ASTContext::ParentMap *Parents; + llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack; + + friend class RecursiveASTVisitor<ParentMapASTVisitor>; + }; + +} // end namespace + +ASTContext::ParentVector +ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { + assert(Node.getMemoizationData() && + "Invariant broken: only nodes that support memoization may be " + "used in the parent map."); + if (!AllParents) { + // We always need to run over the whole translation unit, as + // hasAncestor can escape any subtree. + AllParents.reset( + ParentMapASTVisitor::buildMap(*getTranslationUnitDecl())); + } + ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData()); + if (I == AllParents->end()) { + return ParentVector(); + } + return I->second; +} + +bool +ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, + const ObjCMethodDecl *MethodImpl) { + // No point trying to match an unavailable/deprecated mothod. + if (MethodDecl->hasAttr<UnavailableAttr>() + || MethodDecl->hasAttr<DeprecatedAttr>()) + return false; + if (MethodDecl->getObjCDeclQualifier() != + MethodImpl->getObjCDeclQualifier()) + return false; + if (!hasSameType(MethodDecl->getResultType(), + MethodImpl->getResultType())) + return false; + + if (MethodDecl->param_size() != MethodImpl->param_size()) + return false; + + for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(), + IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(), + EF = MethodDecl->param_end(); + IM != EM && IF != EF; ++IM, ++IF) { + const ParmVarDecl *DeclVar = (*IF); + const ParmVarDecl *ImplVar = (*IM); + if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier()) + return false; + if (!hasSameType(DeclVar->getType(), ImplVar->getType())) + return false; + } + return (MethodDecl->isVariadic() == MethodImpl->isVariadic()); + +} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 1ed65e476ce3..fce8f64b3328 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument( assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - N.printName(OS); + OS << DeclarationName::getFromOpaqueInteger(Val); break; } case DiagnosticsEngine::ak_nameddecl: { @@ -459,6 +458,10 @@ class TemplateDiff { /// FromValueDecl, ToValueDecl - Whether the argument is a decl. ValueDecl *FromValueDecl, *ToValueDecl; + /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of + /// operator before it. + bool FromAddressOf, ToAddressOf; + /// FromDefault, ToDefault - Whether the argument is a default argument. bool FromDefault, ToDefault; @@ -469,7 +472,8 @@ class TemplateDiff { : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode), FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0), IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0), - ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { } + ToValueDecl(0), FromAddressOf(false), ToAddressOf(false), + FromDefault(false), ToDefault(false), Same(false) { } }; /// FlatTree - A flattened tree used to store the DiffNodes. @@ -526,9 +530,12 @@ class TemplateDiff { } /// SetNode - Set FromValueDecl and ToValueDecl of the current node. - void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) { + void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, + bool FromAddressOf, bool ToAddressOf) { FlatTree[CurrentNode].FromValueDecl = FromValueDecl; FlatTree[CurrentNode].ToValueDecl = ToValueDecl; + FlatTree[CurrentNode].FromAddressOf = FromAddressOf; + FlatTree[CurrentNode].ToAddressOf = ToAddressOf; } /// SetSame - Sets the same flag of the current node. @@ -620,9 +627,12 @@ class TemplateDiff { } /// GetNode - Gets the FromValueDecl and ToValueDecl. - void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) { + void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl, + bool &FromAddressOf, bool &ToAddressOf) { FromValueDecl = FlatTree[ReadNode].FromValueDecl; ToValueDecl = FlatTree[ReadNode].ToValueDecl; + FromAddressOf = FlatTree[ReadNode].FromAddressOf; + ToAddressOf = FlatTree[ReadNode].ToAddressOf; } /// NodeIsSame - Returns true the arguments are the same. @@ -821,8 +831,10 @@ class TemplateDiff { void DiffTemplate(const TemplateSpecializationType *FromTST, const TemplateSpecializationType *ToTST) { // Begin descent into diffing template tree. - TemplateParameterList *Params = + TemplateParameterList *ParamsFrom = FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); + TemplateParameterList *ParamsTo = + ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); unsigned TotalArgs = 0; for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { @@ -831,15 +843,18 @@ class TemplateDiff { // Get the parameter at index TotalArgs. If index is larger // than the total number of parameters, then there is an // argument pack, so re-use the last parameter. - NamedDecl *ParamND = Params->getParam( - (TotalArgs < Params->size()) ? TotalArgs - : Params->size() - 1); + unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1); + NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex); + // Handle Types if (TemplateTypeParmDecl *DefaultTTPD = dyn_cast<TemplateTypeParmDecl>(ParamND)) { QualType FromType, ToType; FromType = GetType(FromIter, DefaultTTPD); - ToType = GetType(ToIter, DefaultTTPD); + // A forward declaration can have no default arg but the actual class + // can, don't mix up iterators and get the original parameter. + ToType = GetType( + ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex))); Tree.SetNode(FromType, ToType); Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), ToIter.isEnd() && !ToType.isNull()); @@ -942,7 +957,14 @@ class TemplateDiff { FromValueDecl = GetValueDecl(FromIter, FromExpr); if (!HasToValueDecl && ToExpr) ToValueDecl = GetValueDecl(ToIter, ToExpr); - Tree.SetNode(FromValueDecl, ToValueDecl); + QualType ArgumentType = DefaultNTTPD->getType(); + bool FromAddressOf = FromValueDecl && + !ArgumentType->isReferenceType() && + !FromValueDecl->getType()->isArrayType(); + bool ToAddressOf = ToValueDecl && + !ArgumentType->isReferenceType() && + !ToValueDecl->getType()->isArrayType(); + Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); Tree.SetSame(FromValueDecl && ToValueDecl && FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl()); @@ -973,7 +995,7 @@ class TemplateDiff { /// makeTemplateList - Dump every template alias into the vector. static void makeTemplateList( - SmallVector<const TemplateSpecializationType*, 1> &TemplateList, + SmallVectorImpl<const TemplateSpecializationType *> &TemplateList, const TemplateSpecializationType *TST) { while (TST) { TemplateList.push_back(TST); @@ -1008,7 +1030,7 @@ class TemplateDiff { makeTemplateList(FromTemplateList, FromTST); makeTemplateList(ToTemplateList, ToTST); - SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator + SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); @@ -1037,10 +1059,14 @@ class TemplateDiff { if (!Iter.isEnd()) return Iter->getAsType(); - if (!isVariadic) - return DefaultTTPD->getDefaultArgument(); + if (isVariadic) + return QualType(); + + QualType ArgType = DefaultTTPD->getDefaultArgument(); + if (ArgType->isDependentType()) + return Iter.getDesugar().getAsType(); - return QualType(); + return ArgType; } /// GetExpr - Retrieves the template expression argument, including default @@ -1080,7 +1106,7 @@ class TemplateDiff { return ArgExpr->EvaluateKnownConstInt(Context); } - /// GetValueDecl - Retrieves the template integer argument, including + /// GetValueDecl - Retrieves the template Decl argument, including /// default expression argument. ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { // Default, value-depenedent expressions require fetching @@ -1095,7 +1121,12 @@ class TemplateDiff { default: assert(0 && "Unexpected template argument kind"); } - return cast<DeclRefExpr>(ArgExpr)->getDecl(); + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr); + if (!DRE) { + DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr()); + } + + return DRE->getDecl(); } /// GetTemplateDecl - Retrieves the template template arguments, including @@ -1228,9 +1259,10 @@ class TemplateDiff { } case DiffTree::Declaration: { ValueDecl *FromValueDecl, *ToValueDecl; - Tree.GetNode(FromValueDecl, ToValueDecl); - PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(), - Tree.ToDefault(), Tree.NodeIsSame()); + bool FromAddressOf, ToAddressOf; + Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); + PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, + Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } case DiffTree::Template: { @@ -1478,7 +1510,8 @@ class TemplateDiff { /// PrintDecl - Handles printing of Decl arguments, highlighting /// argument differences. void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, - bool FromDefault, bool ToDefault, bool Same) { + bool FromAddressOf, bool ToAddressOf, bool FromDefault, + bool ToDefault, bool Same) { assert((FromValueDecl || ToValueDecl) && "Only one Decl argument may be NULL"); @@ -1487,15 +1520,21 @@ class TemplateDiff { } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); Bold(); + if (FromAddressOf) + OS << "&"; OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); } else { OS << (FromDefault ? "[(default) " : "["); Bold(); + if (FromAddressOf) + OS << "&"; OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); OS << " != " << (ToDefault ? "(default) " : ""); Bold(); + if (ToAddressOf) + OS << "&"; OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)"); Unbold(); OS << ']'; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 340cc41f7e81..2f402559f4da 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" @@ -62,6 +63,9 @@ namespace { // Null statements static const TerminalColor NullColor = { raw_ostream::BLUE, false }; + // Undeserialized entities + static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; + // CastKind from CastExpr's static const TerminalColor CastColor = { raw_ostream::RED, false }; @@ -173,6 +177,7 @@ namespace { void dumpName(const NamedDecl *D); bool hasNodes(const DeclContext *DC); void dumpDeclContext(const DeclContext *DC); + void dumpLookups(const DeclContext *DC); void dumpAttr(const Attr *A); // C++ Utilities @@ -214,6 +219,11 @@ namespace { const ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D); + void VisitVarTemplateDecl(const VarTemplateDecl *D); + void VisitVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *D); + void VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); @@ -244,6 +254,7 @@ namespace { void VisitAttributedStmt(const AttributedStmt *Node); void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); + void VisitCXXCatchStmt(const CXXCatchStmt *Node); // Exprs void VisitExpr(const Expr *Node); @@ -271,9 +282,14 @@ namespace { void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); void dumpCXXTemporary(const CXXTemporary *Temporary); + void VisitLambdaExpr(const LambdaExpr *Node) { + VisitExpr(Node); + dumpDecl(Node->getLambdaClass()); + } // ObjC void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); @@ -329,8 +345,8 @@ void ASTDumper::indent() { OS << "\n"; ColorScope Color(*this, IndentColor); - for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(), - E = Indents.end(); + for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(), + E = Indents.end(); I != E; ++I) { switch (*I) { case IT_Child: @@ -449,9 +465,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { ColorScope Color(*this, DeclNameColor); - OS << " '"; - ND->getDeclName().printName(OS); - OS << "'"; + OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) @@ -479,20 +493,76 @@ bool ASTDumper::hasNodes(const DeclContext *DC) { if (!DC) return false; - return DC->decls_begin() != DC->decls_end(); + return DC->hasExternalLexicalStorage() || + DC->noload_decls_begin() != DC->noload_decls_end(); } void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + bool HasUndeserializedDecls = DC->hasExternalLexicalStorage(); + for (DeclContext::decl_iterator I = DC->noload_decls_begin(), + E = DC->noload_decls_end(); I != E; ++I) { DeclContext::decl_iterator Next = I; ++Next; - if (Next == E) + if (Next == E && !HasUndeserializedDecls) lastChild(); dumpDecl(*I); } + if (HasUndeserializedDecls) { + lastChild(); + IndentScope Indent(*this); + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized declarations>"; + } +} + +void ASTDumper::dumpLookups(const DeclContext *DC) { + IndentScope Indent(*this); + + OS << "StoredDeclsMap "; + dumpBareDeclRef(cast<Decl>(DC)); + + const DeclContext *Primary = DC->getPrimaryContext(); + if (Primary != DC) { + OS << " primary"; + dumpPointer(cast<Decl>(Primary)); + } + + bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); + + DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(), + E = Primary->noload_lookups_end(); + while (I != E) { + DeclarationName Name = I.getLookupName(); + DeclContextLookupResult R = *I++; + if (I == E && !HasUndeserializedLookups) + lastChild(); + + IndentScope Indent(*this); + OS << "DeclarationName "; + { + ColorScope Color(*this, DeclNameColor); + OS << '\'' << Name << '\''; + } + + for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); + RI != RE; ++RI) { + if (RI + 1 == RE) + lastChild(); + dumpDeclRef(*RI); + if ((*RI)->isHidden()) + OS << " hidden"; + } + } + + if (HasUndeserializedLookups) { + lastChild(); + IndentScope Indent(*this); + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized lookups>"; + } } void ASTDumper::dumpAttr(const Attr *A) { @@ -511,21 +581,29 @@ void ASTDumper::dumpAttr(const Attr *A) { #include "clang/AST/AttrDump.inc" } -static Decl *getPreviousDeclImpl(...) { - return 0; +static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {} + +template<typename T> +static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) { + const T *First = D->getFirstDecl(); + if (First != D) + OS << " first " << First; } template<typename T> -static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) { - return D->getPreviousDecl(); +static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) { + const T *Prev = D->getPreviousDecl(); + if (Prev) + OS << " prev " << Prev; } -/// Get the previous declaration in the redeclaration chain for a declaration. -static const Decl *getPreviousDecl(const Decl *D) { +/// Dump the previous declaration in the redeclaration chain for a declaration, +/// if any. +static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) { switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ - return getPreviousDeclImpl(cast<DERIVED##Decl>(D)); + return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D)); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } @@ -662,20 +740,25 @@ void ASTDumper::dumpDecl(const Decl *D) { dumpPointer(D); if (D->getLexicalDeclContext() != D->getDeclContext()) OS << " parent " << cast<Decl>(D->getDeclContext()); - if (const Decl *Prev = getPreviousDecl(D)) - OS << " prev " << Prev; + dumpPreviousDecl(OS, D); dumpSourceRange(D->getSourceRange()); + if (Module *M = D->getOwningModule()) + OS << " in " << M->getFullModuleName(); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (ND->isHidden()) + OS << " hidden"; bool HasAttrs = D->attr_begin() != D->attr_end(); - bool HasComment = D->getASTContext().getCommentForDecl(D, 0); + const FullComment *Comment = + D->getASTContext().getLocalCommentForDeclUncached(D); // 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); + setMoreChildren(HasAttrs || Comment || HasDeclContext); ConstDeclVisitor<ASTDumper>::Visit(D); - setMoreChildren(HasComment || HasDeclContext); + setMoreChildren(Comment || HasDeclContext); for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; ++I) { if (I + 1 == E) @@ -685,7 +768,10 @@ void ASTDumper::dumpDecl(const Decl *D) { setMoreChildren(HasDeclContext); lastChild(); - dumpFullComment(D->getASTContext().getCommentForDecl(D, 0)); + dumpFullComment(Comment); + + if (D->isInvalidDecl()) + OS << " invalid"; setMoreChildren(false); if (HasDeclContext) @@ -722,6 +808,8 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) { dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isCompleteDefinition()) + OS << " definition"; } void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { @@ -764,6 +852,19 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { else if (D->isDeletedAsWritten()) OS << " delete"; + if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + switch (EPI.ExceptionSpecType) { + default: break; + case EST_Unevaluated: + OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl; + break; + case EST_Uninstantiated: + OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate; + break; + } + } + bool OldMoreChildren = hasMoreChildren(); const FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo(); @@ -1012,6 +1113,49 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl( dumpTemplateArgumentListInfo(D->templateArgs()); } +void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + + VarTemplateDecl::spec_iterator I = D->spec_begin(); + VarTemplateDecl::spec_iterator E = D->spec_end(); + if (I == E) + lastChild(); + dumpDecl(D->getTemplatedDecl()); + for (; I != E; ++I) { + VarTemplateDecl::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::VisitVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *D) { + dumpTemplateArgumentList(D->getTemplateArgs()); + VisitVarDecl(D); +} + +void ASTDumper::VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *D) { + dumpTemplateParameters(D->getTemplateParameters()); + VisitVarTemplateSpecializationDecl(D); +} + void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->wasDeclaredWithTypename()) OS << " typename"; @@ -1097,6 +1241,8 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { dumpType(D->getType()); if (D->getSynthesize()) OS << " synthesize"; + if (D->getBackingIvarReferencedInAccessor()) + OS << " BackingIvarReferencedInAccessor"; switch (D->getAccessControl()) { case ObjCIvarDecl::None: @@ -1331,7 +1477,7 @@ void ASTDumper::dumpStmt(const Stmt *S) { return; } - setMoreChildren(S->children()); + setMoreChildren(!S->children().empty()); ConstStmtVisitor<ASTDumper>::Visit(S); setMoreChildren(false); for (Stmt::const_child_range CI = S->children(); CI; ++CI) { @@ -1385,6 +1531,11 @@ void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { dumpPointer(Node->getLabel()); } +void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { + VisitStmt(Node); + dumpDecl(Node->getExceptionDecl()); +} + //===----------------------------------------------------------------------===// // Expr dumping methods. //===----------------------------------------------------------------------===// @@ -1510,6 +1661,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { default: llvm_unreachable("unknown case"); case PredefinedExpr::Func: OS << " __func__"; break; case PredefinedExpr::Function: OS << " __FUNCTION__"; break; + case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break; case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break; case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; } @@ -1659,6 +1811,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { dumpCXXTemporary(Node->getTemporary()); } +void +ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) { + VisitExpr(Node); + if (const ValueDecl *VD = Node->getExtendingDecl()) { + OS << " extended by "; + dumpBareDeclRef(VD); + } +} + void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { VisitExpr(Node); for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) @@ -1949,6 +2110,20 @@ void Decl::dumpColor() const { &getASTContext().getSourceManager(), /*ShowColors*/true); P.dumpDecl(this); } + +void DeclContext::dumpLookups() const { + dumpLookups(llvm::errs()); +} + +void DeclContext::dumpLookups(raw_ostream &OS) const { + const DeclContext *DC = this; + while (!DC->isTranslationUnit()) + DC = DC->getParent(); + ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); + ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager()); + P.dumpLookups(this); +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 915eb6feb85e..e16015b7c4ed 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -106,6 +106,8 @@ namespace clang { bool ImportDefinition(RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind = IDK_Default); + bool ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, @@ -120,9 +122,12 @@ namespace clang { SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); + bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); + bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); @@ -157,7 +162,9 @@ namespace clang { Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); - + Decl *VisitVarTemplateDecl(VarTemplateDecl *D); + Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + // Importing statements Stmt *VisitStmt(Stmt *S); @@ -400,6 +407,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast<DecayedType>(T1)->getPointeeType(), + cast<DecayedType>(T2)->getPointeeType())) + return false; + break; + case Type::Pointer: if (!IsStructurallyEquivalent(Context, cast<PointerType>(T1)->getPointeeType(), @@ -1695,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), + /*IsDependent*/false); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { @@ -1968,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, = FromData.HasDeclaredCopyConstructorWithConstParam; ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; - ToData.FailedImplicitMoveConstructor - = FromData.FailedImplicitMoveConstructor; - ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment; ToData.IsLambda = FromData.IsLambda; SmallVector<CXXBaseSpecifier *, 4> Bases; @@ -2010,6 +2022,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, return false; } +bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind) { + if (To->getDefinition()) + return false; + + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return false; +} + bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { @@ -2148,13 +2175,30 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { + // Eliminate a potential failure point where we attempt to re-import + // something we're trying to import while completing ToRecord. + Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord); + if (ToOrigin) { + RecordDecl *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin); + if (ToOriginRecord) + ToRecord = ToOriginRecord; + } + StructuralEquivalenceContext Ctx(Importer.getFromContext(), - Importer.getToContext(), + ToRecord->getASTContext(), Importer.getNonEquivalentDecls(), false, Complain); return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } +bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), false, Complain); + return Ctx.IsStructurallyEquivalent(FromVar, ToVar); +} + bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), @@ -2181,6 +2225,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, return Ctx.IsStructurallyEquivalent(From, To); } +bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, + VarTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(From, To); +} + Decl *ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); @@ -2610,8 +2662,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { - if (isExternalLinkage(FoundFunction->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { // FIXME: Actually try to merge the body and other attributes. @@ -2664,10 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { FromEPI.NoexceptExpr) { FunctionProtoType::ExtProtoInfo DefaultEPI; FromTy = Importer.getFromContext().getFunctionType( - FromFPT->getResultType(), - ArrayRef<QualType>(FromFPT->arg_type_begin(), - FromFPT->getNumArgs()), - DefaultEPI); + FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI); usedDifferentExceptionSpec = true; } } @@ -2878,7 +2927,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), - Name)) { + !Name.isEmpty())) { Importer.Imported(D, FoundField); return FoundField; } @@ -2965,7 +3014,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getAccessControl(), - BitWidth, D->getSynthesize()); + BitWidth, D->getSynthesize(), + D->getBackingIvarReferencedInAccessor()); ToIvar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToIvar); LexicalDC->addDeclInternal(ToIvar); @@ -2995,8 +3045,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. - if (isExternalLinkage(FoundVar->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundVar->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; @@ -3088,13 +3138,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { LexicalDC->addDeclInternal(ToVar); // Merge the initializer. - // FIXME: Can we really import any initializer? Alternatively, we could force - // ourselves to import every declaration of a variable and then only use - // getInit() here. - ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + if (ImportDefinition(D, ToVar)) + return 0; - // FIXME: Other bits to merge? - return ToVar; } @@ -4108,6 +4154,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( return D2; } +Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { + // If this variable has a definition in the translation unit we're coming + // from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = + cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this variable template. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // We may already have a template of the same name; try to find and match it. + assert(!DC->isFunctionOrMethod() && + "Variable templates cannot be declared at function scope"); + SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = FoundDecls[I]; + if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The variable templates structurally match; call it the same template. + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(FoundDecls[I]); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + + VarDecl *DTemplated = D->getTemplatedDecl(); + + // Import the type. + QualType T = Importer.Import(DTemplated->getType()); + if (T.isNull()) + return 0; + + // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); + TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo()); + VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc, + IdLoc, Name.getAsIdentifierInfo(), T, + TInfo, DTemplated->getStorageClass()); + D2Templated->setAccess(DTemplated->getAccess()); + D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); + D2Templated->setLexicalDeclContext(LexicalDC); + + // Importer.Imported(DTemplated, D2Templated); + // LexicalDC->addDeclInternal(D2Templated); + + // Merge the initializer. + if (ImportDefinition(DTemplated, D2Templated)) + return 0; + + // Create the variable template declaration itself. + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + VarTemplateDecl *D2 = VarTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedVarTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + + // Note the relationship between the variable templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isThisDeclarationADefinition() && + !D2Templated->isThisDeclarationADefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>( + Importer.Import(D->getSpecializedTemplate())); + if (!VarTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = VarTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); + + // Import template arguments. + SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( + TemplateArgs.data(), TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a variable template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (VarDecl *FoundDef = D2->getDefinition()) { + if (!D->isThisDeclarationADefinition() || + IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // variable. + return Importer.Imported(D, FoundDef); + } + } + } else { + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + + // Create a new specialization. + D2 = VarTemplateSpecializationDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size()); + D2->setSpecializationKind(D->getSpecializationKind()); + D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + + // Add this specialization to the class template. + VarTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + } + Importer.Imported(D, D2); + + if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- @@ -4406,7 +4651,7 @@ Decl *ASTImporter::Import(Decl *FromD) { } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) { // When we've finished transforming a typedef, see whether it was the // typedef for an anonymous tag. - for (SmallVector<TagDecl *, 4>::iterator + for (SmallVectorImpl<TagDecl *>::iterator FromTag = AnonTagsWithPendingTypedefs.begin(), FromTagEnd = AnonTagsWithPendingTypedefs.end(); FromTag != FromTagEnd; ++FromTag) { diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp new file mode 100644 index 000000000000..ae47ea98882b --- /dev/null +++ b/lib/AST/ASTTypeTraits.cpp @@ -0,0 +1,105 @@ +//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides a dynamic type identifier and a dynamically typed node container +// that can be used to store an AST base node at runtime in the same storage in +// a type safe way. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { +namespace ast_type_traits { + +const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { + { NKI_None, "<None>" }, + { NKI_None, "CXXCtorInitializer" }, + { NKI_None, "TemplateArgument" }, + { NKI_None, "NestedNameSpecifier" }, + { NKI_None, "NestedNameSpecifierLoc" }, + { NKI_None, "QualType" }, + { NKI_None, "TypeLoc" }, + { NKI_None, "Decl" }, +#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" }, +#include "clang/AST/DeclNodes.inc" + { NKI_None, "Stmt" }, +#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED }, +#include "clang/AST/StmtNodes.inc" + { NKI_None, "Type" }, +#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" }, +#include "clang/AST/TypeNodes.def" +}; + +bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const { + return isBaseOf(KindId, Other.KindId); +} + +bool ASTNodeKind::isSame(ASTNodeKind Other) const { + return KindId != NKI_None && KindId == Other.KindId; +} + +bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) { + if (Base == NKI_None || Derived == NKI_None) return false; + while (Derived != Base && Derived != NKI_None) + Derived = AllKindInfo[Derived].ParentId; + return Derived == Base; +} + +StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; } + +void DynTypedNode::print(llvm::raw_ostream &OS, + const PrintingPolicy &PP) const { + if (const TemplateArgument *TA = get<TemplateArgument>()) + TA->print(PP, OS); + else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>()) + NNS->print(OS, PP); + else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) + NNSL->getNestedNameSpecifier()->print(OS, PP); + else if (const QualType *QT = get<QualType>()) + QT->print(OS, PP); + else if (const TypeLoc *TL = get<TypeLoc>()) + TL->getType().print(OS, PP); + else if (const Decl *D = get<Decl>()) + D->print(OS, PP); + else if (const Stmt *S = get<Stmt>()) + S->printPretty(OS, 0, PP); + else if (const Type *T = get<Type>()) + QualType(T, 0).print(OS, PP); + else + OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n"; +} + +void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const { + if (const Decl *D = get<Decl>()) + D->dump(OS); + else if (const Stmt *S = get<Stmt>()) + S->dump(OS, SM); + else + OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n"; +} + +SourceRange DynTypedNode::getSourceRange() const { + if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>()) + return CCI->getSourceRange(); + if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) + return NNSL->getSourceRange(); + if (const TypeLoc *TL = get<TypeLoc>()) + return TL->getSourceRange(); + if (const Decl *D = get<Decl>()) + return D->getSourceRange(); + if (const Stmt *S = get<Stmt>()) + return S->getSourceRange(); + return SourceRange(); +} + +} // end namespace ast_type_traits +} // end namespace clang diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index daf65e56bdc6..7af3c8b16263 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; Attr::~Attr() { } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index e804fe720558..461e8b3ac18e 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangAST ASTDiagnostic.cpp ASTDumper.cpp ASTImporter.cpp + ASTTypeTraits.cpp AttrImpl.cpp CXXInheritance.cpp Comment.cpp @@ -25,7 +26,6 @@ add_clang_library(clangAST DeclOpenMP.cpp DeclPrinter.cpp DeclTemplate.cpp - DumpXML.cpp Expr.cpp ExprClassification.cpp ExprConstant.cpp @@ -34,8 +34,8 @@ add_clang_library(clangAST InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp - LambdaMangleContext.cpp Mangle.cpp + MangleNumberingContext.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp NestedNameSpecifier.cpp diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 6d67d9a12b55..89203f18ca77 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class MemberPointerType; +class MangleNumberingContext; /// Implements C++ ABI-specific semantic analysis functions. class CXXABI { @@ -34,9 +35,12 @@ public: /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; - // Returns whether the given class is nearly empty, with just virtual pointers - // and no data except possibly virtual bases. + /// Returns whether the given class is nearly empty, with just virtual + /// pointers and no data except possibly virtual bases. virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; + + /// Returns a new mangling number context for this C++ ABI. + virtual MangleNumberingContext *createMangleNumberingContext() const = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 0e0b35d92adf..b51014b7428f 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -168,9 +168,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, } } - if (Queue.empty()) break; - Record = Queue.back(); // not actually a queue. - Queue.pop_back(); + if (Queue.empty()) + break; + Record = Queue.pop_back_val(); // not actually a queue. } return AllMatches; @@ -447,7 +447,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { - SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides + SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides = Overrides[OverriddenSubobject]; if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), Overriding) == SubobjectOverrides.end()) @@ -650,11 +650,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { SOEnd = OM->second.end(); SO != SOEnd; ++SO) { - SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; + SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second; if (Overriding.size() < 2) continue; - for (SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVectorImpl<UniqueVirtualMethod>::iterator Pos = Overriding.begin(), PosEnd = Overriding.end(); Pos != PosEnd; /* increment in loop */) { @@ -669,7 +669,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { // in a base class subobject that hides the virtual base class // subobject. bool Hidden = false; - for (SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVectorImpl<UniqueVirtualMethod>::iterator OP = Overriding.begin(), OPEnd = Overriding.end(); OP != OPEnd && !Hidden; ++OP) { diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 68c73fd48e3c..f24a23d34c57 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/CharInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -41,14 +42,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) { return good(); } +LLVM_ATTRIBUTE_UNUSED static inline bad implements_child_begin_end( Comment::child_iterator (Comment::*)() const) { return bad(); } #define ASSERT_IMPLEMENTS_child_begin(function) \ - (void) sizeof(good(implements_child_begin_end(function))) + (void) good(implements_child_begin_end(function)) +LLVM_ATTRIBUTE_UNUSED static inline void CheckCommentASTNodes() { #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ @@ -94,9 +97,7 @@ Comment::child_iterator Comment::child_end() const { bool TextComment::isWhitespaceNoCache() const { for (StringRef::const_iterator I = Text.begin(), E = Text.end(); I != E; ++I) { - const char C = *I; - if (C != ' ' && C != '\n' && C != '\r' && - C != '\t' && C != '\f' && C != '\v') + if (!clang::isWhitespace(*I)) return false; } return true; @@ -293,12 +294,14 @@ void DeclInfo::fill() { StringRef ParamCommandComment::getParamName(const FullComment *FC) const { assert(isParamIndexValid()); - return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName(); + if (isVarArgParam()) + return "..."; + return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); } StringRef TParamCommandComment::getParamName(const FullComment *FC) const { assert(isPositionValid()); - const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters; + const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; for (unsigned i = 0, e = getDepth(); i != e; ++i) { if (i == e-1) return TPL->getParam(getIndex(i))->getName(); diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index e24d542c9623..01bd12e5fefa 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -43,6 +43,49 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { return getRegisteredCommandInfo(CommandID); } +static void +HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand, + StringRef Typo, const CommandInfo *Command) { + const unsigned MaxEditDistance = 1; + unsigned BestEditDistance = MaxEditDistance + 1; + StringRef Name = Command->Name; + + unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); + if (MinPossibleEditDistance > 0 && + Typo.size() / MinPossibleEditDistance < 1) + return; + unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); + if (EditDistance > MaxEditDistance) + return; + if (EditDistance == BestEditDistance) + BestCommand.push_back(Command); + else if (EditDistance < BestEditDistance) { + BestCommand.clear(); + BestCommand.push_back(Command); + BestEditDistance = EditDistance; + } +} + +const CommandInfo * +CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const { + // single character command impostures, such as \t or \n must not go + // through the fixit logic. + if (Typo.size() <= 1) + return NULL; + + SmallVector<const CommandInfo *, 2> BestCommand; + + const int NumOfCommands = llvm::array_lengthof(Commands); + for (int i = 0; i < NumOfCommands; i++) + HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]); + + for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) + if (!RegisteredCommands[i]->IsUnknownCommand) + HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]); + + return (BestCommand.size() != 1) ? NULL : BestCommand[0]; +} + CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) { char *Name = Allocator.Allocate<char>(CommandName.size() + 1); memcpy(Name, CommandName.data(), CommandName.size()); diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 70410d61085d..01ed3ce80a66 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -157,7 +157,7 @@ const char *skipDecimalCharacterReference(const char *BufferPtr, } const char *skipHexCharacterReference(const char *BufferPtr, - const char *BufferEnd) { + const char *BufferEnd) { for ( ; BufferPtr != BufferEnd; ++BufferPtr) { if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr)) return BufferPtr; @@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) { } llvm_unreachable("buffer end hit before '*/' was seen"); } + } // unnamed namespace void Lexer::lexCommentText(Token &T) { @@ -352,10 +353,20 @@ void Lexer::lexCommentText(Token &T) { const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); if (!Info) { - formTokenWithChars(T, TokenPtr, tok::unknown_command); - T.setUnknownCommandName(CommandName); - Diag(T.getLocation(), diag::warn_unknown_comment_command_name); - return; + if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) { + StringRef CorrectedName = Info->Name; + SourceLocation Loc = getSourceLocation(BufferPtr); + SourceRange CommandRange(Loc.getLocWithOffset(1), + getSourceLocation(TokenPtr)); + Diag(Loc, diag::warn_correct_comment_command_name) + << CommandName << CorrectedName + << FixItHint::CreateReplacement(CommandRange, CorrectedName); + } else { + formTokenWithChars(T, TokenPtr, tok::unknown_command); + T.setUnknownCommandName(CommandName); + Diag(T.getLocation(), diag::warn_unknown_comment_command_name); + return; + } } if (Info->IsVerbatimBlockCommand) { setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index d89c79b3d93d..03e01015b954 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -16,6 +16,15 @@ #include "llvm/Support/ErrorHandling.h" namespace clang { + +static inline bool isWhitespace(llvm::StringRef S) { + for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) { + if (!isWhitespace(*I)) + return false; + } + return true; +} + namespace comments { /// Re-lexes a sequence of tok::text tokens. @@ -594,6 +603,18 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { consumeToken(); break; // Two newlines -- end of paragraph. } + // Also allow [tok::newline, tok::text, tok::newline] if the middle + // tok::text is just whitespace. + if (Tok.is(tok::text) && isWhitespace(Tok.getText())) { + Token WhitespaceTok = Tok; + consumeToken(); + if (Tok.is(tok::newline) || Tok.is(tok::eof)) { + consumeToken(); + break; + } + // We have [tok::newline, tok::text, non-newline]. Put back tok::text. + putBack(WhitespaceTok); + } if (Content.size() > 0) Content.back()->addTrailingNewline(); continue; diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index e0138d5f3f27..1c6222f9ec02 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -29,8 +29,7 @@ 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), - HeaderfileCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_function: - DiagSelect = !isAnyFunctionDecl() ? 1 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; break; case CommandTraits::KCI_functiongroup: - DiagSelect = !isAnyFunctionDecl() ? 2 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; break; case CommandTraits::KCI_method: DiagSelect = !isObjCMethodDecl() ? 3 : 0; @@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_class: - DiagSelect = !isClassOrStructDecl() ? 1 : 0; + DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; + // Allow @class command on @interface declarations. + // FIXME. Currently, \class and @class are indistinguishable. So, + // \class is also allowed on an @interface declaration + if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) + DiagSelect = 0; break; case CommandTraits::KCI_interface: DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; @@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) { << Comment->getSourceRange(); } +/// \brief Turn a string into the corresponding PassDirection or -1 if it's not +/// valid. +static int getParamPassDirection(StringRef Arg) { + return llvm::StringSwitch<int>(Arg) + .Case("[in]", ParamCommandComment::In) + .Case("[out]", ParamCommandComment::Out) + .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) + .Default(-1); +} + void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { - ParamCommandComment::PassDirection Direction; std::string ArgLower = Arg.lower(); - // TODO: optimize: lower Name first (need an API in SmallString for that), - // after that StringSwitch. - if (ArgLower == "[in]") - Direction = ParamCommandComment::In; - else if (ArgLower == "[out]") - Direction = ParamCommandComment::Out; - else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") - Direction = ParamCommandComment::InOut; - else { - // Remove spaces. - std::string::iterator O = ArgLower.begin(); - for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end(); - I != E; ++I) { - const char C = *I; - if (C != ' ' && C != '\n' && C != '\r' && - C != '\t' && C != '\v' && C != '\f') - *O++ = C; - } - ArgLower.resize(O - ArgLower.begin()); - - bool RemovingWhitespaceHelped = false; - if (ArgLower == "[in]") { - Direction = ParamCommandComment::In; - RemovingWhitespaceHelped = true; - } else if (ArgLower == "[out]") { - Direction = ParamCommandComment::Out; - RemovingWhitespaceHelped = true; - } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") { - Direction = ParamCommandComment::InOut; - RemovingWhitespaceHelped = true; - } else { - Direction = ParamCommandComment::In; - RemovingWhitespaceHelped = false; - } + int Direction = getParamPassDirection(ArgLower); + + if (Direction == -1) { + // Try again with whitespace removed. + ArgLower.erase( + std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), + ArgLower.end()); + Direction = getParamPassDirection(ArgLower); SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - if (RemovingWhitespaceHelped) + if (Direction != -1) { + const char *FixedName = ParamCommandComment::getDirectionAsString( + (ParamCommandComment::PassDirection)Direction); Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) - << ArgRange - << FixItHint::CreateReplacement( - ArgRange, - ParamCommandComment::getDirectionAsString(Direction)); - else - Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) - << ArgRange; + << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); + } else { + Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; + Direction = ParamCommandComment::In; // Sane fall back. + } } - Command->setDirection(Direction, /* Explicit = */ true); + Command->setDirection((ParamCommandComment::PassDirection)Direction, + /*Explicit=*/true); } void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, @@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, SmallVector<unsigned, 2> Position; if (resolveTParamReference(Arg, TemplateParameters, &Position)) { Command->setPosition(copyArray(llvm::makeArrayRef(Position))); - llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt = - TemplateParameterDocs.find(Arg); - if (PrevCommandIt != TemplateParameterDocs.end()) { + TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; + if (PrevCommand) { SourceRange ArgRange(ArgLocBegin, ArgLocEnd); Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) << Arg << ArgRange; - TParamCommandComment *PrevCommand = PrevCommandIt->second; Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) << PrevCommand->getParamNameRange(); } - TemplateParameterDocs[Arg] = Command; + PrevCommand = Command; return; } @@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, } while (!HTMLOpenTags.empty()) { - const HTMLStartTagComment *HST = HTMLOpenTags.back(); - HTMLOpenTags.pop_back(); + const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); StringRef LastNotClosedTagName = HST->getTagName(); if (LastNotClosedTagName == TagName) break; @@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { return; } PrevCommand = BriefCommand; - } else if (Info->IsReturnsCommand) { - if (!ReturnsCommand) { - ReturnsCommand = Command; - return; - } - PrevCommand = ReturnsCommand; } else if (Info->IsHeaderfileCommand) { if (!HeaderfileCommand) { HeaderfileCommand = Command; @@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { // Check that referenced parameter name is in the function decl. const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, ParamVars); + if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { + PCC->setIsVarArgParam(); + continue; + } if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { UnresolvedParamCommands.push_back(PCC); continue; @@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() { return isFunctionDecl() && ThisDeclInfo->CurrentDecl && isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); } - + +bool Sema::isFunctionOrMethodVariadic() { + if (!isAnyFunctionDecl() && !isObjCMethodDecl()) + return false; + if (const FunctionDecl *FD = + dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) + return FD->isVariadic(); + if (const ObjCMethodDecl *MD = + dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) + return MD->isVariadic(); + return false; +} + 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; @@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() { isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && !isUnionDecl(); } + +bool Sema::isClassTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} + +bool Sema::isFunctionTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} bool Sema::isObjCInterfaceDecl() { if (!ThisDeclInfo) @@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name, if (II && II->getName() == Name) return i; } + if (Name == "..." && isFunctionOrMethodVariadic()) + return ParamCommandComment::VarArgParamIndex; return ParamCommandComment::InvalidParamIndex; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ab9d73b9178e..6bd985851a39 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -34,6 +34,10 @@ using namespace clang; +Decl *clang::getPrimaryMergedDecl(Decl *D) { + return D->getASTContext().getPrimaryMergedDecl(D); +} + //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// @@ -85,6 +89,7 @@ using namespace clang; // and settings from the immediate context. const unsigned IgnoreExplicitVisibilityBit = 2; +const unsigned IgnoreAllVisibilityBit = 4; /// Kinds of LV computation. The linkage side of the computation is /// always the same, but different things can change how visibility is @@ -108,7 +113,11 @@ enum LVComputationKind { /// 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) + LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), + + /// Do an LV computation when we only care about the linkage. + LVForLinkageOnly = + LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit }; /// Does this computation kind permit us to consider additional @@ -211,11 +220,19 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D, return None; } +static LinkageInfo +getLVForType(const Type &T, LVComputationKind computation) { + if (computation == LVForLinkageOnly) + return LinkageInfo(T.getLinkage(), DefaultVisibility, true); + return T.getLinkageAndVisibility(); +} + /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. For visibility purposes, template /// parameters are part of the signature of a template. static LinkageInfo -getLVForTemplateParameterList(const TemplateParameterList *params) { +getLVForTemplateParameterList(const TemplateParameterList *params, + LVComputationKind computation) { LinkageInfo LV; for (TemplateParameterList::const_iterator P = params->begin(), PEnd = params->end(); @@ -234,7 +251,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { // Handle the non-pack case first. if (!NTTP->isExpandedParameterPack()) { if (!NTTP->getType()->isDependentType()) { - LV.merge(NTTP->getType()->getLinkageAndVisibility()); + LV.merge(getLVForType(*NTTP->getType(), computation)); } continue; } @@ -254,7 +271,8 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { // Handle the non-pack case first. if (!TTP->isExpandedParameterPack()) { - LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters())); + LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(), + computation)); continue; } @@ -262,7 +280,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); i != n; ++i) { LV.merge(getLVForTemplateParameterList( - TTP->getExpansionTemplateParameters(i))); + TTP->getExpansionTemplateParameters(i), computation)); } } @@ -273,13 +291,25 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); +static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { + const Decl *Ret = NULL; + const DeclContext *DC = D->getDeclContext(); + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC)) + Ret = cast<Decl>(DC); + DC = DC->getParent(); + } + return Ret; +} + /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. /// /// 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) { +getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args, + LVComputationKind computation) { LinkageInfo LV; for (unsigned i = 0, e = args.size(); i != e; ++i) { @@ -291,13 +321,13 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { continue; case TemplateArgument::Type: - LV.merge(arg.getAsType()->getLinkageAndVisibility()); + LV.merge(getLVForType(*arg.getAsType(), computation)); continue; case TemplateArgument::Declaration: if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) { assert(!usesTypeVisibility(ND)); - LV.merge(getLVForDecl(ND, LVForValue)); + LV.merge(getLVForDecl(ND, computation)); } continue; @@ -309,11 +339,11 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { case TemplateArgument::TemplateExpansion: if (TemplateDecl *Template = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) - LV.merge(getLVForDecl(Template, LVForValue)); + LV.merge(getLVForDecl(Template, computation)); continue; case TemplateArgument::Pack: - LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray())); + LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation)); continue; } llvm_unreachable("bad template argument kind"); @@ -323,8 +353,9 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { } static LinkageInfo -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) { - return getLVForTemplateArgumentList(TArgs.asArray()); +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation) { + return getLVForTemplateArgumentList(TArgs.asArray(), computation); } static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, @@ -348,19 +379,20 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, /// \param[out] LV the computation to use for the parent static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *specInfo) { + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); // Merge information from the template parameters. FunctionTemplateDecl *temp = specInfo->getTemplate(); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // Merge information from the template arguments. const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; - LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); LV.mergeMaybeWithVisibility(argsLV, considerVisibility); } @@ -379,6 +411,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D, if (D->hasAttr<VisibilityAttr>()) return true; return false; + case LVForLinkageOnly: + return false; } llvm_unreachable("bad visibility computation kind"); } @@ -431,7 +465,7 @@ static void mergeTemplateLV(LinkageInfo &LV, ClassTemplateDecl *temp = spec->getSpecializedTemplate(); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility && !hasExplicitVisibilityAlready(computation)); @@ -439,8 +473,10 @@ static void mergeTemplateLV(LinkageInfo &LV, // 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); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); + if (considerVisibility) + LV.mergeVisibility(argsLV); + LV.mergeExternalVisibility(argsLV); } static bool useInlineVisibilityHidden(const NamedDecl *D) { @@ -472,7 +508,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { } template <typename T> static bool isFirstInExternCContext(T *D) { - const T *First = D->getFirstDeclaration(); + const T *First = D->getFirstDecl(); return First->isInExternCContext(); } @@ -508,7 +544,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, !Var->getType().isVolatileQualified()) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) - return PrevVar->getLinkageAndVisibility(); + return getLVForDecl(PrevVar, computation); if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && @@ -539,11 +575,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared 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. - if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) - return LinkageInfo::internal(); } + // - a data member of an anonymous union. + assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!"); + assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast<VarDecl>(D); @@ -627,7 +662,7 @@ 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 && !isFirstInExternCContext(Var)) { - LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility(); + LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) @@ -660,16 +695,27 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && - !Function->isInExternCContext() && - Function->getType()->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); + !Function->isInExternCContext()) { + // Only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity and + // the one in getLVForClassMember for Functions some other way. + QualType TypeAsWritten = Function->getType(); + if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // 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()) { - mergeTemplateLV(LV, Function, specInfo); + mergeTemplateLV(LV, Function, specInfo, computation); } // - a named class (Clause 9), or an unnamed class defined in a @@ -695,7 +741,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, } else if (isa<EnumConstantDecl>(D)) { LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), computation); - if (!isExternalLinkage(EnumLV.getLinkage())) + if (!isExternalFormalLinkage(EnumLV.getLinkage())) return LinkageInfo::none(); LV.merge(EnumLV); @@ -704,7 +750,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // - a namespace (7.3), unless it is declared within an unnamed @@ -739,6 +785,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, if (!(isa<CXXMethodDecl>(D) || isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || isa<TagDecl>(D))) return LinkageInfo::none(); @@ -766,13 +813,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, 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 (classLV.getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); + if (!isExternallyVisible(classLV.getLinkage())) + return LinkageInfo::none(); + + // Otherwise, don't merge in classLV yet, because in certain cases // we need to completely ignore the visibility from it. @@ -782,14 +830,25 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { // If the type of the function uses a type with unique-external // linkage, it's not legally usable from outside this translation unit. - if (MD->getType()->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); - + // But only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity and the + // one in getLVForNamespaceScopeDecl for Functions some other way. + { + QualType TypeAsWritten = MD->getType(); + if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - mergeTemplateLV(LV, MD, spec); + mergeTemplateLV(LV, MD, spec, computation); if (spec->isExplicitSpecialization()) { explicitSpecSuppressor = MD; } else if (isExplicitMemberSpecialization(spec->getTemplate())) { @@ -819,9 +878,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, } 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 = VD->getType()->getLinkageAndVisibility(); - LV.mergeMaybeWithVisibility(typeLV, - !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()); + LinkageInfo typeLV = getLVForType(*VD->getType(), computation); + if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) + LV.mergeVisibility(typeLV); + LV.mergeExternalVisibility(typeLV); if (isExplicitMemberSpecialization(VD)) { explicitSpecSuppressor = VD; @@ -834,7 +894,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, !classLV.isVisibilityExplicit() && !hasExplicitVisibilityAlready(computation)); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); if (const RedeclarableTemplateDecl *redeclTemp = @@ -866,81 +926,42 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, void NamedDecl::anchor() { } +static LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation); + bool NamedDecl::isLinkageValid() const { - if (!HasCachedLinkage) + if (!hasCachedLinkage()) return true; - return getLVForDecl(this, LVForExplicitValue).getLinkage() == - Linkage(CachedLinkage); + return computeLVForDecl(this, LVForLinkageOnly).getLinkage() == + getCachedLinkage(); } -Linkage NamedDecl::getLinkage() const { - if (HasCachedLinkage) - return Linkage(CachedLinkage); - +Linkage NamedDecl::getLinkageInternal() const { // 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); + return getLVForDecl(this, LVForLinkageOnly).getLinkage(); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { LVComputationKind computation = (usesTypeVisibility(this) ? LVForType : LVForValue); - LinkageInfo LI = getLVForDecl(this, computation); - if (HasCachedLinkage) { - assert(Linkage(CachedLinkage) == LI.getLinkage()); - return LI; - } - HasCachedLinkage = 1; - CachedLinkage = LI.getLinkage(); - -#ifndef NDEBUG - verifyLinkage(); -#endif - - return LI; + return getLVForDecl(this, computation); } -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); -} +static Optional<Visibility> +getExplicitVisibilityAux(const NamedDecl *ND, + NamedDecl::ExplicitVisibilityKind kind, + bool IsMostRecent) { + assert(!IsMostRecent || ND == ND->getMostRecentDecl()); -Optional<Visibility> -NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { // Check the declaration itself first. - if (Optional<Visibility> V = getVisibilityOf(this, kind)) + if (Optional<Visibility> V = getVisibilityOf(ND, 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)) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) { CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); @@ -950,16 +971,18 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { // specialization of a class template, check for visibility // on the pattern. if (const ClassTemplateSpecializationDecl *spec - = dyn_cast<ClassTemplateSpecializationDecl>(this)) + = dyn_cast<ClassTemplateSpecializationDecl>(ND)) 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 (!IsMostRecent && !isa<NamespaceDecl>(ND)) { + const NamedDecl *MostRecent = ND->getMostRecentDecl(); + if (MostRecent != ND) + return getExplicitVisibilityAux(MostRecent, kind, true); + } - if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (const VarDecl *Var = dyn_cast<VarDecl>(ND)) { if (Var->isStaticDataMember()) { VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember(); if (InstantiatedFrom) @@ -969,7 +992,7 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { return None; } // Also handle function template specializations. - if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) { + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) { // If the function is a specialization of a template with an // explicit visibility attribute, use that. if (FunctionTemplateSpecializationInfo *templateInfo @@ -987,12 +1010,33 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { } // The visibility of a template is stored in the templated decl. - if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this)) + if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND)) return getVisibilityOf(TD->getTemplatedDecl(), kind); return None; } +Optional<Visibility> +NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { + return getExplicitVisibilityAux(this, kind, false); +} + +static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, + LVComputationKind computation) { + // This lambda has its linkage/visibility determined by its owner. + if (ContextDecl) { + if (isa<ParmVarDecl>(ContextDecl)) + DC = ContextDecl->getDeclContext()->getRedeclContext(); + else + return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); + } + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) + return getLVForDecl(ND, computation); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -1040,13 +1084,55 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, return LV; } + + if (!Var->isStaticLocal()) + return LinkageInfo::none(); } - return LinkageInfo::none(); + ASTContext &Context = D->getASTContext(); + if (!Context.getLangOpts().CPlusPlus) + return LinkageInfo::none(); + + const Decl *OuterD = getOutermostFuncOrBlockContext(D); + if (!OuterD) + return LinkageInfo::none(); + + LinkageInfo LV; + if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) { + if (!BD->getBlockManglingNumber()) + return LinkageInfo::none(); + + LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(), + BD->getBlockManglingContextDecl(), computation); + } else { + const FunctionDecl *FD = cast<FunctionDecl>(OuterD); + if (!FD->isInlined() && + FD->getTemplateSpecializationKind() == TSK_Undeclared) + return LinkageInfo::none(); + + LV = getLVForDecl(FD, computation); + } + if (!isExternallyVisible(LV.getLinkage())) + return LinkageInfo::none(); + return LinkageInfo(VisibleNoLinkage, LV.getVisibility(), + LV.isVisibilityExplicit()); } -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { +static inline const CXXRecordDecl* +getOutermostEnclosingLambda(const CXXRecordDecl *Record) { + const CXXRecordDecl *Ret = Record; + while (Record && Record->isLambda()) { + Ret = Record; + if (!Record->getParent()) break; + // Get the Containing Class of this Lambda Class + Record = dyn_cast_or_null<CXXRecordDecl>( + Record->getParent()->getParent()); + } + return Ret; +} + +static LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation) { // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { @@ -1074,20 +1160,25 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, // This lambda has no mangling number, so it's internal. return LinkageInfo::internal(); } - - // This lambda has its linkage/visibility determined by its owner. - const DeclContext *DC = D->getDeclContext()->getRedeclContext(); - if (Decl *ContextDecl = Record->getLambdaContextDecl()) { - if (isa<ParmVarDecl>(ContextDecl)) - DC = ContextDecl->getDeclContext()->getRedeclContext(); - else - return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); - } - if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) - return getLVForDecl(ND, computation); + // This lambda has its linkage/visibility determined: + // - either by the outermost lambda if that lambda has no mangling + // number. + // - or by the parent of the outer most lambda + // This prevents infinite recursion in settings such as nested lambdas + // used in NSDMI's, for e.g. + // struct L { + // int t{}; + // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); + // }; + const CXXRecordDecl *OuterMostLambda = + getOutermostEnclosingLambda(Record); + if (!OuterMostLambda->getLambdaManglingNumber()) + return LinkageInfo::internal(); - return LinkageInfo::external(); + return getLVForClosure( + OuterMostLambda->getDeclContext()->getRedeclContext(), + OuterMostLambda->getLambdaContextDecl(), computation); } break; @@ -1127,6 +1218,57 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, return LinkageInfo::none(); } +namespace clang { +class LinkageComputer { +public: + static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + if (computation == LVForLinkageOnly && D->hasCachedLinkage()) + return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); + + LinkageInfo LV = computeLVForDecl(D, computation); + if (D->hasCachedLinkage()) + assert(D->getCachedLinkage() == LV.getLinkage()); + + D->setCachedLinkage(LV.getLinkage()); + +#ifndef NDEBUG + // 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 = D->getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return LV; + + // 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 *Old = NULL; + for (NamedDecl::redecl_iterator I = D->redecls_begin(), + E = D->redecls_end(); + I != E; ++I) { + NamedDecl *T = cast<NamedDecl>(*I); + if (T == D) + continue; + if (T->hasCachedLinkage()) { + Old = T; + break; + } + } + assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); +#endif + + return LV; + } +}; +} + +static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + return clang::LinkageComputer::getLVForDecl(D, computation); +} + std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getPrintingPolicy()); } @@ -1265,6 +1407,15 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { cast<UsingDecl>(OldD)->getQualifier()); } + if (isa<UnresolvedUsingValueDecl>(this) && + isa<UnresolvedUsingValueDecl>(OldD)) { + ASTContext &Context = getASTContext(); + return Context.getCanonicalNestedNameSpecifier( + cast<UnresolvedUsingValueDecl>(this)->getQualifier()) == + Context.getCanonicalNestedNameSpecifier( + cast<UnresolvedUsingValueDecl>(OldD)->getQualifier()); + } + // A typedef of an Objective-C class type can replace an Objective-C class // declaration or definition, and vice versa. if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) || @@ -1278,7 +1429,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - return getLinkage() != NoLinkage; + return getFormalLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDeclImpl() { @@ -1469,6 +1620,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { llvm_unreachable("Invalid storage class"); } +VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { + assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); + assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); + AllBits = 0; + VarDeclBits.SClass = SC; + // Everything else is implicitly initialized to false. +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, @@ -1502,7 +1664,7 @@ 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())) + if (!D.hasExternalFormalLinkage()) return NoLanguageLinkage; // Language linkage is a C++ concept, but saying that everything else in C has @@ -1547,32 +1709,15 @@ bool VarDecl::isExternC() const { return isExternCTemplate(*this); } -static bool isLinkageSpecContext(const DeclContext *DC, - LinkageSpecDecl::LanguageIDs ID) { - while (DC->getDeclKind() != Decl::TranslationUnit) { - if (DC->getDeclKind() == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; - DC = DC->getParent(); - } - return false; -} - -template <typename T> -static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) { - return isLinkageSpecContext(D->getLexicalDeclContext(), ID); -} - bool VarDecl::isInExternCContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); + return getLexicalDeclContext()->isExternCContext(); } bool VarDecl::isInExternCXXContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); + return getLexicalDeclContext()->isExternCXXContext(); } -VarDecl *VarDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); } VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( ASTContext &C) const @@ -1581,13 +1726,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // A declaration is a definition unless [...] it contains the 'extern' // specifier or a linkage-specification and neither an initializer [...], // it declares a static data member in a class declaration [...]. - // C++ [temp.expl.spec]p15: - // An explicit specialization of a static data member of a template is a - // definition if the declaration includes an initializer; otherwise, it is - // a declaration. + // C++1y [temp.expl.spec]p15: + // An explicit specialization of a static data member or an explicit + // specialization of a static data member template is a definition if the + // declaration includes an initializer; otherwise, it is a declaration. + // + // FIXME: How do you declare (but not define) a partial specialization of + // a static data member template outside the containing class? if (isStaticDataMember()) { - if (isOutOfLine() && (hasInit() || - getTemplateSpecializationKind() != TSK_ExplicitSpecialization)) + if (isOutOfLine() && + (hasInit() || + // If the first declaration is out-of-line, this may be an + // instantiation of an out-of-line partial specialization of a variable + // template for which we have not yet instantiated the initializer. + (getFirstDecl()->isOutOfLine() + ? getTemplateSpecializationKind() == TSK_Undeclared + : getTemplateSpecializationKind() != + TSK_ExplicitSpecialization) || + isa<VarTemplatePartialSpecializationDecl>(this))) return Definition; else return DeclarationOnly; @@ -1602,6 +1758,16 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( if (hasInit()) return Definition; + if (hasAttr<AliasAttr>()) + return Definition; + + // A variable template specialization (other than a static data member + // template or an explicit specialization) is a declaration until we + // instantiate its initializer. + if (isa<VarTemplateSpecializationDecl>(this) && + getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + return DeclarationOnly; + if (hasExternalStorage()) return DeclarationOnly; @@ -1631,7 +1797,7 @@ VarDecl *VarDecl::getActingDefinition() { return 0; VarDecl *LastTentative = 0; - VarDecl *First = getFirstDeclaration(); + VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { Kind = (*I)->isThisDeclarationADefinition(); @@ -1643,20 +1809,8 @@ VarDecl *VarDecl::getActingDefinition() { return LastTentative; } -bool VarDecl::isTentativeDefinitionNow() const { - DefinitionKind Kind = isThisDeclarationADefinition(); - if (Kind != TentativeDefinition) - return false; - - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if ((*I)->isThisDeclarationADefinition() == Definition) - return false; - } - return true; -} - VarDecl *VarDecl::getDefinition(ASTContext &C) { - VarDecl *First = getFirstDeclaration(); + VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { if ((*I)->isThisDeclarationADefinition(C) == Definition) @@ -1668,7 +1822,7 @@ VarDecl *VarDecl::getDefinition(ASTContext &C) { VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const { DefinitionKind Kind = DeclarationOnly; - const VarDecl *First = getFirstDeclaration(); + const VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C)); @@ -1763,6 +1917,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); if (!Eval) { Stmt *S = Init.get<Stmt *>(); + // Note: EvaluatedStmt contains an APValue, which usually holds + // resources not allocated from the ASTContext. We need to do some + // work to avoid leaking those, but we do so in VarDecl::evaluateValue + // where we can detect whether there's anything to clean up or not. Eval = new (getASTContext()) EvaluatedStmt; Eval->Value = S; Init = Eval; @@ -1775,6 +1933,13 @@ APValue *VarDecl::evaluateValue() const { return evaluateValue(Notes); } +namespace { +// Destroy an APValue that was allocated in an ASTContext. +void DestroyAPValue(void* UntypedValue) { + static_cast<APValue*>(UntypedValue)->~APValue(); +} +} // namespace + APValue *VarDecl::evaluateValue( SmallVectorImpl<PartialDiagnosticAt> &Notes) const { EvaluatedStmt *Eval = ensureEvaluatedStmt(); @@ -1800,9 +1965,13 @@ APValue *VarDecl::evaluateValue( bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(), this, Notes); - // Ensure the result is an uninitialized APValue if evaluation fails. + // Ensure the computed APValue is cleaned up later if evaluation succeeded, + // or that it's empty (so that there's nothing to clean up) if evaluation + // failed. if (!Result) Eval->Evaluated = APValue(); + else if (Eval->Evaluated.needsCleanup()) + getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated); Eval->IsEvaluating = false; Eval->WasEvaluated = true; @@ -1853,19 +2022,6 @@ bool VarDecl::checkInitIsICE() const { return Eval->IsICE; } -bool VarDecl::extendsLifetimeOfTemporary() const { - assert(getType()->isReferenceType() &&"Non-references never extend lifetime"); - - const Expr *E = getInit(); - if (!E) - return false; - - if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(E)) - E = Cleanups->getSubExpr(); - - return isa<MaterializeTemporaryExpr>(E); -} - VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -1874,25 +2030,73 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); - + return TSK_Undeclared; } +SourceLocation VarDecl::getPointOfInstantiation() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getPointOfInstantiation(); + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getPointOfInstantiation(); + + return SourceLocation(); +} + +VarTemplateDecl *VarDecl::getDescribedVarTemplate() const { + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<VarTemplateDecl *>(); +} + +void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { + getASTContext().setTemplateOrSpecializationInfo(this, Template); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { - return getASTContext().getInstantiatedFromStaticDataMember(this); + if (isStaticDataMember()) + // FIXME: Remove ? + // return getASTContext().getInstantiatedFromStaticDataMember(this); + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<MemberSpecializationInfo *>(); + return 0; } void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { - MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); - assert(MSI && "Not an instantiated static data member?"); - MSI->setTemplateSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && - PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) - MSI->setPointOfInstantiation(PointOfInstantiation); + assert((isa<VarTemplateSpecializationDecl>(this) || + getMemberSpecializationInfo()) && + "not a variable or static data member template specialization"); + + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + Spec->getPointOfInstantiation().isInvalid()) + Spec->setPointOfInstantiation(PointOfInstantiation); + } + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); + } +} + +void +VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK) { + assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() && + "Previous template or instantiation?"); + getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK); } //===----------------------------------------------------------------------===// @@ -1908,6 +2112,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, S, DefArg); } +QualType ParmVarDecl::getOriginalType() const { + TypeSourceInfo *TSI = getTypeSourceInfo(); + QualType T = TSI ? TSI->getType() : getType(); + if (const DecayedType *DT = dyn_cast<DecayedType>(T)) + return DT->getOriginalType(); + return T; +} + ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl)); return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(), @@ -2010,7 +2222,8 @@ bool FunctionDecl::hasTrivialBody() const bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) { + if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed || + I->hasAttr<AliasAttr>()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : *I; return true; } @@ -2020,15 +2233,11 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { } Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->Body) { - Definition = *I; - return I->Body.get(getASTContext().getExternalSource()); - } else if (I->IsLateTemplateParsed) { - Definition = *I; - return 0; - } - } + if (!hasBody(Definition)) + return 0; + + if (Definition->Body) + return Definition->Body.get(getASTContext().getExternalSource()); return 0; } @@ -2046,13 +2255,45 @@ void FunctionDecl::setPure(bool P) { Parent->markedVirtualFunctionPure(); } +template<std::size_t Len> +static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) { + IdentifierInfo *II = ND->getIdentifier(); + return II && II->isStr(Str); +} + bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); return tunit && !tunit->getASTContext().getLangOpts().Freestanding && - getIdentifier() && - getIdentifier()->isStr("main"); + isNamed(this, "main"); +} + +bool FunctionDecl::isMSVCRTEntryPoint() const { + const TranslationUnitDecl *TUnit = + dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); + if (!TUnit) + return false; + + // Even though we aren't really targeting MSVCRT if we are freestanding, + // semantic analysis for these functions remains the same. + + // MSVCRT entry points only exist on MSVCRT targets. + if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT()) + return false; + + // Nameless functions like constructors cannot be entry points. + if (!getIdentifier()) + return false; + + return llvm::StringSwitch<bool>(getName()) + .Cases("main", // an ANSI console app + "wmain", // a Unicode console App + "WinMain", // an ANSI GUI app + "wWinMain", // a Unicode GUI app + "DllMain", // a DLL + true) + .Default(false); } bool FunctionDecl::isReservedGlobalPlacementOperator() const { @@ -2077,13 +2318,83 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } -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; +static bool isNamespaceStd(const DeclContext *DC) { + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext()); + return ND && isNamed(ND, "std") && + ND->getParent()->getRedeclContext()->isTranslationUnit(); +} +bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { + if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) + return false; + if (getDeclName().getCXXOverloadedOperator() != OO_New && + getDeclName().getCXXOverloadedOperator() != OO_Delete && + getDeclName().getCXXOverloadedOperator() != OO_Array_New && + getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return false; + + if (isa<CXXRecordDecl>(getDeclContext())) + return false; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>(); + if (FPT->getNumArgs() > 2 || FPT->isVariadic()) + return false; + + // If this is a single-parameter function, it must be a replaceable global + // allocation or deallocation function. + if (FPT->getNumArgs() == 1) + return true; + + // Otherwise, we're looking for a second parameter whose type is + // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'. + QualType Ty = FPT->getArgType(1); + ASTContext &Ctx = getASTContext(); + if (Ctx.getLangOpts().SizedDeallocation && + Ctx.hasSameType(Ty, Ctx.getSizeType())) + return true; + if (!Ty->isReferenceType()) + return false; + Ty = Ty->getPointeeType(); + if (Ty.getCVRQualifiers() != Qualifiers::Const) + return false; + // FIXME: Recognise nothrow_t in an inline namespace inside std? + const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext()); +} + +FunctionDecl * +FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const { + ASTContext &Ctx = getASTContext(); + if (!Ctx.getLangOpts().SizedDeallocation) + return 0; + + if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) + return 0; + if (getDeclName().getCXXOverloadedOperator() != OO_Delete && + getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return 0; + if (isa<CXXRecordDecl>(getDeclContext())) + return 0; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + if (getNumParams() != 2 || isVariadic() || + !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1), + Ctx.getSizeType())) + return 0; + + // This is a sized deallocation function. Find the corresponding unsized + // deallocation function. + lookup_const_result R = getDeclContext()->lookup(getDeclName()); + for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE; + ++RI) + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI)) + if (FD->getNumParams() == 1 && !FD->isVariadic()) + return FD; + return 0; +} + +LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } @@ -2092,11 +2403,11 @@ bool FunctionDecl::isExternC() const { } bool FunctionDecl::isInExternCContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); + return getLexicalDeclContext()->isExternCContext(); } bool FunctionDecl::isInExternCXXContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); + return getLexicalDeclContext()->isExternCXXContext(); } bool FunctionDecl::isGlobal() const { @@ -2127,13 +2438,13 @@ bool FunctionDecl::isNoReturn() const { void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - redeclarable_base::setPreviousDeclaration(PrevDecl); + redeclarable_base::setPreviousDecl(PrevDecl); if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { FunctionTemplateDecl *PrevFunTmpl = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); - FunTmpl->setPreviousDeclaration(PrevFunTmpl); + FunTmpl->setPreviousDecl(PrevFunTmpl); } if (PrevDecl && PrevDecl->IsInline) @@ -2141,12 +2452,10 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { } const FunctionDecl *FunctionDecl::getCanonicalDecl() const { - return getFirstDeclaration(); + return getFirstDecl(); } -FunctionDecl *FunctionDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. @@ -2166,6 +2475,22 @@ unsigned FunctionDecl::getBuiltinID() const { return 0; ASTContext &Context = getASTContext(); + if (Context.getLangOpts().CPlusPlus) { + const LinkageSpecDecl *LinkageDecl = dyn_cast<LinkageSpecDecl>( + getFirstDecl()->getDeclContext()); + // In C++, the first declaration of a builtin is always inside an implicit + // extern "C". + // FIXME: A recognised library function may not be directly in an extern "C" + // declaration, for instance "extern "C" { namespace std { decl } }". + if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) + return 0; + } + + // If the function is marked "overloadable", it has a different mangled name + // and is not the C library function. + if (getAttr<OverloadableAttr>()) + return 0; + if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return BuiltinID; @@ -2177,22 +2502,7 @@ unsigned FunctionDecl::getBuiltinID() const { if (getStorageClass() == SC_Static) return 0; - // If this function is at translation-unit scope and we're not in - // C++, it refers to the C library function. - if (!Context.getLangOpts().CPlusPlus && - getDeclContext()->isTranslationUnit()) - return BuiltinID; - - // If the function is in an extern "C" linkage specification and is - // not marked "overloadable", it's the real function. - if (isa<LinkageSpecDecl>(getDeclContext()) && - cast<LinkageSpecDecl>(getDeclContext())->getLanguage() - == LinkageSpecDecl::lang_c && - !getAttr<OverloadableAttr>()) - return BuiltinID; - - // Not a builtin - return 0; + return BuiltinID; } @@ -2304,7 +2614,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (Prev->Body) { // If it's not the case that both 'inline' and 'extern' are @@ -2332,7 +2642,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (RedeclForcesDefC99(Prev)) return false; } @@ -2818,26 +3128,18 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { } unsigned FieldDecl::getFieldIndex() const { + const FieldDecl *Canonical = getCanonicalDecl(); + if (Canonical != this) + return Canonical->getFieldIndex(); + if (CachedFieldIndex) return CachedFieldIndex - 1; unsigned Index = 0; const RecordDecl *RD = getParent(); - const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->isMsStruct(getASTContext()); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I, ++Index) { - I->CachedFieldIndex = Index + 1; - - if (IsMsStruct) { - // Zero-length bitfields following non-bitfield members are ignored. - if (getASTContext().ZeroBitfieldFollowsNonBitfield(*I, LastFD)) { - --Index; - continue; - } - LastFD = *I; - } - } + I != E; ++I, ++Index) + I->getCanonicalDecl()->CachedFieldIndex = Index + 1; assert(CachedFieldIndex && "failed to find field in parent"); return CachedFieldIndex - 1; @@ -2874,12 +3176,10 @@ SourceRange TagDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), E); } -TagDecl* TagDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); } void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { - TypedefNameDeclOrQualifier = TDD; + NamedDeclOrQualifier = TDD; if (TypeForDecl) assert(TypeForDecl->isLinkageValid()); assert(isLinkageValid()); @@ -2936,7 +3236,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended qualifier info is allocated. if (!hasExtInfo()) - TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + NamedDeclOrQualifier = new (getASTContext()) ExtInfo; // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; } else { @@ -2944,7 +3244,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { getASTContext().Deallocate(getExtInfo()); - TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0; + NamedDeclOrQualifier = (TypedefNameDecl*) 0; } else getExtInfo()->QualifierLoc = QualifierLoc; @@ -2959,7 +3259,7 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context, // Make sure the extended decl info is allocated. if (!hasExtInfo()) // Allocate external info struct. - TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + NamedDeclOrQualifier = new (getASTContext()) ExtInfo; // Set the template parameter lists info. getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 084a4321d8f1..121c5a671a29 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const { return false; } +void Decl::markUsed(ASTContext &C) { + if (Used) + return; + + if (C.getASTMutationListener()) + C.getASTMutationListener()->DeclarationMarkedUsed(this); + + Used = true; +} + bool Decl::isReferenced() const { if (Referenced) return true; @@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: + case VarTemplate: return IDNS_Ordinary; case ClassTemplate: @@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: + case VarTemplateSpecialization: + case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: @@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const { return getASTContext().getDeclAttrs(this); } -void Decl::swapAttrs(Decl *RHS) { - bool HasLHSAttr = this->HasAttrs; - bool HasRHSAttr = RHS->HasAttrs; - - // Usually, neither decl has attrs, nothing to do. - if (!HasLHSAttr && !HasRHSAttr) return; - - // If 'this' has no attrs, swap the other way. - if (!HasLHSAttr) - return RHS->swapAttrs(this); - - ASTContext &Context = getASTContext(); - - // Handle the case when both decls have attrs. - if (HasRHSAttr) { - std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); - return; - } - - // Otherwise, LHS has an attr and RHS doesn't. - Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); - Context.eraseDeclAttrs(this); - this->HasAttrs = false; - RHS->HasAttrs = true; -} - Decl *Decl::castFromDeclContext (const DeclContext *D) { Decl::Kind DK = D->getDeclKind(); switch(DK) { @@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const { return false; } +static bool isLinkageSpecContext(const DeclContext *DC, + LinkageSpecDecl::LanguageIDs ID) { + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; + DC = DC->getParent(); + } + return false; +} + +bool DeclContext::isExternCContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); +} + +bool DeclContext::isExternCXXContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); +} + bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() { 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); - } + for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) + I->second.setHasExternalDecls(); } /// \brief Load the declarations within this lexical storage from an @@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, if (!(Map = DC->LookupPtr.getPointer())) Map = DC->CreateStoredDeclsMap(Context); - // Add an entry to the map for this name, if it's not already present. - (*Map)[Name]; + (*Map)[Name].removeExternalDecls(); return DeclContext::lookup_result(); } @@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, Map = DC->CreateStoredDeclsMap(Context); StoredDeclsList &List = (*Map)[Name]; - for (ArrayRef<NamedDecl*>::iterator - I = Decls.begin(), E = Decls.end(); I != E; ++I) { - if (List.isNull()) - List.setOnlyValue(*I); - else - // FIXME: Need declarationReplaces handling for redeclarations in modules. - List.AddSubsequentDecl(*I); + + // Clear out any old external visible declarations, to avoid quadratic + // performance in the redeclaration checks below. + List.removeExternalDecls(); + + if (!List.isNull()) { + // We have both existing declarations and new declarations for this name. + // Some of the declarations may simply replace existing ones. Handle those + // first. + llvm::SmallVector<unsigned, 8> Skip; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) + if (List.HandleRedeclaration(Decls[I])) + Skip.push_back(I); + Skip.push_back(Decls.size()); + + // Add in any new declarations. + unsigned SkipPos = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (I == Skip[SkipPos]) + ++SkipPos; + else + List.AddSubsequentDecl(Decls[I]); + } + } else { + // Convert the array to a StoredDeclsList. + for (ArrayRef<NamedDecl*>::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + if (List.isNull()) + List.setOnlyValue(*I); + else + List.AddSubsequentDecl(*I); + } } return List.getLookupResult(); @@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() { SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl(Contexts[I]); + buildLookupImpl<&DeclContext::decls_begin, + &DeclContext::decls_end>(Contexts[I]); // We no longer have any lazy decls. LookupPtr.setInt(false); @@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() { /// declarations contained within DCtx, which will either be this /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. +template<DeclContext::decl_iterator (DeclContext::*Begin)() const, + DeclContext::decl_iterator (DeclContext::*End)() const> void DeclContext::buildLookupImpl(DeclContext *DCtx) { - for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end(); + for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)(); I != E; ++I) { Decl *D = *I; // Insert this declaration into the lookup structure, but only if // it's semantically within its decl context. Any other decls which // should be found in this context are added eagerly. + // + // If it's from an AST file, don't add it now. It'll get handled by + // FindExternalVisibleDeclsByName if needed. Exception: if we're not + // in C++, we do not track external visible decls for the TU, so in + // that case we need to collect them all here. if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND)) + if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) && + (!ND->isFromASTFile() || + (isTranslationUnit() && + !getParentASTContext().getLangOpts().CPlusPlus))) makeDeclVisibleInContextImpl(ND, false); // If this declaration is itself a transparent declaration context @@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) { // context (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookupImpl(InnerCtx); + buildLookupImpl<Begin, End>(InnerCtx); } } @@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) { 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. + // If we have a lookup result with no external decls, we are done. std::pair<StoredDeclsMap::iterator, bool> R = Map->insert(std::make_pair(Name, StoredDeclsList())); - if (!R.second) + if (!R.second && !R.first->second.hasExternalDecls()) return R.first->second.getLookupResult(); ExternalASTSource *Source = getParentASTContext().getExternalSource(); - if (Source->FindExternalVisibleDeclsByName(this, Name)) { + if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) { if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) @@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) { return I->second.getLookupResult(); } +DeclContext::lookup_result +DeclContext::noload_lookup(DeclarationName Name) { + assert(DeclKind != Decl::LinkageSpec && + "Should not perform lookups into linkage specs!"); + if (!hasExternalVisibleStorage()) + return lookup(Name); + + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) + return PrimaryContext->noload_lookup(Name); + + StoredDeclsMap *Map = LookupPtr.getPointer(); + if (LookupPtr.getInt()) { + // Carefully build the lookup map, without deserializing anything. + SmallVector<DeclContext *, 2> Contexts; + collectAllContexts(Contexts); + for (unsigned I = 0, N = Contexts.size(); I != N; ++I) + buildLookupImpl<&DeclContext::noload_decls_begin, + &DeclContext::noload_decls_end>(Contexts[I]); + + // We no longer have any lazy decls. + LookupPtr.setInt(false); + + // There may now be names for which we have local decls but are + // missing the external decls. FIXME: Just set the hasExternalDecls + // flag on those names that have external decls. + NeedToReconcileExternalVisibleStorage = true; + + Map = LookupPtr.getPointer(); + } + + if (!Map) + return lookup_result(lookup_iterator(0), lookup_iterator(0)); + + StoredDeclsMap::iterator I = Map->find(Name); + return I != Map->end() + ? I->second.getLookupResult() + : lookup_result(lookup_iterator(0), lookup_iterator(0)); +} + void DeclContext::localUncachedLookup(DeclarationName Name, SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); @@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, assert(this == getPrimaryContext() && "expected a primary DC"); // Skip declarations within functions. - // FIXME: We shouldn't need to build lookup tables for function declarations - // ever, and we can't do so correctly because we can't model the nesting of - // scopes which occurs within functions. We use "qualified" lookup into - // function declarations when handling friend declarations inside nested - // classes, and consequently accept the following invalid code: - // - // void f() { void g(); { int g; struct S { friend void g(); }; } } - if (isFunctionOrMethod() && !isa<FunctionDecl>(D)) + if (isFunctionOrMethod()) return; // Skip declarations which should be invisible to name lookup. @@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Insert this declaration into the map. StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()]; - if (DeclNameEntries.isNull()) { + + if (Internal) { + // If this is being added as part of loading an external declaration, + // this may not be the only external declaration with this name. + // In this case, we never try to replace an existing declaration; we'll + // handle that when we finalize the list of declarations for this name. + DeclNameEntries.setHasExternalDecls(); + DeclNameEntries.AddSubsequentDecl(D); + return; + } + + else if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 064649904d30..a17abdd0ae2a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -10,9 +10,9 @@ // This file implements the C++ related Decl classes. // //===----------------------------------------------------------------------===// - #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclTemplate.h" @@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) AccessSpecDecl(EmptyShell()); } +void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const { + ExternalASTSource *Source = C.getExternalSource(); + assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set"); + assert(Source && "getFromExternalSource with no external source"); + + for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I) + I.setDecl(cast<NamedDecl>(Source->GetExternalDecl( + reinterpret_cast<uintptr_t>(I.getDecl()) >> 2))); + Impl.Decls.setLazy(false); +} + CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), @@ -60,9 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), - FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(), - Definition(D), FirstFriend(0) { + Definition(D), FirstFriend() { } CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { @@ -97,12 +107,17 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, - bool Dependent) { + bool Dependent, bool IsGeneric, + LambdaCaptureDefault CaptureDefault) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, 0, 0); R->IsBeingDefined = true; - R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); + R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, + Dependent, + IsGeneric, + CaptureDefault); R->MayHaveOutOfDateDef = false; + R->setImplicit(true); C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -552,18 +567,16 @@ void CXXRecordDecl::addedMember(Decl *D) { if (Conversion->getPrimaryTemplate()) { // We don't record specializations. - } else if (FunTmpl) { - if (FunTmpl->getPreviousDecl()) - data().Conversions.replace(FunTmpl->getPreviousDecl(), - FunTmpl, AS); - else - data().Conversions.addDecl(getASTContext(), FunTmpl, AS); } else { - if (Conversion->getPreviousDecl()) - data().Conversions.replace(Conversion->getPreviousDecl(), - Conversion, AS); + ASTContext &Ctx = getASTContext(); + ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx); + NamedDecl *Primary = + FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion); + if (Primary->getPreviousDecl()) + Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()), + Primary, AS); else - data().Conversions.addDecl(getASTContext(), Conversion, AS); + Conversions.addDecl(Ctx, Primary, AS); } } @@ -662,7 +675,7 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!Context.getLangOpts().ObjCAutoRefCount || T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) setHasObjectMember(true); - } else if (!T.isPODType(Context)) + } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; if (T->isReferenceType()) { @@ -712,6 +725,13 @@ void CXXRecordDecl::addedMember(Decl *D) { if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); + // We may need to perform overload resolution to determine whether a + // field can be moved if it's const or volatile qualified. + if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) { + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForMoveAssignment = true; + } + // C++11 [class.ctor]p5, C++11 [class.copy]p11: // A defaulted [special member] for a class X is defined as // deleted if: @@ -880,10 +900,13 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Handle using declarations of conversion functions. - if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) { if (Shadow->getDeclName().getNameKind() - == DeclarationName::CXXConversionFunctionName) - data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess()); + == DeclarationName::CXXConversionFunctionName) { + ASTContext &Ctx = getASTContext(); + data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess()); + } + } } void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { @@ -929,6 +952,43 @@ bool CXXRecordDecl::isCLike() const { return isPOD() && data().HasOnlyCMembers; } + +bool CXXRecordDecl::isGenericLambda() const { + if (!isLambda()) return false; + return getLambdaData().IsGenericLambda; +} + +CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { + if (!isLambda()) return 0; + DeclarationName Name = + getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_const_result Calls = lookup(Name); + + assert(!Calls.empty() && "Missing lambda call operator!"); + assert(Calls.size() == 1 && "More than one lambda call operator!"); + + NamedDecl *CallOp = Calls.front(); + if (FunctionTemplateDecl *CallOpTmpl = + dyn_cast<FunctionTemplateDecl>(CallOp)) + return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl()); + + return cast<CXXMethodDecl>(CallOp); +} + +CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { + if (!isLambda()) return 0; + DeclarationName Name = + &getASTContext().Idents.get(getLambdaStaticInvokerName()); + DeclContext::lookup_const_result Invoker = lookup(Name); + if (Invoker.empty()) return 0; + assert(Invoker.size() == 1 && "More than one static invoker operator!"); + NamedDecl *InvokerFun = Invoker.front(); + if (FunctionTemplateDecl *InvokerTemplate = + dyn_cast<FunctionTemplateDecl>(InvokerFun)) + return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl()); + + return cast<CXXMethodDecl>(InvokerFun); +} void CXXRecordDecl::getCaptureFields( llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, @@ -940,15 +1000,22 @@ void CXXRecordDecl::getCaptureFields( RecordDecl::field_iterator Field = field_begin(); for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures; C != CEnd; ++C, ++Field) { - if (C->capturesThis()) { + if (C->capturesThis()) ThisCapture = *Field; - continue; - } - - Captures[C->getCapturedVar()] = *Field; + else if (C->capturesVariable()) + Captures[C->getCapturedVar()] = *Field; } + assert(Field == field_end()); } +TemplateParameterList * +CXXRecordDecl::getGenericLambdaTemplateParameterList() const { + if (!isLambda()) return 0; + CXXMethodDecl *CallOp = getLambdaCallOperator(); + if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) + return Tmpl->getTemplateParameters(); + return 0; +} static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T; @@ -1085,16 +1152,21 @@ static void CollectVisibleConversions(ASTContext &Context, /// in current class; including conversion function templates. std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator> CXXRecordDecl::getVisibleConversionFunctions() { - // If root class, all conversions are visible. - if (bases_begin() == bases_end()) - return std::make_pair(data().Conversions.begin(), data().Conversions.end()); - // If visible conversion list is already evaluated, return it. - if (!data().ComputedVisibleConversions) { - CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); - data().ComputedVisibleConversions = true; + ASTContext &Ctx = getASTContext(); + + ASTUnresolvedSet *Set; + if (bases_begin() == bases_end()) { + // If root class, all conversions are visible. + Set = &data().Conversions.get(Ctx); + } else { + Set = &data().VisibleConversions.get(Ctx); + // If visible conversion list is not evaluated, evaluate it. + if (!data().ComputedVisibleConversions) { + CollectVisibleConversions(Ctx, this, *Set); + data().ComputedVisibleConversions = true; + } } - return std::make_pair(data().VisibleConversions.begin(), - data().VisibleConversions.end()); + return std::make_pair(Set->begin(), Set->end()); } void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { @@ -1109,7 +1181,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { // with sufficiently large numbers of directly-declared conversions // that asymptotic behavior matters. - ASTUnresolvedSet &Convs = data().Conversions; + ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext()); for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); @@ -1134,7 +1206,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, TemplateSpecializationKind TSK) { assert(TemplateOrInstantiation.isNull() && "Previous template or instantiation?"); - assert(!isa<ClassTemplateSpecializationDecl>(this)); + assert(!isa<ClassTemplatePartialSpecializationDecl>(this)); TemplateOrInstantiation = new (getASTContext()) MemberSpecializationInfo(RD, TSK); } @@ -1235,8 +1307,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { } // Set access bits correctly on the directly-declared conversions. - for (UnresolvedSetIterator I = data().Conversions.begin(), - E = data().Conversions.end(); + for (conversion_iterator I = conversion_begin(), E = conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); } @@ -1266,21 +1337,8 @@ bool CXXMethodDecl::isStatic() const { 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; + OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator(); + return isStaticOverloadedOperator(OOK); } static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, @@ -1408,7 +1466,8 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { // type X, X&, const X&, volatile X& or const volatile X&. if (/*operator=*/getOverloadedOperator() != OO_Equal || /*non-static*/ isStatic() || - /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate()) + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || + getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1427,7 +1486,8 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const { // non-template member function of class X with exactly one parameter of type // X&&, const X&&, volatile X&&, or const volatile X&&. if (getOverloadedOperator() != OO_Equal || isStatic() || - getPrimaryTemplate() || getDescribedFunctionTemplate()) + getPrimaryTemplate() || getDescribedFunctionTemplate() || + getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1492,11 +1552,17 @@ bool CXXMethodDecl::hasInlineBody() const { } bool CXXMethodDecl::isLambdaStaticInvoker() const { - return getParent()->isLambda() && - getIdentifier() && getIdentifier()->getName() == "__invoke"; + const CXXRecordDecl *P = getParent(); + if (P->isLambda()) { + if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) { + if (StaticInvoker == this) return true; + if (P->isGenericLambda() && this->isFunctionTemplateSpecialization()) + return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl(); + } + } + return false; } - CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, @@ -1865,7 +1931,7 @@ NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline, : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline) { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); if (PrevDecl) AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace()); @@ -1959,8 +2025,8 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, - bool IsTypeNameArg) { - return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg); + bool HasTypename) { + return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); } UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -1969,6 +2035,12 @@ UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { DeclarationNameInfo(), false); } +SourceRange UsingDecl::getSourceRange() const { + SourceLocation Begin = isAccessDeclaration() + ? getQualifierLoc().getBeginLoc() : UsingLocation; + return SourceRange(Begin, getNameInfo().getEndLoc()); +} + void UnresolvedUsingValueDecl::anchor() { } UnresolvedUsingValueDecl * @@ -1988,6 +2060,12 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) { DeclarationNameInfo()); } +SourceRange UnresolvedUsingValueDecl::getSourceRange() const { + SourceLocation Begin = isAccessDeclaration() + ? getQualifierLoc().getBeginLoc() : UsingLocation; + return SourceRange(Begin, getNameInfo().getEndLoc()); +} + void UnresolvedUsingTypenameDecl::anchor() { } UnresolvedUsingTypenameDecl * diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 37a812e71aae..1c639d676dc9 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID, return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists); } +FriendDecl *CXXRecordDecl::getFirstFriend() const { + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + Decl *First = data().FirstFriend.get(Source); + return First ? cast<FriendDecl>(First) : 0; +} diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 4ddbb22199b2..b2b5b70197b7 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -441,6 +441,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( return NULL; } +ObjCProtocolDecl * +ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) { + for (ObjCInterfaceDecl::all_protocol_iterator P = + all_referenced_protocol_begin(), PE = all_referenced_protocol_end(); + P != PE; ++P) + if ((*P)->lookupProtocolNamed(Name)) + return (*P); + ObjCInterfaceDecl *SuperClass = getSuperClass(); + return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL; +} + /// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). /// When argument category "C" is specified, any implicit method found @@ -627,23 +638,29 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { Decl *CtxD = cast<Decl>(getDeclContext()); - if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { - if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) - Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { - if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) - Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCImplementationDecl *ImplD = - dyn_cast<ObjCImplementationDecl>(CtxD)) { - if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) - Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCCategoryImplDecl *CImplD = - dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) - Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + if (!CtxD->isInvalidDecl()) { + if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + if (!ImplD->isInvalidDecl()) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + if (!ImplD->isInvalidDecl()) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (!IFD->isInvalidDecl()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) + if (!CatD->isInvalidDecl()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } } if (!Redecl && isRedeclaration()) { @@ -1062,7 +1079,7 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc), TypeForDecl(0), Data() { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); // Copy the 'data' pointer over. if (PrevDecl) @@ -1308,7 +1325,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, - bool synthesized) { + bool synthesized, + bool backingIvarReferencedInAccessor) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -1336,13 +1354,13 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, } return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, - ac, BW, synthesized); + ac, BW, synthesized, backingIvarReferencedInAccessor); } ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl)); return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, ObjCIvarDecl::None, 0, false); + QualType(), 0, ObjCIvarDecl::None, 0, false, false); } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { @@ -1401,7 +1419,7 @@ ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id, ObjCProtocolDecl *PrevDecl) : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data() { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); if (PrevDecl) Data = PrevDecl->Data; } @@ -1493,6 +1511,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM, } } + +void ObjCProtocolDecl::collectInheritedProtocolProperties( + const ObjCPropertyDecl *Property, + ProtocolPropertyMap &PM) const { + if (const ObjCProtocolDecl *PDecl = getDefinition()) { + bool MatchFound = false; + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + if (Prop == Property) + continue; + if (Prop->getIdentifier() == Property->getIdentifier()) { + PM[PDecl] = Prop; + MatchFound = true; + break; + } + } + // Scan through protocol's protocols which did not have a matching property. + if (!MatchFound) + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + (*PI)->collectInheritedProtocolProperties(Property, PM); + } +} //===----------------------------------------------------------------------===// // ObjCCategoryDecl diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index c0d10a0f418c..0d195f74623d 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { } OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef<DeclRefExpr *> VL) { + ArrayRef<Expr *> VL) { unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(DeclRefExpr *)); + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned N) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -52,9 +52,10 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, return D; } -void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { +void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + Expr **Vars = reinterpret_cast<Expr **>(this + 1); std::copy(VL.begin(), VL.end(), Vars); } + diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d47972bc6130..767f6620a295 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -260,6 +260,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { QualType CurDeclType = getDeclType(*D); if (!Decls.empty() && !CurDeclType.isNull()) { QualType BaseType = GetBaseType(CurDeclType); + if (!BaseType.isNull() && isa<ElaboratedType>(BaseType)) + BaseType = cast<ElaboratedType>(BaseType)->getNamedType(); if (!BaseType.isNull() && isa<TagType>(BaseType) && cast<TagType>(BaseType)->getDecl() == Decls[0]) { Decls.push_back(*D); @@ -337,12 +339,14 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { if (D->isModulePrivate()) Out << "__module_private__ "; } - D->getUnderlyingType().print(Out, Policy, D->getName()); + D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName()); prettyPrintAttributes(D); } void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { - Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy); + Out << "using " << *D; + prettyPrintAttributes(D); + Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy); } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { @@ -665,9 +669,9 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { Out << "__module_private__ "; } - QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); - if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) - T = Parm->getOriginalType(); + QualType T = D->getTypeSourceInfo() + ? D->getTypeSourceInfo()->getType() + : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); T.print(Out, Policy, D->getName()); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { @@ -1153,7 +1157,10 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { - Out << "using "; + if (!D->isAccessDeclaration()) + Out << "using "; + if (D->hasTypename()) + Out << "typename "; D->getQualifier()->print(Out, Policy); Out << *D; } @@ -1166,7 +1173,8 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - Out << "using "; + if (!D->isAccessDeclaration()) + Out << "using "; D->getQualifier()->print(Out, Policy); Out << D->getName(); } @@ -1180,9 +1188,10 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { 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()); + I != E; ++I) { + Out << (I == D->varlist_begin() ? '(' : ','); + NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); + ND->printQualifiedName(Out); } Out << ")"; } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 0b94f7d2c49b..7172fb7b487f 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -129,33 +129,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, //===----------------------------------------------------------------------===// 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. - SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; - for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; - Prev = Prev->getPreviousDecl()) { - if (Prev->Common) { - Common = Prev->Common; - break; - } - - PrevDecls.push_back(Prev); + if (Common) + return Common; + + // Walk the previous-declaration chain until we either find a declaration + // with a common pointer or we run out of previous declarations. + SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; + for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) { + if (Prev->Common) { + Common = Prev->Common; + break; } - // If we never found a common pointer, allocate one now. - if (!Common) { - // FIXME: If any of the declarations is from an AST file, we probably - // need an update record to add the common data. - - Common = newCommon(getASTContext()); - } - - // Update any previous declarations we saw with the common pointer. - for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I) - PrevDecls[I]->Common = Common; + PrevDecls.push_back(Prev); + } + + // If we never found a common pointer, allocate one now. + if (!Common) { + // FIXME: If any of the declarations is from an AST file, we probably + // need an update record to add the common data. + + Common = newCommon(getASTContext()); } + // Update any previous declarations we saw with the common pointer. + for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I) + PrevDecls[I]->Common = Common; + return Common; } @@ -245,6 +246,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const { return CommonPtr; } +void FunctionTemplateDecl::LoadLazySpecializations() const { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> & +FunctionTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + FunctionDecl * FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, unsigned NumArgs, void *&InsertPos) { @@ -261,18 +279,17 @@ void FunctionTemplateDecl::addSpecialization( L->AddedCXXTemplateSpecialization(this, Info->Function); } -std::pair<const TemplateArgument *, unsigned> -FunctionTemplateDecl::getInjectedTemplateArgs() { +ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() { TemplateParameterList *Params = getTemplateParameters(); Common *CommonPtr = getCommonPtr(); if (!CommonPtr->InjectedArgs) { CommonPtr->InjectedArgs - = new (getASTContext()) TemplateArgument [Params->size()]; - GenerateInjectedTemplateArgs(getASTContext(), Params, + = new (getASTContext()) TemplateArgument[Params->size()]; + GenerateInjectedTemplateArgs(getASTContext(), Params, CommonPtr->InjectedArgs); } - - return std::make_pair(CommonPtr->InjectedArgs, Params->size()); + + return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size()); } //===----------------------------------------------------------------------===// @@ -292,7 +309,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, ClassTemplateDecl *PrevDecl) { AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl); - New->setPreviousDeclaration(PrevDecl); + New->setPreviousDecl(PrevDecl); return New; } @@ -381,13 +398,11 @@ void ClassTemplateDecl::getPartialSpecializations( llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &PartialSpecs = getPartialSpecializations(); PS.clear(); - PS.resize(PartialSpecs.size()); + PS.reserve(PartialSpecs.size()); for (llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>::iterator P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); - P != PEnd; ++P) { - assert(!PS[P->getSequenceNumber()]); - PS[P->getSequenceNumber()] = P->getMostRecentDecl(); - } + P != PEnd; ++P) + PS.push_back(P->getMostRecentDecl()); } ClassTemplatePartialSpecializationDecl * @@ -813,19 +828,16 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, ClassTemplateDecl *SpecializedTemplate, const TemplateArgument *Args, unsigned NumArgs, - TemplateArgumentLoc *ArgInfos, - unsigned NumArgInfos, - ClassTemplatePartialSpecializationDecl *PrevDecl, - unsigned SequenceNumber) + const ASTTemplateArgumentListInfo *ArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, NumArgs, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), - NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), InstantiatedFromMember(0, false) -{ +{ AdoptTemplateParameterList(Params, this); } @@ -839,12 +851,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl, - unsigned SequenceNumber) { - unsigned N = ArgInfos.size(); - TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; - for (unsigned I = 0; I != N; ++I) - ClonedArgs[I] = ArgInfos[I]; + ClassTemplatePartialSpecializationDecl *PrevDecl) { + const ASTTemplateArgumentListInfo *ASTArgInfos = + ASTTemplateArgumentListInfo::Create(Context, ArgInfos); ClassTemplatePartialSpecializationDecl *Result = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, @@ -852,9 +861,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, Params, SpecializedTemplate, Args, NumArgs, - ClonedArgs, N, - PrevDecl, - SequenceNumber); + ASTArgInfos, + PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Result->MayHaveOutOfDateDef = false; @@ -942,3 +950,252 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0, false, TemplateArgumentListInfo()); } + +//===----------------------------------------------------------------------===// +// VarTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void VarTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +VarTemplateDecl *VarTemplateDecl::getDefinition() { + VarTemplateDecl *CurD = this; + while (CurD) { + if (CurD->isThisDeclarationADefinition()) + return CurD; + CurD = CurD->getPreviousDecl(); + } + return 0; +} + +VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + VarTemplateDecl *PrevDecl) { + VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl); + New->setPreviousDecl(PrevDecl); + return New; +} + +VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl)); + return new (Mem) VarTemplateDecl(EmptyShell()); +} + +// TODO: Unify accross class, function and variable templates? +// May require moving this and Common to RedeclarableTemplateDecl. +void VarTemplateDecl::LoadLazySpecializations() const { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSetVector<VarTemplateSpecializationDecl> & +VarTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & +VarTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +VarTemplateDecl::newCommon(ASTContext &C) const { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +VarTemplateSpecializationDecl * +VarTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, + void *InsertPos) { + if (InsertPos) + getSpecializations().InsertNode(D, InsertPos); + else { + VarTemplateSpecializationDecl *Existing = + getSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); +} + +void VarTemplateDecl::AddPartialSpecialization( + VarTemplatePartialSpecializationDecl *D, void *InsertPos) { + if (InsertPos) + getPartialSpecializations().InsertNode(D, InsertPos); + else { + VarTemplatePartialSpecializationDecl *Existing = + getPartialSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +void VarTemplateDecl::getPartialSpecializations( + SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs = + getPartialSpecializations(); + PS.clear(); + PS.reserve(PartialSpecs.size()); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), + PEnd = PartialSpecs.end(); + P != PEnd; ++P) + PS.push_back(P->getMostRecentDecl()); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// VarTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( + ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) + : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T, + TInfo, S), + SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), + SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK) + : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, + SC_None), + ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) { + VarTemplateSpecializationDecl *Result = new (Context) + VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC, + StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs); + return Result; +} + +VarTemplateSpecializationDecl * +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + void *Mem = + AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl)); + VarTemplateSpecializationDecl *Result = + new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization); + return Result; +} + +void VarTemplateSpecializationDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); +} + +VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<VarTemplateDecl *>(); +} + +void VarTemplateSpecializationDecl::setTemplateArgsInfo( + const TemplateArgumentListInfo &ArgsInfo) { + unsigned N = ArgsInfo.size(); + TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc()); + TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc()); + for (unsigned I = 0; I != N; ++I) + TemplateArgsInfo.addArgument(ArgsInfo[I]); +} + +//===----------------------------------------------------------------------===// +// VarTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +void VarTemplatePartialSpecializationDecl::anchor() {} + +VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const ASTTemplateArgumentListInfo *ArgInfos) + : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization, + DC, StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + InstantiatedFromMember(0, false) { + // TODO: The template parameters should be in DC by now. Verify. + // AdoptTemplateParameterList(Params, DC); +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos) { + const ASTTemplateArgumentListInfo *ASTArgInfos + = ASTTemplateArgumentListInfo::Create(Context, ArgInfos); + + VarTemplatePartialSpecializationDecl *Result = + new (Context) VarTemplatePartialSpecializationDecl( + Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, + S, Args, NumArgs, ASTArgInfos); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + return Result; +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl( + C, ID, sizeof(VarTemplatePartialSpecializationDecl)); + VarTemplatePartialSpecializationDecl *Result = + new (Mem) VarTemplatePartialSpecializationDecl(); + return Result; +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index e4a41b6ffb50..e064e23a0ae9 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { llvm_unreachable("Invalid DeclarationName Kind!"); } +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { + switch (N.getNameKind()) { + case DeclarationName::Identifier: + if (const IdentifierInfo *II = N.getAsIdentifierInfo()) + OS << II->getName(); + return OS; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return OS << N.getObjCSelector().getAsString(); + + case DeclarationName::CXXConstructorName: { + QualType ClassType = N.getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) + return OS << *ClassRec->getDecl(); + return OS << ClassType.getAsString(); + } + + case DeclarationName::CXXDestructorName: { + OS << '~'; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + + case DeclarationName::CXXOperatorName: { + static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { + 0, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = OperatorNames[N.getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + + OS << "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + OS << ' '; + return OS << OpName; + } + + case DeclarationName::CXXLiteralOperatorName: + return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName(); + + case DeclarationName::CXXConversionFunctionName: { + OS << "operator "; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + case DeclarationName::CXXUsingDirective: + return OS << "<using-directive>"; + } + + llvm_unreachable("Unexpected declaration name kind"); +} + } // end namespace clang DeclarationName::NameKind DeclarationName::getNameKind() const { @@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const { std::string DeclarationName::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); - printName(OS); + OS << *this; return OS.str(); } -void DeclarationName::printName(raw_ostream &OS) const { - switch (getNameKind()) { - case Identifier: - if (const IdentifierInfo *II = getAsIdentifierInfo()) - OS << II->getName(); - return; - - case ObjCZeroArgSelector: - case ObjCOneArgSelector: - case ObjCMultiArgSelector: - OS << getObjCSelector().getAsString(); - return; - - case CXXConstructorName: { - QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - OS << *ClassRec->getDecl(); - else - OS << ClassType.getAsString(); - return; - } - - case CXXDestructorName: { - OS << '~'; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - - case CXXOperatorName: { - static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - 0, -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - const char *OpName = OperatorNames[getCXXOverloadedOperator()]; - assert(OpName && "not an overloaded operator"); - - OS << "operator"; - if (OpName[0] >= 'a' && OpName[0] <= 'z') - OS << ' '; - OS << OpName; - return; - } - - case CXXLiteralOperatorName: - OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); - return; - - case CXXConversionFunctionName: { - OS << "operator "; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - case CXXUsingDirective: - OS << "<using-directive>"; - return; - } - - llvm_unreachable("Unexpected declaration name kind"); -} - QualType DeclarationName::getCXXNameType() const { if (CXXSpecialName *CXXName = getAsCXXSpecialName()) return CXXName->Type; @@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - printName(llvm::errs()); - llvm::errs() << '\n'; + llvm::errs() << *this << '\n'; } DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { @@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: - Name.printName(OS); + OS << Name; return; case DeclarationName::CXXConstructorName: @@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) OS << "operator "; OS << TInfo->getType().getAsString(); - } - else - Name.printName(OS); + } else + OS << Name; return; } llvm_unreachable("Unexpected declaration name kind"); diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp deleted file mode 100644 index be22ae450b62..000000000000 --- a/lib/AST/DumpXML.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the Decl::dumpXML() method, a debugging tool to -// print a detailed graph of an AST in an unspecified XML format. -// -// There is no guarantee of stability for this format. -// -//===----------------------------------------------------------------------===// - -// 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" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/Stmt.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TemplateBase.h" -#include "clang/AST/TemplateName.h" -#include "clang/AST/Type.h" -#include "clang/AST/TypeLoc.h" -#include "clang/AST/TypeLocVisitor.h" -#include "clang/AST/TypeVisitor.h" -#include "llvm/ADT/SmallString.h" - -using namespace clang; - -#ifndef NDEBUG - -namespace { - -enum NodeState { - NS_Attrs, NS_LazyChildren, NS_Children -}; - -struct Node { - StringRef Name; - NodeState State; - Node(StringRef name) : Name(name), State(NS_Attrs) {} - - bool isDoneWithAttrs() const { return State != NS_Attrs; } -}; - -template <class Impl> struct XMLDeclVisitor { -#define DISPATCH(NAME, CLASS) \ - static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) - - void dispatch(Decl *D) { - if (D->isUsed()) - static_cast<Impl*>(this)->set("used", "1"); - switch (D->getKind()) { -#define DECL(DERIVED, BASE) \ - case Decl::DERIVED: \ - DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \ - static_cast<Impl*>(this)->completeAttrs(); \ - DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \ - DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \ - break; -#define ABSTRACT_DECL(DECL) -#include "clang/AST/DeclNodes.inc" - } - } - -#define DECL(DERIVED, BASE) \ - void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \ - DISPATCH(dispatch##BASE##Attrs, BASE); \ - DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \ - } \ - void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \ - void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \ - DISPATCH(dispatch##BASE##Children, BASE); \ - DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \ - } \ - void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \ - void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \ - DISPATCH(dispatch##BASE##AsContext, BASE); \ - DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \ - } \ - void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {} -#include "clang/AST/DeclNodes.inc" - - void dispatchDeclAttrs(Decl *D) { - DISPATCH(visitDeclAttrs, Decl); - } - void visitDeclAttrs(Decl *D) {} - - void dispatchDeclChildren(Decl *D) { - DISPATCH(visitDeclChildren, Decl); - } - void visitDeclChildren(Decl *D) {} - - void dispatchDeclAsContext(Decl *D) { - DISPATCH(visitDeclAsContext, Decl); - } - void visitDeclAsContext(Decl *D) {} - -#undef DISPATCH -}; - -template <class Impl> struct XMLTypeVisitor { -#define DISPATCH(NAME, CLASS) \ - static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T)) - - void dispatch(Type *T) { - switch (T->getTypeClass()) { -#define TYPE(DERIVED, BASE) \ - case Type::DERIVED: \ - DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \ - static_cast<Impl*>(this)->completeAttrs(); \ - DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \ - break; -#define ABSTRACT_TYPE(DERIVED, BASE) -#include "clang/AST/TypeNodes.def" - } - } - -#define TYPE(DERIVED, BASE) \ - void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \ - DISPATCH(dispatch##BASE##Attrs, BASE); \ - DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \ - } \ - void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \ - void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \ - DISPATCH(dispatch##BASE##Children, BASE); \ - DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \ - } \ - void visit##DERIVED##TypeChildren(DERIVED##Type *T) {} -#include "clang/AST/TypeNodes.def" - - void dispatchTypeAttrs(Type *T) { - DISPATCH(visitTypeAttrs, Type); - } - void visitTypeAttrs(Type *T) {} - - void dispatchTypeChildren(Type *T) { - DISPATCH(visitTypeChildren, Type); - } - void visitTypeChildren(Type *T) {} - -#undef DISPATCH -}; - -static StringRef getTypeKindName(Type *T) { - switch (T->getTypeClass()) { -#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; -#define ABSTRACT_TYPE(DERIVED, BASE) -#include "clang/AST/TypeNodes.def" - } - - llvm_unreachable("unknown type kind!"); -} - -struct XMLDumper : public XMLDeclVisitor<XMLDumper>, - public XMLTypeVisitor<XMLDumper> { - raw_ostream &out; - ASTContext &Context; - SmallVector<Node, 16> Stack; - unsigned Indent; - explicit XMLDumper(raw_ostream &OS, ASTContext &context) - : out(OS), Context(context), Indent(0) {} - - void indent() { - for (unsigned I = Indent; I; --I) - out << ' '; - } - - /// Push a new node on the stack. - void push(StringRef name) { - if (!Stack.empty()) { - assert(Stack.back().isDoneWithAttrs()); - if (Stack.back().State == NS_LazyChildren) { - Stack.back().State = NS_Children; - out << ">\n"; - } - Indent++; - indent(); - } - Stack.push_back(Node(name)); - out << '<' << name; - } - - /// Set the given attribute to the given value. - void set(StringRef attr, StringRef value) { - assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); - out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation - } - - /// Finish attributes. - void completeAttrs() { - assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); - Stack.back().State = NS_LazyChildren; - } - - /// Pop a node. - void pop() { - assert(!Stack.empty() && Stack.back().isDoneWithAttrs()); - if (Stack.back().State == NS_LazyChildren) { - out << "/>\n"; - } else { - indent(); - out << "</" << Stack.back().Name << ">\n"; - } - if (Stack.size() > 1) Indent--; - Stack.pop_back(); - } - - //---- General utilities -------------------------------------------// - - void setPointer(StringRef prop, const void *p) { - SmallString<10> buffer; - llvm::raw_svector_ostream os(buffer); - os << p; - os.flush(); - set(prop, buffer); - } - - void setPointer(void *p) { - setPointer("ptr", p); - } - - void setInteger(StringRef prop, const llvm::APSInt &v) { - set(prop, v.toString(10)); - } - - void setInteger(StringRef prop, unsigned n) { - SmallString<10> buffer; - llvm::raw_svector_ostream os(buffer); - os << n; - os.flush(); - set(prop, buffer); - } - - void setFlag(StringRef prop, bool flag) { - if (flag) set(prop, "true"); - } - - void setName(DeclarationName Name) { - if (!Name) - return set("name", ""); - - // Common case. - if (Name.isIdentifier()) - return set("name", Name.getAsIdentifierInfo()->getName()); - - set("name", Name.getAsString()); - } - - class TemporaryContainer { - XMLDumper &Dumper; - public: - TemporaryContainer(XMLDumper &dumper, StringRef name) - : Dumper(dumper) { - Dumper.push(name); - Dumper.completeAttrs(); - } - - ~TemporaryContainer() { - Dumper.pop(); - } - }; - - void visitTemplateParameters(TemplateParameterList *L) { - push("template_parameters"); - completeAttrs(); - for (TemplateParameterList::iterator - I = L->begin(), E = L->end(); I != E; ++I) - dispatch(*I); - pop(); - } - - void visitTemplateArguments(const TemplateArgumentList &L) { - push("template_arguments"); - completeAttrs(); - for (unsigned I = 0, E = L.size(); I != E; ++I) - dispatch(L[I]); - pop(); - } - - /// Visits a reference to the given declaration. - void visitDeclRef(Decl *D) { - push(D->getDeclKindName()); - setPointer("ref", D); - completeAttrs(); - pop(); - } - void visitDeclRef(StringRef Name, Decl *D) { - TemporaryContainer C(*this, Name); - if (D) visitDeclRef(D); - } - - void dispatch(const TemplateArgument &A) { - switch (A.getKind()) { - case TemplateArgument::Null: { - TemporaryContainer C(*this, "null"); - break; - } - case TemplateArgument::Type: { - dispatch(A.getAsType()); - break; - } - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: - case TemplateArgument::NullPtr: - // FIXME: Implement! - break; - - case TemplateArgument::Declaration: { - visitDeclRef(A.getAsDecl()); - break; - } - case TemplateArgument::Integral: { - push("integer"); - setInteger("value", A.getAsIntegral()); - completeAttrs(); - pop(); - break; - } - case TemplateArgument::Expression: { - dispatch(A.getAsExpr()); - break; - } - case TemplateArgument::Pack: { - for (TemplateArgument::pack_iterator P = A.pack_begin(), - PEnd = A.pack_end(); - P != PEnd; ++P) - dispatch(*P); - break; - } - } - } - - void dispatch(const TemplateArgumentLoc &A) { - dispatch(A.getArgument()); - } - - //---- Declarations ------------------------------------------------// - // Calls are made in this order: - // # Enter a new node. - // push("FieldDecl") - // - // # In this phase, attributes are set on the node. - // visitDeclAttrs(D) - // visitNamedDeclAttrs(D) - // ... - // visitFieldDeclAttrs(D) - // - // # No more attributes after this point. - // completeAttrs() - // - // # Create "header" child nodes, i.e. those which logically - // # belong to the declaration itself. - // visitDeclChildren(D) - // visitNamedDeclChildren(D) - // ... - // visitFieldDeclChildren(D) - // - // # Create nodes for the lexical children. - // visitDeclAsContext(D) - // visitNamedDeclAsContext(D) - // ... - // visitFieldDeclAsContext(D) - // - // # Finish the node. - // pop(); - void dispatch(Decl *D) { - push(D->getDeclKindName()); - XMLDeclVisitor<XMLDumper>::dispatch(D); - pop(); - } - void visitDeclAttrs(Decl *D) { - setPointer(D); - } - - /// Visit all the lexical decls in the given context. - void visitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - dispatch(*I); - - // FIXME: point out visible declarations not in lexical context? - } - - /// Set the "access" attribute on the current node according to the - /// given specifier. - void setAccess(AccessSpecifier AS) { - switch (AS) { - case AS_public: return set("access", "public"); - case AS_protected: return set("access", "protected"); - case AS_private: return set("access", "private"); - case AS_none: llvm_unreachable("explicit forbidden access"); - } - } - - template <class T> void visitRedeclarableAttrs(T *D) { - if (T *Prev = D->getPreviousDecl()) - setPointer("previous", Prev); - } - - - // TranslationUnitDecl - void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { - visitDeclContext(D); - } - - // LinkageSpecDecl - void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { - StringRef lang = ""; - switch (D->getLanguage()) { - case LinkageSpecDecl::lang_c: lang = "C"; break; - case LinkageSpecDecl::lang_cxx: lang = "C++"; break; - } - set("lang", lang); - } - void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) { - visitDeclContext(D); - } - - // NamespaceDecl - void visitNamespaceDeclAttrs(NamespaceDecl *D) { - setFlag("inline", D->isInline()); - if (!D->isOriginalNamespace()) - setPointer("original", D->getOriginalNamespace()); - } - void visitNamespaceDeclAsContext(NamespaceDecl *D) { - visitDeclContext(D); - } - - // NamedDecl - void visitNamedDeclAttrs(NamedDecl *D) { - setName(D->getDeclName()); - } - - // ValueDecl - void visitValueDeclChildren(ValueDecl *D) { - dispatch(D->getType()); - } - - // DeclaratorDecl - void visitDeclaratorDeclChildren(DeclaratorDecl *D) { - //dispatch(D->getTypeSourceInfo()->getTypeLoc()); - } - - // VarDecl - void visitVarDeclAttrs(VarDecl *D) { - visitRedeclarableAttrs(D); - if (D->getStorageClass() != SC_None) - set("storage", - VarDecl::getStorageClassSpecifierString(D->getStorageClass())); - StringRef initStyle = ""; - switch (D->getInitStyle()) { - case VarDecl::CInit: initStyle = "c"; break; - case VarDecl::CallInit: initStyle = "call"; break; - case VarDecl::ListInit: initStyle = "list"; break; - } - set("initstyle", initStyle); - setFlag("nrvo", D->isNRVOVariable()); - // TODO: instantiation, etc. - } - void visitVarDeclChildren(VarDecl *D) { - if (D->hasInit()) dispatch(D->getInit()); - } - - // ParmVarDecl? - - // FunctionDecl - void visitFunctionDeclAttrs(FunctionDecl *D) { - visitRedeclarableAttrs(D); - setFlag("pure", D->isPure()); - setFlag("trivial", D->isTrivial()); - setFlag("returnzero", D->hasImplicitReturnZero()); - setFlag("prototype", D->hasWrittenPrototype()); - setFlag("deleted", D->isDeletedAsWritten()); - if (D->getStorageClass() != SC_None) - set("storage", - VarDecl::getStorageClassSpecifierString(D->getStorageClass())); - setFlag("inline", D->isInlineSpecified()); - if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) - set("asmlabel", ALA->getLabel()); - // TODO: instantiation, etc. - } - void visitFunctionDeclChildren(FunctionDecl *D) { - for (FunctionDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) - dispatch(*I); - for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(), - E = D->getDeclsInPrototypeScope().end(); - I != E; ++I) - dispatch(*I); - if (D->doesThisDeclarationHaveABody()) - dispatch(D->getBody()); - } - - // CXXMethodDecl ? - // CXXConstructorDecl ? - // CXXDestructorDecl ? - // CXXConversionDecl ? - - void dispatch(CXXCtorInitializer *Init) { - // TODO - } - - // FieldDecl - void visitFieldDeclAttrs(FieldDecl *D) { - setFlag("mutable", D->isMutable()); - } - void visitFieldDeclChildren(FieldDecl *D) { - if (D->isBitField()) { - TemporaryContainer C(*this, "bitwidth"); - dispatch(D->getBitWidth()); - } - // TODO: C++0x member initializer - } - - // EnumConstantDecl - void visitEnumConstantDeclChildren(EnumConstantDecl *D) { - // value in any case? - if (D->getInitExpr()) dispatch(D->getInitExpr()); - } - - // IndirectFieldDecl - void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) { - for (IndirectFieldDecl::chain_iterator - I = D->chain_begin(), E = D->chain_end(); I != E; ++I) { - NamedDecl *VD = const_cast<NamedDecl*>(*I); - push(isa<VarDecl>(VD) ? "variable" : "field"); - setPointer("ptr", VD); - completeAttrs(); - pop(); - } - } - - // TypeDecl - void visitTypeDeclAttrs(TypeDecl *D) { - setPointer("typeptr", D->getTypeForDecl()); - } - - // TypedefDecl - void visitTypedefDeclAttrs(TypedefDecl *D) { - visitRedeclarableAttrs<TypedefNameDecl>(D); - } - void visitTypedefDeclChildren(TypedefDecl *D) { - dispatch(D->getTypeSourceInfo()->getTypeLoc()); - } - - // TypeAliasDecl - void visitTypeAliasDeclAttrs(TypeAliasDecl *D) { - visitRedeclarableAttrs<TypedefNameDecl>(D); - } - void visitTypeAliasDeclChildren(TypeAliasDecl *D) { - dispatch(D->getTypeSourceInfo()->getTypeLoc()); - } - - // TagDecl - void visitTagDeclAttrs(TagDecl *D) { - visitRedeclarableAttrs(D); - } - void visitTagDeclAsContext(TagDecl *D) { - visitDeclContext(D); - } - - // EnumDecl - void visitEnumDeclAttrs(EnumDecl *D) { - setFlag("scoped", D->isScoped()); - setFlag("fixed", D->isFixed()); - } - void visitEnumDeclChildren(EnumDecl *D) { - { - TemporaryContainer C(*this, "promotion_type"); - dispatch(D->getPromotionType()); - } - { - TemporaryContainer C(*this, "integer_type"); - dispatch(D->getIntegerType()); - } - } - - // RecordDecl ? - - void visitCXXRecordDeclChildren(CXXRecordDecl *D) { - if (!D->isThisDeclarationADefinition()) return; - - for (CXXRecordDecl::base_class_iterator - I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { - push("base"); - setAccess(I->getAccessSpecifier()); - completeAttrs(); - dispatch(I->getTypeSourceInfo()->getTypeLoc()); - pop(); - } - } - - // ClassTemplateSpecializationDecl ? - - // FileScopeAsmDecl ? - - // BlockDecl - void visitBlockDeclAttrs(BlockDecl *D) { - setFlag("variadic", D->isVariadic()); - } - void visitBlockDeclChildren(BlockDecl *D) { - for (FunctionDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) - dispatch(*I); - dispatch(D->getBody()); - } - - // AccessSpecDecl - void visitAccessSpecDeclAttrs(AccessSpecDecl *D) { - setAccess(D->getAccess()); - } - - // TemplateDecl - void visitTemplateDeclChildren(TemplateDecl *D) { - visitTemplateParameters(D->getTemplateParameters()); - if (D->getTemplatedDecl()) - dispatch(D->getTemplatedDecl()); - } - - // FunctionTemplateDecl - void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) { - visitRedeclarableAttrs(D); - } - void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) { - // Mention all the specializations which don't have explicit - // declarations elsewhere. - for (FunctionTemplateDecl::spec_iterator - I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { - FunctionTemplateSpecializationInfo *Info - = I->getTemplateSpecializationInfo(); - - bool Unknown = false; - switch (Info->getTemplateSpecializationKind()) { - case TSK_ImplicitInstantiation: Unknown = false; break; - case TSK_Undeclared: Unknown = true; break; - - // These will be covered at their respective sites. - case TSK_ExplicitSpecialization: continue; - case TSK_ExplicitInstantiationDeclaration: continue; - case TSK_ExplicitInstantiationDefinition: continue; - } - - TemporaryContainer C(*this, - Unknown ? "uninstantiated" : "instantiation"); - visitTemplateArguments(*Info->TemplateArguments); - dispatch(Info->Function); - } - } - - // ClasTemplateDecl - void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) { - visitRedeclarableAttrs(D); - } - void visitClassTemplateDeclChildren(ClassTemplateDecl *D) { - // Mention all the specializations which don't have explicit - // declarations elsewhere. - for (ClassTemplateDecl::spec_iterator - I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { - - bool Unknown = false; - switch (I->getTemplateSpecializationKind()) { - case TSK_ImplicitInstantiation: Unknown = false; break; - case TSK_Undeclared: Unknown = true; break; - - // These will be covered at their respective sites. - case TSK_ExplicitSpecialization: continue; - case TSK_ExplicitInstantiationDeclaration: continue; - case TSK_ExplicitInstantiationDefinition: continue; - } - - TemporaryContainer C(*this, - Unknown ? "uninstantiated" : "instantiation"); - visitTemplateArguments(I->getTemplateArgs()); - dispatch(*I); - } - } - - // TemplateTypeParmDecl - void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) { - setInteger("depth", D->getDepth()); - setInteger("index", D->getIndex()); - } - void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) { - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - dispatch(D->getDefaultArgumentInfo()->getTypeLoc()); - // parameter pack? - } - - // NonTypeTemplateParmDecl - void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) { - setInteger("depth", D->getDepth()); - setInteger("index", D->getIndex()); - } - void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) { - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - dispatch(D->getDefaultArgument()); - // parameter pack? - } - - // TemplateTemplateParmDecl - void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) { - setInteger("depth", D->getDepth()); - setInteger("index", D->getIndex()); - } - void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) { - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - dispatch(D->getDefaultArgument()); - // parameter pack? - } - - // FriendDecl - void visitFriendDeclChildren(FriendDecl *D) { - if (TypeSourceInfo *T = D->getFriendType()) - dispatch(T->getTypeLoc()); - else - dispatch(D->getFriendDecl()); - } - - // UsingDirectiveDecl ? - // UsingDecl ? - // UsingShadowDecl ? - // NamespaceAliasDecl ? - // UnresolvedUsingValueDecl ? - // UnresolvedUsingTypenameDecl ? - // StaticAssertDecl ? - - // ObjCImplDecl - void visitObjCImplDeclChildren(ObjCImplDecl *D) { - visitDeclRef(D->getClassInterface()); - } - void visitObjCImplDeclAsContext(ObjCImplDecl *D) { - visitDeclContext(D); - } - - void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { - setPointer("typeptr", D->getTypeForDecl()); - setFlag("forward_decl", !D->isThisDeclarationADefinition()); - setFlag("implicit_interface", D->isImplicitInterfaceDecl()); - } - void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { - visitDeclRef("super", D->getSuperClass()); - visitDeclRef("implementation", D->getImplementation()); - if (D->protocol_begin() != D->protocol_end()) { - TemporaryContainer C(*this, "protocols"); - for (ObjCInterfaceDecl::protocol_iterator - I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) - visitDeclRef(*I); - } - - 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); - } - - // ObjCCategoryDecl - void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { - setFlag("extension", D->IsClassExtension()); - } - void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) { - visitDeclRef("interface", D->getClassInterface()); - visitDeclRef("implementation", D->getImplementation()); - if (D->protocol_begin() != D->protocol_end()) { - TemporaryContainer C(*this, "protocols"); - for (ObjCCategoryDecl::protocol_iterator - I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) - visitDeclRef(*I); - } - } - void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) { - visitDeclContext(D); - } - - // ObjCCategoryImplDecl - void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) { - set("identifier", D->getName()); - } - void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) { - visitDeclRef(D->getCategoryDecl()); - } - - // ObjCImplementationDecl - void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) { - set("identifier", D->getName()); - } - void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) { - visitDeclRef("super", D->getSuperClass()); - if (D->init_begin() != D->init_end()) { - TemporaryContainer C(*this, "initializers"); - for (ObjCImplementationDecl::init_iterator - I = D->init_begin(), E = D->init_end(); I != E; ++I) - dispatch(*I); - } - } - - // ObjCProtocolDecl - void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { - if (!D->isThisDeclarationADefinition()) - return; - - if (D->protocol_begin() != D->protocol_end()) { - TemporaryContainer C(*this, "protocols"); - for (ObjCInterfaceDecl::protocol_iterator - I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) - visitDeclRef(*I); - } - } - void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) { - if (!D->isThisDeclarationADefinition()) - return; - - visitDeclContext(D); - } - - // ObjCMethodDecl - void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { - // decl qualifier? - // implementation control? - - setFlag("instance", D->isInstanceMethod()); - setFlag("variadic", D->isVariadic()); - setFlag("property_accessor", D->isPropertyAccessor()); - setFlag("defined", D->isDefined()); - setFlag("related_result_type", D->hasRelatedResultType()); - } - void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { - dispatch(D->getResultType()); - for (ObjCMethodDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) - dispatch(*I); - if (D->isThisDeclarationADefinition()) - dispatch(D->getBody()); - } - - // ObjCIvarDecl - void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) { - switch (AC) { - case ObjCIvarDecl::None: return set(prop, "none"); - case ObjCIvarDecl::Private: return set(prop, "private"); - case ObjCIvarDecl::Protected: return set(prop, "protected"); - case ObjCIvarDecl::Public: return set(prop, "public"); - case ObjCIvarDecl::Package: return set(prop, "package"); - } - } - void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) { - setFlag("synthesize", D->getSynthesize()); - setAccessControl("access", D->getAccessControl()); - } - - // ObjCCompatibleAliasDecl - void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) { - visitDeclRef(D->getClassInterface()); - } - - // FIXME: ObjCPropertyDecl - // FIXME: ObjCPropertyImplDecl - - //---- Types -----------------------------------------------------// - void dispatch(TypeLoc TL) { - dispatch(TL.getType()); // for now - } - - void dispatch(QualType T) { - if (T.hasLocalQualifiers()) { - push("QualType"); - Qualifiers Qs = T.getLocalQualifiers(); - setFlag("const", Qs.hasConst()); - setFlag("volatile", Qs.hasVolatile()); - setFlag("restrict", Qs.hasRestrict()); - if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace()); - if (Qs.hasObjCGCAttr()) { - switch (Qs.getObjCGCAttr()) { - case Qualifiers::Weak: set("gc", "weak"); break; - case Qualifiers::Strong: set("gc", "strong"); break; - case Qualifiers::GCNone: llvm_unreachable("explicit none"); - } - } - - completeAttrs(); - dispatch(QualType(T.getTypePtr(), 0)); - pop(); - return; - } - - Type *Ty = const_cast<Type*>(T.getTypePtr()); - push(getTypeKindName(Ty)); - XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr())); - pop(); - } - - void setCallingConv(CallingConv CC) { - switch (CC) { - case CC_Default: return; - case CC_C: return set("cc", "cdecl"); - case CC_X86FastCall: return set("cc", "x86_fastcall"); - case CC_X86StdCall: return set("cc", "x86_stdcall"); - case CC_X86ThisCall: return set("cc", "x86_thiscall"); - case CC_X86Pascal: return set("cc", "x86_pascal"); - 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"); - } - } - - void visitTypeAttrs(Type *D) { - setPointer(D); - setFlag("dependent", D->isDependentType()); - setFlag("variably_modified", D->isVariablyModifiedType()); - - setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr()); - } - - void visitPointerTypeChildren(PointerType *T) { - dispatch(T->getPointeeType()); - } - void visitReferenceTypeChildren(ReferenceType *T) { - dispatch(T->getPointeeType()); - } - void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) { - dispatch(T->getPointeeType()); - } - void visitBlockPointerTypeChildren(BlockPointerType *T) { - dispatch(T->getPointeeType()); - } - - // Types that just wrap declarations. - void visitTagTypeChildren(TagType *T) { - visitDeclRef(T->getDecl()); - } - void visitTypedefTypeChildren(TypedefType *T) { - visitDeclRef(T->getDecl()); - } - void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) { - visitDeclRef(T->getDecl()); - } - void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) { - visitDeclRef(T->getDecl()); - } - void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) { - visitDeclRef(T->getDecl()); - } - - void visitFunctionTypeAttrs(FunctionType *T) { - setFlag("noreturn", T->getNoReturnAttr()); - setCallingConv(T->getCallConv()); - if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType()); - } - void visitFunctionTypeChildren(FunctionType *T) { - dispatch(T->getResultType()); - } - - void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { - setFlag("const", T->isConst()); - setFlag("volatile", T->isVolatile()); - setFlag("restrict", T->isRestrict()); - switch (T->getExceptionSpecType()) { - case EST_None: break; - case EST_DynamicNone: set("exception_spec", "throw()"); break; - case EST_Dynamic: set("exception_spec", "throw(T)"); break; - case EST_MSAny: set("exception_spec", "throw(...)"); break; - case EST_BasicNoexcept: set("exception_spec", "noexcept"); break; - case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break; - case EST_Unevaluated: set("exception_spec", "unevaluated"); break; - case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break; - } - } - void visitFunctionProtoTypeChildren(FunctionProtoType *T) { - push("parameters"); - setFlag("variadic", T->isVariadic()); - completeAttrs(); - for (FunctionProtoType::arg_type_iterator - I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I) - dispatch(*I); - pop(); - - if (T->hasDynamicExceptionSpec()) { - push("exception_specifiers"); - setFlag("any", T->getExceptionSpecType() == EST_MSAny); - completeAttrs(); - for (FunctionProtoType::exception_iterator - I = T->exception_begin(), E = T->exception_end(); I != E; ++I) - dispatch(*I); - pop(); - } - // FIXME: noexcept specifier - } - - void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { - if (const RecordType *RT = T->getAs<RecordType>()) - visitDeclRef(RT->getDecl()); - - // TODO: TemplateName - - push("template_arguments"); - completeAttrs(); - for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) - dispatch(T->getArg(I)); - pop(); - } - - //---- Statements ------------------------------------------------// - void dispatch(Stmt *S) { - // FIXME: this is not really XML at all - push("Stmt"); - out << ">\n"; - Stack.back().State = NS_Children; // explicitly become non-lazy - S->dump(out, Context.getSourceManager()); - out << '\n'; - pop(); - } -}; -} - -void Decl::dumpXML() const { - dumpXML(llvm::errs()); -} - -void Decl::dumpXML(raw_ostream &out) const { - XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); -} - -#else /* ifndef NDEBUG */ - -void Decl::dumpXML() const {} -void Decl::dumpXML(raw_ostream &out) const {} - -#endif diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9538ddf9416c..9055ddac35e3 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -20,6 +20,7 @@ #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" @@ -50,9 +51,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return cast<CXXRecordDecl>(D); } -const Expr * -Expr::skipRValueSubobjectAdjustments( - SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { +const Expr *Expr::skipRValueSubobjectAdjustments( + SmallVectorImpl<const Expr *> &CommaLHSs, + SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { const Expr *E = this; while (true) { E = E->IgnoreParens(); @@ -73,12 +74,14 @@ Expr::skipRValueSubobjectAdjustments( continue; } } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (!ME->isArrow() && ME->getBase()->isRValue()) { + if (!ME->isArrow()) { assert(ME->getBase()->getType()->isRecordType()); if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { - E = ME->getBase(); - Adjustments.push_back(SubobjectAdjustment(Field)); - continue; + if (!Field->isBitField() && !Field->getType()->isReferenceType()) { + E = ME->getBase(); + Adjustments.push_back(SubobjectAdjustment(Field)); + continue; + } } } } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { @@ -88,6 +91,11 @@ Expr::skipRValueSubobjectAdjustments( const MemberPointerType *MPT = BO->getRHS()->getType()->getAs<MemberPointerType>(); Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS())); + continue; + } else if (BO->getOpcode() == BO_Comma) { + CommaLHSs.push_back(BO->getLHS()); + E = BO->getRHS(); + continue; } } @@ -231,8 +239,8 @@ SourceLocation Expr::getExprLoc() const { /// \brief Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. -static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, - bool &TypeDependent, +static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D, + QualType T, bool &TypeDependent, bool &ValueDependent, bool &InstantiationDependent) { TypeDependent = false; @@ -307,6 +315,9 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, Var->getDeclContext()->isDependentContext()) { ValueDependent = true; InstantiationDependent = true; + TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo(); + if (TInfo->getType()->isIncompleteArrayType()) + TypeDependent = true; } return; @@ -321,7 +332,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, } } -void DeclRefExpr::computeDependence(ASTContext &Ctx) { +void DeclRefExpr::computeDependence(const ASTContext &Ctx) { bool TypeDependent = false; bool ValueDependent = false; bool InstantiationDependent = false; @@ -355,7 +366,7 @@ void DeclRefExpr::computeDependence(ASTContext &Ctx) { ExprBits.ContainsUnexpandedParameterPack = true; } -DeclRefExpr::DeclRefExpr(ASTContext &Ctx, +DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingLocal, @@ -392,7 +403,7 @@ DeclRefExpr::DeclRefExpr(ASTContext &Ctx, computeDependence(Ctx); } -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, +DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, @@ -408,7 +419,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, T, VK, FoundD, TemplateArgs); } -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, +DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, @@ -423,7 +434,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, FoundD = 0; std::size_t Size = sizeof(DeclRefExpr); - if (QualifierLoc != 0) + if (QualifierLoc) Size += sizeof(NestedNameSpecifierLoc); if (FoundD) Size += sizeof(NamedDecl *); @@ -438,7 +449,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, NameInfo, FoundD, TemplateArgs, T, VK); } -DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, +DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, @@ -471,6 +482,30 @@ SourceLocation DeclRefExpr::getLocEnd() const { std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { ASTContext &Context = CurrentDecl->getASTContext(); + if (IT == PredefinedExpr::FuncDName) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) { + OwningPtr<MangleContext> MC; + MC.reset(Context.createMangleContext()); + + if (MC->shouldMangleDeclName(ND)) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND)) + MC->mangleCXXCtor(CD, Ctor_Base, Out); + else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND)) + MC->mangleCXXDtor(DD, Dtor_Base, Out); + else + MC->mangleName(ND, Out); + + Out.flush(); + if (!Buffer.empty() && Buffer.front() == '\01') + return Buffer.substr(1); + return Buffer.str(); + } else + return ND->getIdentifier()->getName(); + } + return ""; + } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual) return FD->getNameAsString(); @@ -578,7 +613,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { POut.flush(); - if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) + // Print "auto" for all deduced return types. This includes C++1y return + // type deduction and lambdas. For trailing return types resolve the + // decltype expression. Otherwise print the real type when this is + // not a constructor or destructor. + if ((isa<CXXMethodDecl>(FD) && + cast<CXXMethodDecl>(FD)->getParent()->isLambda()) || + (FT && FT->getResultType()->getAs<AutoType>())) + Proto = "auto " + Proto; + else if (FT && FT->getResultType()->getAs<DecltypeType>()) + FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType() + .getAsStringInternal(Proto, Policy); + else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) AFT->getResultType().getAsStringInternal(Proto, Policy); Out << Proto; @@ -586,6 +632,16 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { Out.flush(); return Name.str().str(); } + if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) { + for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent()) + // Skip to its enclosing function or method, but not its enclosing + // CapturedDecl. + if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) { + const Decl *D = Decl::castFromDeclContext(DC); + return ComputeName(IT, D); + } + llvm_unreachable("CapturedDecl not inside a function or method"); + } if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) { SmallString<256> Name; llvm::raw_svector_ostream Out(Name); @@ -615,7 +671,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { return ""; } -void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { +void APNumericStorage::setIntValue(const ASTContext &C, + const llvm::APInt &Val) { if (hasAllocation()) C.Deallocate(pVal); @@ -631,7 +688,7 @@ void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { VAL = 0; } -IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V, +IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, false, false), @@ -643,17 +700,17 @@ IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V, } IntegerLiteral * -IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V, +IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) { return new (C) IntegerLiteral(C, V, type, l); } IntegerLiteral * -IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) { +IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) IntegerLiteral(Empty); } -FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V, +FloatingLiteral::FloatingLiteral(const 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) { @@ -662,20 +719,20 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V, setValue(C, V); } -FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty) +FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { setRawSemantics(IEEEhalf); FloatingLiteralBits.IsExact = false; } FloatingLiteral * -FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V, +FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) { return new (C) FloatingLiteral(C, V, isexact, Type, L); } FloatingLiteral * -FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) { +FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } @@ -749,7 +806,7 @@ int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) { return CharByteWidth; } -StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str, +StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs) { @@ -771,7 +828,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str, return SL; } -StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { +StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C, + unsigned NumStrs) { void *Mem = C.Allocate(sizeof(StringLiteral)+ sizeof(SourceLocation)*(NumStrs-1), llvm::alignOf<StringLiteral>()); @@ -875,7 +933,7 @@ void StringLiteral::outputString(raw_ostream &OS) const { OS << '"'; } -void StringLiteral::setString(ASTContext &C, StringRef Str, +void StringLiteral::setString(const ASTContext &C, StringRef Str, StringKind Kind, bool IsPascal) { //FIXME: we assume that the string data comes from a target that uses the same // code unit size and endianess for the type of string. @@ -1028,9 +1086,9 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { // Postfix Operators. //===----------------------------------------------------------------------===// -CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, - ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation rparenloc) +CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, + unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t, + ExprValueKind VK, SourceLocation rparenloc) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), @@ -1057,7 +1115,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, +CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(CallExprClass, t, VK, OK_Ordinary, fn->isTypeDependent(), @@ -1085,14 +1143,14 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) +CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty) : Expr(SC, Empty), SubExprs(0), NumArgs(0) { // FIXME: Why do we allocate this? SubExprs = new (C) Stmt*[PREARGS_START]; CallExprBits.NumPreArgs = 0; } -CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, +CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty) : Expr(SC, Empty), SubExprs(0), NumArgs(0) { // FIXME: Why do we allocate this? @@ -1131,7 +1189,7 @@ FunctionDecl *CallExpr::getDirectCallee() { /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. -void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { +void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) { // No change, just return. if (NumArgs == getNumArgs()) return; @@ -1220,7 +1278,7 @@ SourceLocation CallExpr::getLocEnd() const { return end; } -OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, +OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef<OffsetOfNode> comps, @@ -1234,7 +1292,7 @@ OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, RParenLoc); } -OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, +OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C, unsigned numComps, unsigned numExprs) { void *Mem = C.Allocate(sizeof(OffsetOfExpr) + sizeof(OffsetOfNode) * numComps + @@ -1242,7 +1300,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, return new (Mem) OffsetOfExpr(numComps, numExprs); } -OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, +OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, SourceLocation RParenLoc) @@ -1276,7 +1334,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask); } -MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, +MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *memberdecl, @@ -1630,7 +1688,7 @@ void CastExpr::setCastPath(const CXXCastPath &Path) { memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*)); } -ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, +ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind VK) { @@ -1643,7 +1701,7 @@ ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, return E; } -ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, +ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); @@ -1651,7 +1709,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, } -CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, +CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, @@ -1665,7 +1723,8 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, return E; } -CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C, + unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize); @@ -1774,7 +1833,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, +InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), @@ -1782,7 +1841,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true) { sawArrayRangeDesignator(false); - setInitializesStdInitializerList(false); for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; @@ -1797,16 +1855,16 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); } -void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { +void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) InitExprs.reserve(C, NumInits); } -void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { +void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) { InitExprs.resize(C, NumInits, 0); } -Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { +Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0); InitExprs.back() = expr; @@ -1923,6 +1981,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case GenericSelectionExprClass: return cast<GenericSelectionExpr>(this)->getResultExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + case ChooseExprClass: + return cast<ChooseExpr>(this)->getChosenSubExpr()-> + isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); @@ -2066,17 +2127,24 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; case CXXTemporaryObjectExprClass: - case CXXConstructExprClass: + case CXXConstructExprClass: { + if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) { + if (Type->hasAttr<WarnUnusedAttr>()) { + WarnE = this; + Loc = getLocStart(); + R1 = getSourceRange(); + return true; + } + } return false; + } case ObjCMessageExprClass: { const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this); if (Ctx.getLangOpts().ObjCAutoRefCount && ME->isInstanceMessage() && !ME->getType()->isVoidType() && - ME->getSelector().getIdentifierInfoForSlot(0) && - ME->getSelector().getIdentifierInfoForSlot(0) - ->getName().startswith("init")) { + ME->getMethodFamily() == OMF_init) { WarnE = this; Loc = getExprLoc(); R1 = ME->getSourceRange(); @@ -2161,7 +2229,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, WarnE = this; if (const CXXFunctionalCastExpr *CXXCE = dyn_cast<CXXFunctionalCastExpr>(this)) { - Loc = CXXCE->getTypeBeginLoc(); + Loc = CXXCE->getLocStart(); R1 = CXXCE->getSubExpr()->getSourceRange(); } else { const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this); @@ -2291,6 +2359,12 @@ Expr* Expr::IgnoreParens() { continue; } } + if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) { + if (!P->isConditionDependent()) { + E = P->getChosenSubExpr(); + continue; + } + } return E; } } @@ -2300,26 +2374,11 @@ Expr* Expr::IgnoreParens() { Expr *Expr::IgnoreParenCasts() { Expr *E = this; while (true) { - if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *P = dyn_cast<CastExpr>(E)) { E = P->getSubExpr(); continue; } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2341,24 +2400,12 @@ Expr *Expr::IgnoreParenCasts() { Expr *Expr::IgnoreParenLValueCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } else if (CastExpr *P = dyn_cast<CastExpr>(E)) { + E = E->IgnoreParens(); + if (CastExpr *P = dyn_cast<CastExpr>(E)) { if (P->getCastKind() == CK_LValueToRValue) { E = P->getSubExpr(); continue; } - } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } } else if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2376,10 +2423,7 @@ Expr *Expr::IgnoreParenLValueCasts() { Expr *Expr::ignoreParenBaseCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *CE = dyn_cast<CastExpr>(E)) { if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase || @@ -2396,26 +2440,11 @@ Expr *Expr::ignoreParenBaseCasts() { Expr *Expr::IgnoreParenImpCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) { E = P->getSubExpr(); continue; } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2444,10 +2473,7 @@ Expr *Expr::IgnoreConversionOperator() { Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *P = dyn_cast<CastExpr>(E)) { // We ignore integer <-> casts that are of the same width, ptr<->ptr and @@ -2469,20 +2495,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } - if (SubstNonTypeTemplateParmExpr *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { E = NTTP->getReplacement(); @@ -2628,11 +2640,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) { bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { // This function is attempting whether an expression is an initializer - // which can be evaluated at compile-time. isEvaluatable handles most - // of the cases, but it can't deal with some initializer-specific - // expressions, and it can't deal with aggregates; we deal with those here, - // and fall back to isEvaluatable for the other cases. - + // which can be evaluated at compile-time. It very closely parallels + // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it + // will lead to unexpected results. Like ConstExprEmitter, it falls back + // to isEvaluatable most of the time. + // // If we ever capture reference-binding directly in the AST, we can // kill the second parameter. @@ -2643,30 +2655,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { switch (getStmtClass()) { default: break; - case IntegerLiteralClass: - case FloatingLiteralClass: case StringLiteralClass: - case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { const CXXConstructExpr *CE = cast<CXXConstructExpr>(this); - // Only if it's - if (CE->getConstructor()->isTrivial()) { - // 1) an application of the trivial default constructor or + if (CE->getConstructor()->isTrivial() && + CE->getConstructor()->getParent()->hasTrivialDestructor()) { + // Trivial default constructor if (!CE->getNumArgs()) return true; - // 2) an elidable trivial copy construction of an operand which is - // itself a constant initializer. Note that we consider the - // operand on its own, *not* as a reference binding. - if (CE->isElidable() && - CE->getArg(0)->isConstantInitializer(Ctx, false)) - return true; + // Trivial copy constructor + assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument"); + return CE->getArg(0)->isConstantInitializer(Ctx, false); } - // 3) a foldable constexpr constructor. break; } case CompoundLiteralExprClass: { @@ -2677,16 +2682,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return Exp->isConstantInitializer(Ctx, false); } case InitListExprClass: { - // FIXME: This doesn't deal with fields with reference types correctly. - // FIXME: This incorrectly allows pointers cast to integers to be assigned - // to bitfields. - const InitListExpr *Exp = cast<InitListExpr>(this); - unsigned numInits = Exp->getNumInits(); - for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx, false)) - return false; + const InitListExpr *ILE = cast<InitListExpr>(this); + if (ILE->getType()->isArrayType()) { + unsigned numInits = ILE->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!ILE->getInit(i)->isConstantInitializer(Ctx, false)) + return false; + } + return true; } - return true; + + if (ILE->getType()->isRecordType()) { + unsigned ElementNo = 0; + RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isUnnamedBitfield()) + continue; + + if (ElementNo < ILE->getNumInits()) { + const Expr *Elt = ILE->getInit(ElementNo++); + if (Field->isBitField()) { + // Bitfields have to evaluate to an integer. + llvm::APSInt ResultTmp; + if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) + return false; + } else { + bool RefType = Field->getType()->isReferenceType(); + if (!Elt->isConstantInitializer(Ctx, RefType)) + return false; + } + } + } + return true; + } + + break; } case ImplicitValueInitExprClass: return true; @@ -2694,12 +2730,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return cast<ParenExpr>(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef); case GenericSelectionExprClass: - if (cast<GenericSelectionExpr>(this)->isResultDependent()) - return false; return cast<GenericSelectionExpr>(this)->getResultExpr() ->isConstantInitializer(Ctx, IsForRef); case ChooseExprClass: - return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx) + if (cast<ChooseExpr>(this)->isConditionDependent()) + return false; + return cast<ChooseExpr>(this)->getChosenSubExpr() ->isConstantInitializer(Ctx, IsForRef); case UnaryOperatorClass: { const UnaryOperator* Exp = cast<UnaryOperator>(this); @@ -2710,31 +2746,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: - case CStyleCastExprClass: { + case CStyleCastExprClass: + case ObjCBridgedCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: { const CastExpr *CE = cast<CastExpr>(this); - // If we're promoting an integer to an _Atomic type then this is constant - // if the integer is constant. We also need to check the converse in case - // someone does something like: - // - // int a = (_Atomic(int))42; - // - // I doubt anyone would write code like this directly, but it's quite - // possible as the result of macro expansions. - if (CE->getCastKind() == CK_NonAtomicToAtomic || - CE->getCastKind() == CK_AtomicToNonAtomic) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - - // Handle bitcasts of vector constants. - if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle misc casts we want to ignore. - // FIXME: Is it really safe to ignore all these? if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue || CE->getCastKind() == CK_ToUnion || - CE->getCastKind() == CK_ConstructorConversion) + CE->getCastKind() == CK_ConstructorConversion || + CE->getCastKind() == CK_NonAtomicToAtomic || + CE->getCastKind() == CK_AtomicToNonAtomic) return CE->getSubExpr()->isConstantInitializer(Ctx, false); break; @@ -2742,6 +2767,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case MaterializeTemporaryExprClass: return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() ->isConstantInitializer(Ctx, false); + + case SubstNonTypeTemplateParmExprClass: + return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement() + ->isConstantInitializer(Ctx, false); + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr() + ->isConstantInitializer(Ctx, false); + case CXXDefaultInitExprClass: + return cast<CXXDefaultInitExpr>(this)->getExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } @@ -2829,9 +2864,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case DesignatedInitExprClass: case ParenListExprClass: case CXXPseudoDestructorExprClass: + case CXXStdInitializerListExprClass: case SubstNonTypeTemplateParmExprClass: case MaterializeTemporaryExprClass: case ShuffleVectorExprClass: + case ConvertVectorExprClass: case AsTypeExprClass: // These have a side-effect if any subexpression does. break; @@ -2858,7 +2895,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { HasSideEffects(Ctx); case ChooseExprClass: - return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx); + return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx); case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); @@ -3017,7 +3054,8 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) { Expr::NullPointerConstantKind Expr::isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const { - if (isValueDependent()) { + if (isValueDependent() && + (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) { switch (NPC) { case NPC_NeverValueDependent: llvm_unreachable("Unexpected value dependent expression!"); @@ -3053,7 +3091,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const GenericSelectionExpr *GE = dyn_cast<GenericSelectionExpr>(this)) { + if (GE->isResultDependent()) + return NPCK_NotNull; return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) { + if (CE->isConditionDependent()) + return NPCK_NotNull; + return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { // See through default argument expressions. @@ -3078,7 +3122,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) - if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) + if (!Ctx.getLangOpts().CPlusPlus11 && + UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){ const Expr *InitExpr = CLE->getInitializer(); if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr)) @@ -3089,14 +3134,19 @@ Expr::isNullPointerConstant(ASTContext &Ctx, (Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType())) return NPCK_NotNull; - // If we have an integer constant expression, we need to *evaluate* it and - // 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().CPlusPlus11) { - if (!isCXX98IntegralConstantExpr(Ctx)) + // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with + // value zero or a prvalue of type std::nullptr_t. + // Microsoft mode permits C++98 rules reflecting MSVC behavior. + const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this); + if (Lit && !Lit->getValue()) + return NPCK_ZeroLiteral; + else if (!Ctx.getLangOpts().MicrosoftMode || + !isCXX98IntegralConstantExpr(Ctx)) return NPCK_NotNull; } else { + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. if (!isIntegerConstantExpr(Ctx)) return NPCK_NotNull; } @@ -3370,7 +3420,7 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args, } } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, @@ -3395,7 +3445,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, Method, Args, RBracLoc, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, @@ -3418,7 +3468,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, @@ -3441,14 +3491,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context, unsigned NumArgs, unsigned NumStoredSelLocs) { ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs); return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); } -ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, +ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, ArrayRef<Expr *> Args, SourceLocation RBraceLoc, ArrayRef<SourceLocation> SelLocs, @@ -3460,7 +3510,7 @@ ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, return alloc(C, Args.size(), NumStoredSelLocs); } -ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, +ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, unsigned NumArgs, unsigned NumStoredSelLocs) { unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + @@ -3537,11 +3587,7 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const { llvm_unreachable("Invalid BridgeKind!"); } -bool ChooseExpr::isConditionTrue(const ASTContext &C) const { - return getCond()->EvaluateKnownConstInt(C) != 0; -} - -ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, +ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type, SourceLocation BLoc, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, @@ -3565,16 +3611,15 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, } } -void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, - unsigned NumExprs) { +void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) { if (SubExprs) C.Deallocate(SubExprs); - SubExprs = new (C) Stmt* [NumExprs]; - this->NumExprs = NumExprs; - memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); + this->NumExprs = Exprs.size(); + SubExprs = new (C) Stmt*[NumExprs]; + memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size()); } -GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, +GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<Expr*> AssocExprs, @@ -3600,7 +3645,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } -GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, +GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<Expr*> AssocExprs, @@ -3637,7 +3682,7 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const { return getField()->getIdentifier(); } -DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, +DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, @@ -3704,7 +3749,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, } DesignatedInitExpr * -DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, +DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators, unsigned NumDesignators, ArrayRef<Expr*> IndexExprs, SourceLocation ColonOrEqualLoc, @@ -3716,14 +3761,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, IndexExprs, Init); } -DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C, unsigned NumIndexExprs) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } -void DesignatedInitExpr::setDesignators(ASTContext &C, +void DesignatedInitExpr::setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs) { Designators = new (C) Designator[NumDesigs]; @@ -3790,7 +3835,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const { /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). -void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, +void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; @@ -3815,7 +3860,7 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, NumDesignators = NumDesignators - 1 + NumNewDesignators; } -ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, +ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs, SourceLocation rparenloc) : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, @@ -3847,7 +3892,8 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { return cast<OpaqueValueExpr>(e); } -PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh, +PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context, + EmptyShell sh, unsigned numSemanticExprs) { void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) + (1 + numSemanticExprs) * sizeof(Expr*), @@ -3860,7 +3906,7 @@ PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs) PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1; } -PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax, +PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax, ArrayRef<Expr*> semantics, unsigned resultIndex) { assert(syntax && "no syntactic expression!"); @@ -3975,7 +4021,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements, } } -ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C, +ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C, ArrayRef<Expr *> Elements, QualType T, ObjCMethodDecl * Method, SourceRange SR) { @@ -3984,7 +4030,7 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C, return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR); } -ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C, +ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements) { void *Mem = C.Allocate(sizeof(ObjCArrayLiteral) @@ -4029,7 +4075,7 @@ ObjCDictionaryLiteral::ObjCDictionaryLiteral( } ObjCDictionaryLiteral * -ObjCDictionaryLiteral::Create(ASTContext &C, +ObjCDictionaryLiteral::Create(const ASTContext &C, ArrayRef<ObjCDictionaryElement> VK, bool HasPackExpansions, QualType T, ObjCMethodDecl *method, @@ -4044,7 +4090,7 @@ ObjCDictionaryLiteral::Create(ASTContext &C, } ObjCDictionaryLiteral * -ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements, +ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements, bool HasPackExpansions) { unsigned ExpansionsSize = 0; if (HasPackExpansions) @@ -4055,7 +4101,7 @@ ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements, HasPackExpansions); } -ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C, +ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C, Expr *base, Expr *key, QualType T, ObjCMethodDecl *getMethod, diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 402d7b532b21..3738c0e4f2c9 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -40,46 +40,106 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const { return false; } -QualType CXXTypeidExpr::getTypeOperand() const { +QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); - return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() - .getUnqualifiedType(); + Qualifiers Quals; + return Context.getUnqualifiedArrayType( + Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals); } -QualType CXXUuidofExpr::getTypeOperand() const { +QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); - return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() - .getUnqualifiedType(); + Qualifiers Quals; + return Context.getUnqualifiedArrayType( + Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals); } // static -UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) { +UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT, + bool *RDHasMultipleGUIDsPtr) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); if (QT->isPointerType() || QT->isReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) - Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + Ty = Ty->getBaseElementTypeUnsafe(); // Loop all record redeclaration looking for an uuid attribute. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return 0; + + // __uuidof can grab UUIDs from template arguments. + if (ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + UuidAttr *UuidForRD = 0; + + for (unsigned I = 0, N = TAL.size(); I != N; ++I) { + const TemplateArgument &TA = TAL[I]; + bool SeenMultipleGUIDs = false; + + UuidAttr *UuidForTA = 0; + if (TA.getKind() == TemplateArgument::Type) + UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs); + else if (TA.getKind() == TemplateArgument::Declaration) + UuidForTA = + GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs); + + // If the template argument has a UUID, there are three cases: + // - This is the first UUID seen for this RecordDecl. + // - This is a different UUID than previously seen for this RecordDecl. + // - This is the same UUID than previously seen for this RecordDecl. + if (UuidForTA) { + if (!UuidForRD) + UuidForRD = UuidForTA; + else if (UuidForRD != UuidForTA) + SeenMultipleGUIDs = true; + } + + // Seeing multiple UUIDs means that we couldn't find a UUID + if (SeenMultipleGUIDs) { + if (RDHasMultipleGUIDsPtr) + *RDHasMultipleGUIDsPtr = true; + return 0; + } + } + + return UuidForRD; + } + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), - E = RD->redecls_end(); I != E; ++I) { + E = RD->redecls_end(); + I != E; ++I) if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) return Uuid; - } return 0; } +StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const { + StringRef Uuid; + if (isTypeOperand()) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(getTypeOperand(Context))->getGuid(); + else { + // Special case: __uuidof(0) means an all-zero GUID. + Expr *Op = getExprOperand(); + if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid(); + else + Uuid = "00000000-0000-0000-0000-000000000000"; + } + return Uuid; +} + // CXXScalarValueInitExpr SourceLocation CXXScalarValueInitExpr::getLocStart() const { return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc; } // CXXNewExpr -CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, - FunctionDecl *operatorDelete, +CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew, + FunctionDecl *operatorNew, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, ArrayRef<Expr*> placementArgs, SourceRange typeIdParens, Expr *arraySize, @@ -134,11 +194,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, this->Range.setEnd(DirectInitRange.getEnd()); break; case ListInit: this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break; - default: break; + default: + if (TypeIdParens.isValid()) + this->Range.setEnd(TypeIdParens.getEnd()); + break; } } -void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, +void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray, unsigned numPlaceArgs, bool hasInitializer){ assert(SubExprs == 0 && "SubExprs already allocated"); Array = isArray; @@ -148,7 +211,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, SubExprs = new (C) Stmt*[TotalSize]; } -bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { +bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { return getOperatorNew()->getType()-> castAs<FunctionProtoType>()->isNothrow(Ctx); } @@ -172,14 +235,16 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } -CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, +CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context, Expr *Base, bool isArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, None, - FunctionProtoType::ExtProtoInfo())), + Context.getPointerType(Context.getFunctionType( + Context.VoidTy, None, + FunctionProtoType::ExtProtoInfo( + Context.getDefaultCallingConvention(false, true)))), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || (DestroyedType.getTypeSourceInfo() && @@ -224,7 +289,7 @@ SourceLocation CXXPseudoDestructorExpr::getLocEnd() const { // UnresolvedLookupExpr UnresolvedLookupExpr * -UnresolvedLookupExpr::Create(ASTContext &C, +UnresolvedLookupExpr::Create(const ASTContext &C, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, @@ -245,7 +310,7 @@ UnresolvedLookupExpr::Create(ASTContext &C, } UnresolvedLookupExpr * -UnresolvedLookupExpr::CreateEmpty(ASTContext &C, +UnresolvedLookupExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedLookupExpr); @@ -258,7 +323,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, return E; } -OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, +OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, @@ -330,7 +395,7 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, setType(C.DependentTy); } -void OverloadExpr::initializeResults(ASTContext &C, +void OverloadExpr::initializeResults(const ASTContext &C, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { assert(Results == 0 && "Results already initialized!"); @@ -386,11 +451,12 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, } DependentScopeDeclRefExpr * -DependentScopeDeclRefExpr::Create(ASTContext &C, +DependentScopeDeclRefExpr::Create(const ASTContext &C, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { + assert(QualifierLoc && "should be created for dependent qualifiers"); std::size_t size = sizeof(DependentScopeDeclRefExpr); if (Args) size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size()); @@ -402,7 +468,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, } DependentScopeDeclRefExpr * -DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, +DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(DependentScopeDeclRefExpr); @@ -427,8 +493,8 @@ SourceLocation CXXConstructExpr::getLocEnd() const { if (isa<CXXTemporaryObjectExpr>(this)) return cast<CXXTemporaryObjectExpr>(this)->getLocEnd(); - if (ParenRange.isValid()) - return ParenRange.getEnd(); + if (ParenOrBraceRange.isValid()) + return ParenOrBraceRange.getEnd(); SourceLocation End = Loc; for (unsigned I = getNumArgs(); I > 0; --I) { @@ -520,7 +586,7 @@ const char *CXXNamedCastExpr::getCastName() const { } } -CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, +CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, @@ -538,14 +604,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, return E; } -CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C, +CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize); } -CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, +CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, @@ -563,7 +629,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, return E; } -CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, +CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); @@ -604,8 +670,8 @@ bool CXXDynamicCastExpr::isAlwaysNull() const } CXXReinterpretCastExpr * -CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, - CastKind K, Expr *Op, +CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, @@ -621,13 +687,13 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, } CXXReinterpretCastExpr * -CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); } -CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, +CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, Expr *Op, TypeSourceInfo *WrittenTy, SourceLocation L, @@ -636,31 +702,39 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets); } -CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { +CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) { return new (C) CXXConstCastExpr(EmptyShell()); } CXXFunctionalCastExpr * -CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, - TypeSourceInfo *Written, SourceLocation L, - CastKind K, Expr *Op, const CXXCastPath *BasePath, - SourceLocation R) { +CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, + TypeSourceInfo *Written, CastKind K, Expr *Op, + const CXXCastPath *BasePath, + SourceLocation L, SourceLocation R) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXFunctionalCastExpr *E = - new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R); + new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R); if (PathSize) E->setCastPath(*BasePath); return E; } CXXFunctionalCastExpr * -CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize); } +SourceLocation CXXFunctionalCastExpr::getLocStart() const { + return getTypeInfoAsWritten()->getTypeLoc().getLocStart(); +} + +SourceLocation CXXFunctionalCastExpr::getLocEnd() const { + return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getLocEnd(); +} + UserDefinedLiteral::LiteralOperatorKind UserDefinedLiteral::getLiteralOperatorKind() const { if (getNumArgs() == 0) @@ -696,14 +770,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const { } CXXDefaultArgExpr * -CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, +CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc, ParmVarDecl *Param, Expr *SubExpr) { void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *)); return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, SubExpr); } -CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, +CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field, QualType T) : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C), T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType() @@ -714,12 +788,12 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, assert(Field->hasInClassInitializer()); } -CXXTemporary *CXXTemporary::Create(ASTContext &C, +CXXTemporary *CXXTemporary::Create(const ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } -CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, +CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { assert((SubExpr->getType()->isRecordType() || @@ -729,11 +803,11 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } -CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, +CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C, CXXConstructorDecl *Cons, TypeSourceInfo *Type, ArrayRef<Expr*> Args, - SourceRange parenRange, + SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization) @@ -743,7 +817,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, Cons, false, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, - CXXConstructExpr::CK_Complete, parenRange), + CXXConstructExpr::CK_Complete, ParenOrBraceRange), Type(Type) { } @@ -752,10 +826,13 @@ SourceLocation CXXTemporaryObjectExpr::getLocStart() const { } SourceLocation CXXTemporaryObjectExpr::getLocEnd() const { - return getParenRange().getEnd(); + SourceLocation Loc = getParenOrBraceRange().getEnd(); + if (Loc.isInvalid() && getNumArgs()) + Loc = getArg(getNumArgs()-1)->getLocEnd(); + return Loc; } -CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, +CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, ArrayRef<Expr*> Args, @@ -763,28 +840,29 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, - SourceRange ParenRange) { + SourceRange ParenOrBraceRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, ConstructKind, - ParenRange); + ParenOrBraceRange); } -CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, - SourceLocation Loc, +CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, + QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, ArrayRef<Expr*> args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, - SourceRange ParenRange) + SourceRange ParenOrBraceRange) : Expr(SC, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()), + Constructor(D), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange), + NumArgs(args.size()), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ListInitialization(ListInitialization), ZeroInitialization(ZeroInitialization), @@ -811,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) - : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) + : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; if (Implicit) @@ -829,20 +907,22 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, assert(Var && "capture must have a variable!"); break; } - VarAndBits.setInt(Bits); + DeclAndBits.setInt(Bits); } LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const { - if (capturesThis()) + Decl *D = DeclAndBits.getPointer(); + if (!D) return LCK_This; - return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef; + return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef; } -LambdaExpr::LambdaExpr(QualType T, +LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef<Capture> Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef<Capture> Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, @@ -854,6 +934,7 @@ LambdaExpr::LambdaExpr(QualType T, T->isDependentType(), T->isDependentType(), T->isDependentType(), ContainsUnexpandedParameterPack), IntroducerRange(IntroducerRange), + CaptureDefaultLoc(CaptureDefaultLoc), NumCaptures(Captures.size()), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), @@ -867,7 +948,7 @@ LambdaExpr::LambdaExpr(QualType T, // FIXME: Propagate "has unexpanded parameter pack" bit. // Copy captures. - ASTContext &Context = Class->getASTContext(); + const ASTContext &Context = Class->getASTContext(); Data.NumCaptures = NumCaptures; Data.NumExplicitCaptures = 0; Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures); @@ -899,11 +980,12 @@ LambdaExpr::LambdaExpr(QualType T, } } -LambdaExpr *LambdaExpr::Create(ASTContext &Context, +LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef<Capture> Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef<Capture> Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, @@ -923,13 +1005,15 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, Size += sizeof(VarDecl *) * ArrayIndexVars.size(); } void *Mem = Context.Allocate(Size); - return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, - Captures, ExplicitParams, ExplicitResultType, + return new (Mem) LambdaExpr(T, IntroducerRange, + CaptureDefault, CaptureDefaultLoc, Captures, + ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, ClosingBrace, ContainsUnexpandedParameterPack); } -LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures, +LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, + unsigned NumCaptures, unsigned NumArrayIndexVars) { unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1); if (NumArrayIndexVars) @@ -984,13 +1068,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const { CXXMethodDecl *LambdaExpr::getCallOperator() const { CXXRecordDecl *Record = getLambdaClass(); - DeclarationName Name - = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_result Calls = Record->lookup(Name); - assert(!Calls.empty() && "Missing lambda call operator!"); - assert(Calls.size() == 1 && "More than one lambda call operator!"); - CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front()); - return Result; + return Record->getLambdaCallOperator(); +} + +TemplateParameterList *LambdaExpr::getTemplateParameterList() const { + CXXRecordDecl *Record = getLambdaClass(); + return Record->getGenericLambdaTemplateParameterList(); + } CompoundStmt *LambdaExpr::getBody() const { @@ -1017,7 +1101,7 @@ ExprWithCleanups::ExprWithCleanups(Expr *subexpr, getObjectsBuffer()[i] = objects[i]; } -ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr, +ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr, ArrayRef<CleanupObject> objects) { size_t size = sizeof(ExprWithCleanups) + objects.size() * sizeof(CleanupObject); @@ -1030,7 +1114,8 @@ ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects) ExprWithCleanupsBits.NumObjects = numObjects; } -ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty, +ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, + EmptyShell empty, unsigned numObjects) { size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject); void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>()); @@ -1063,7 +1148,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::Create(ASTContext &C, +CXXUnresolvedConstructExpr::Create(const ASTContext &C, TypeSourceInfo *Type, SourceLocation LParenLoc, ArrayRef<Expr*> Args, @@ -1074,7 +1159,7 @@ CXXUnresolvedConstructExpr::Create(ASTContext &C, } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) { +CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) { Stmt::EmptyShell Empty; void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + sizeof(Expr *) * NumArgs); @@ -1085,7 +1170,7 @@ SourceLocation CXXUnresolvedConstructExpr::getLocStart() const { return Type->getTypeLoc().getBeginLoc(); } -CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -1121,7 +1206,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, } } -CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -1142,7 +1227,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, MemberNameInfo(MemberNameInfo) { } CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::Create(ASTContext &C, +CXXDependentScopeMemberExpr::Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -1171,7 +1256,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, } CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, +CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { if (!HasTemplateKWAndArgsInfo) @@ -1222,7 +1307,7 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, return true; } -UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, +UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, @@ -1260,8 +1345,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const { } UnresolvedMemberExpr * -UnresolvedMemberExpr::Create(ASTContext &C, - bool HasUnresolvedUsing, +UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -1284,7 +1368,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, } UnresolvedMemberExpr * -UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo, +UnresolvedMemberExpr::CreateEmpty(const ASTContext &C, + bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedMemberExpr); if (HasTemplateKWAndArgsInfo) @@ -1352,7 +1437,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, } FunctionParmPackExpr * -FunctionParmPackExpr::Create(ASTContext &Context, QualType T, +FunctionParmPackExpr::Create(const ASTContext &Context, QualType T, ParmVarDecl *ParamPack, SourceLocation NameLoc, ArrayRef<Decl *> Params) { return new (Context.Allocate(sizeof(FunctionParmPackExpr) + @@ -1361,7 +1446,8 @@ FunctionParmPackExpr::Create(ASTContext &Context, QualType T, } FunctionParmPackExpr * -FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) { +FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, + unsigned NumParams) { return new (Context.Allocate(sizeof(FunctionParmPackExpr) + sizeof(ParmVarDecl*) * NumParams)) FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0); @@ -1396,7 +1482,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, } } -TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T, +TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef<TypeSourceInfo *> Args, @@ -1407,7 +1493,7 @@ TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T, return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value); } -TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C, +TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C, unsigned NumArgs) { unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs; void *Mem = C.Allocate(Size); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index bcb6d4e809bf..54f77efef0f9 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::OffsetOfExprClass: case Expr::CXXThrowExprClass: case Expr::ShuffleVectorExprClass: + case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: @@ -286,13 +287,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // __builtin_choose_expr is equivalent to the chosen expression. case Expr::ChooseExprClass: - return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx)); + return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr()); // Extended vector element access is an lvalue unless there are duplicates // in the shuffle expression. case Expr::ExtVectorElementExprClass: - return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ? - Cl::CL_DuplicateVectorComponents : Cl::CL_LValue; + if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements()) + return Cl::CL_DuplicateVectorComponents; + if (cast<ExtVectorElementExpr>(E)->isArrow()) + return Cl::CL_LValue; + return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase()); // Simply look at the actual default argument. case Expr::CXXDefaultArgExprClass: @@ -353,6 +357,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXConstructExprClass: case Expr::CXXTemporaryObjectExprClass: case Expr::LambdaExprClass: + case Expr::CXXStdInitializerListExprClass: return Cl::CL_ClassTemporary; case Expr::VAArgExprClass: @@ -587,6 +592,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Const stuff is obviously not modifiable. if (CT.isConstQualified()) return Cl::CM_ConstQualified; + if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant) + return Cl::CM_ConstQualified; // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8c650290b579..390cfe9cd235 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -23,8 +23,8 @@ // where it is possible to determine the evaluated result regardless. // // * A set of notes indicating why the evaluation was not a constant expression -// (under the C++11 rules only, at the moment), or, if folding failed too, -// why the expression could not be folded. +// (under the C++11 / C++1y rules only, at the moment), or, if folding failed +// too, why the expression could not be folded. // // If we are checking for a potential constant expression, failure to constant // fold a potential constant sub-expression will be indicated by a 'false' @@ -63,7 +63,25 @@ namespace { if (!B) return QualType(); if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) return D->getType(); - return B.get<const Expr*>()->getType(); + + const Expr *Base = B.get<const Expr*>(); + + // For a materialized temporary, the type of the temporary we materialized + // may not be the type of the expression. + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(Base)) { + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Temp = MTE->GetTemporaryExpr(); + const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs, + Adjustments); + // Keep any cv-qualifiers from the reference if we generated a temporary + // for it. + if (Inner != Temp) + return Inner->getType(); + } + + return Base->getType(); } /// Get an LValue path entry, which is known to not be an array index, as a @@ -284,7 +302,7 @@ namespace { /// This - The binding for the this pointer in this call, if any. const LValue *This; - /// ParmBindings - Parameter bindings for this function call, indexed by + /// Arguments - Parameter bindings for this function call, indexed by /// parameters' function scope indices. APValue *Arguments; @@ -299,6 +317,12 @@ namespace { const FunctionDecl *Callee, const LValue *This, APValue *Arguments); ~CallStackFrame(); + + APValue *getTemporary(const void *Key) { + MapTy::iterator I = Temporaries.find(Key); + return I == Temporaries.end() ? 0 : &I->second; + } + APValue &createTemporary(const void *Key, bool IsLifetimeExtended); }; /// Temporarily override 'this'. @@ -343,14 +367,37 @@ namespace { OptionalDiagnostic &operator<<(const APFloat &F) { if (Diag) { + // FIXME: Force the precision of the source value down so we don't + // print digits which are usually useless (we don't really care here if + // we truncate a digit by accident in edge cases). Ideally, + // APFloat::toString would automatically print the shortest + // representation which rounds to the correct value, but it's a bit + // tricky to implement. + unsigned precision = + llvm::APFloat::semanticsPrecision(F.getSemantics()); + precision = (precision * 59 + 195) / 196; SmallVector<char, 32> Buffer; - F.toString(Buffer); + F.toString(Buffer, precision); *Diag << StringRef(Buffer.data(), Buffer.size()); } return *this; } }; + /// A cleanup, and a flag indicating whether it is lifetime-extended. + class Cleanup { + llvm::PointerIntPair<APValue*, 1, bool> Value; + + public: + Cleanup(APValue *Val, bool IsLifetimeExtended) + : Value(Val, IsLifetimeExtended) {} + + bool isLifetimeExtended() const { return Value.getInt(); } + void endLifetime() { + *Value.getPointer() = APValue(); + } + }; + /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information /// about the AST context, but also maintains information about the folded @@ -380,13 +427,22 @@ namespace { /// NextCallIndex - The next call index to assign. unsigned NextCallIndex; + /// StepsLeft - The remaining number of evaluation steps we're permitted + /// to perform. This is essentially a limit for the number of statements + /// we will evaluate. + unsigned StepsLeft; + /// BottomFrame - The frame in which evaluation started. This must be /// initialized after CurrentCall and CallStackDepth. CallStackFrame BottomFrame; + /// A stack of values whose lifetimes end at the end of some surrounding + /// evaluation frame. + llvm::SmallVector<Cleanup, 16> CleanupStack; + /// EvaluatingDecl - This is the declaration whose initializer is being /// evaluated, if any. - const VarDecl *EvaluatingDecl; + APValue::LValueBase EvaluatingDecl; /// EvaluatingDeclValue - This is the value being constructed for the /// declaration whose initializer is being evaluated, if any. @@ -396,24 +452,52 @@ namespace { /// notes attached to it will also be stored, otherwise they will not be. bool HasActiveDiagnostic; - /// CheckingPotentialConstantExpression - Are we checking whether the - /// expression is a potential constant expression? If so, some diagnostics - /// are suppressed. - bool CheckingPotentialConstantExpression; - - bool IntOverflowCheckMode; + enum EvaluationMode { + /// Evaluate as a constant expression. Stop if we find that the expression + /// is not a constant expression. + EM_ConstantExpression, + + /// Evaluate as a potential constant expression. Keep going if we hit a + /// construct that we can't evaluate yet (because we don't yet know the + /// value of something) but stop if we hit something that could never be + /// a constant expression. + EM_PotentialConstantExpression, + + /// Fold the expression to a constant. Stop if we hit a side-effect that + /// we can't model. + EM_ConstantFold, + + /// Evaluate the expression looking for integer overflow and similar + /// issues. Don't worry about side-effects, and try to visit all + /// subexpressions. + EM_EvaluateForOverflow, - EvalInfo(const ASTContext &C, Expr::EvalStatus &S, - bool OverflowCheckMode=false) + /// Evaluate in any way we know how. Don't worry about side-effects that + /// can't be modeled. + EM_IgnoreSideEffects + } EvalMode; + + /// Are we checking whether the expression is a potential constant + /// expression? + bool checkingPotentialConstantExpression() const { + return EvalMode == EM_PotentialConstantExpression; + } + + /// Are we checking an expression for overflow? + // FIXME: We should check for any kind of undefined or suspicious behavior + // in such constructs, not just overflow. + bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; } + + EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0), CallStackDepth(0), NextCallIndex(1), + StepsLeft(getLangOpts().ConstexprStepLimit), BottomFrame(*this, SourceLocation(), 0, 0, 0), - EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false), - CheckingPotentialConstantExpression(false), - IntOverflowCheckMode(OverflowCheckMode) {} + EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0), + HasActiveDiagnostic(false), EvalMode(Mode) {} - void setEvaluatingDecl(const VarDecl *VD, APValue &Value) { - EvaluatingDecl = VD; + void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { + EvaluatingDecl = Base; EvaluatingDeclValue = &Value; } @@ -422,7 +506,7 @@ namespace { bool CheckCallLimit(SourceLocation Loc) { // Don't perform any constexpr calls (other than the call we're checking) // when checking a potential constant expression. - if (CheckingPotentialConstantExpression && CallStackDepth > 1) + if (checkingPotentialConstantExpression() && CallStackDepth > 1) return false; if (NextCallIndex == 0) { // NextCallIndex has wrapped around. @@ -446,6 +530,15 @@ namespace { return (Frame->Index == CallIndex) ? Frame : 0; } + bool nextStep(const Stmt *S) { + if (!StepsLeft) { + Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded); + return false; + } + --StepsLeft; + return true; + } + private: /// Add a diagnostic to the diagnostics list. PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) { @@ -462,22 +555,41 @@ namespace { OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { - // If we have a prior diagnostic, it will be noting that the expression - // isn't a constant expression. This diagnostic is more important. - // FIXME: We might want to show both diagnostics to the user. if (EvalStatus.Diag) { + // If we have a prior diagnostic, it will be noting that the expression + // isn't a constant expression. This diagnostic is more important, + // unless we require this evaluation to produce a constant expression. + // + // FIXME: We might want to show both diagnostics to the user in + // EM_ConstantFold mode. + if (!EvalStatus.Diag->empty()) { + switch (EvalMode) { + case EM_ConstantFold: + case EM_IgnoreSideEffects: + case EM_EvaluateForOverflow: + if (!EvalStatus.HasSideEffects) + break; + // We've had side-effects; we want the diagnostic from them, not + // some later problem. + case EM_ConstantExpression: + case EM_PotentialConstantExpression: + HasActiveDiagnostic = false; + return OptionalDiagnostic(); + } + } + unsigned CallStackNotes = CallStackDepth - 1; unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit(); if (Limit) CallStackNotes = std::min(CallStackNotes, Limit + 1); - if (CheckingPotentialConstantExpression) + if (checkingPotentialConstantExpression()) CallStackNotes = 0; HasActiveDiagnostic = true; EvalStatus.Diag->clear(); EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); addDiag(Loc, DiagId); - if (!CheckingPotentialConstantExpression) + if (!checkingPotentialConstantExpression()) addCallStack(Limit); return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); } @@ -494,15 +606,17 @@ namespace { return OptionalDiagnostic(); } - bool getIntOverflowCheckMode() { return IntOverflowCheckMode; } - /// Diagnose that the evaluation does not produce a C++11 core constant /// expression. + /// + /// FIXME: Stop evaluating if we're in EM_ConstantExpression or + /// EM_PotentialConstantExpression mode and we produce one of these. template<typename LocArg> OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { - // Don't override a previous diagnostic. + // Don't override a previous diagnostic. Don't bother collecting + // diagnostics if we're evaluating for overflow. if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) { HasActiveDiagnostic = false; return OptionalDiagnostic(); @@ -525,30 +639,72 @@ namespace { } } + /// Should we continue evaluation after encountering a side-effect that we + /// couldn't model? + bool keepEvaluatingAfterSideEffect() { + switch (EvalMode) { + case EM_PotentialConstantExpression: + case EM_EvaluateForOverflow: + case EM_IgnoreSideEffects: + return true; + + case EM_ConstantExpression: + case EM_ConstantFold: + return false; + } + llvm_unreachable("Missed EvalMode case"); + } + + /// Note that we have had a side-effect, and determine whether we should + /// keep evaluating. + bool noteSideEffect() { + EvalStatus.HasSideEffects = true; + return keepEvaluatingAfterSideEffect(); + } + /// Should we continue evaluation as much as possible after encountering a - /// construct which can't be folded? + /// construct which can't be reduced to a value? bool keepEvaluatingAfterFailure() { - // Should return true in IntOverflowCheckMode, so that we check for - // overflow even if some subexpressions can't be evaluated as constants. - return IntOverflowCheckMode || - (CheckingPotentialConstantExpression && - EvalStatus.Diag && EvalStatus.Diag->empty()); + if (!StepsLeft) + return false; + + switch (EvalMode) { + case EM_PotentialConstantExpression: + case EM_EvaluateForOverflow: + return true; + + case EM_ConstantExpression: + case EM_ConstantFold: + case EM_IgnoreSideEffects: + return false; + } + llvm_unreachable("Missed EvalMode case"); } }; /// Object used to treat all foldable expressions as constant expressions. struct FoldConstant { + EvalInfo &Info; bool Enabled; - - explicit FoldConstant(EvalInfo &Info) - : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() && - !Info.EvalStatus.HasSideEffects) { - } - // Treat the value we've computed since this object was created as constant. - void Fold(EvalInfo &Info) { - if (Enabled && !Info.EvalStatus.Diag->empty() && + bool HadNoPriorDiags; + EvalInfo::EvaluationMode OldMode; + + explicit FoldConstant(EvalInfo &Info, bool Enabled) + : Info(Info), + Enabled(Enabled), + HadNoPriorDiags(Info.EvalStatus.Diag && + Info.EvalStatus.Diag->empty() && + !Info.EvalStatus.HasSideEffects), + OldMode(Info.EvalMode) { + if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression) + Info.EvalMode = EvalInfo::EM_ConstantFold; + } + void keepDiagnostics() { Enabled = false; } + ~FoldConstant() { + if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() && !Info.EvalStatus.HasSideEffects) Info.EvalStatus.Diag->clear(); + Info.EvalMode = OldMode; } }; @@ -563,11 +719,50 @@ namespace { SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0) : Info(Info), Old(Info.EvalStatus) { Info.EvalStatus.Diag = NewDiag; + // If we're speculatively evaluating, we may have skipped over some + // evaluations and missed out a side effect. + Info.EvalStatus.HasSideEffects = true; } ~SpeculativeEvaluationRAII() { Info.EvalStatus = Old; } }; + + /// RAII object wrapping a full-expression or block scope, and handling + /// the ending of the lifetime of temporaries created within it. + template<bool IsFullExpression> + class ScopeRAII { + EvalInfo &Info; + unsigned OldStackSize; + public: + ScopeRAII(EvalInfo &Info) + : Info(Info), OldStackSize(Info.CleanupStack.size()) {} + ~ScopeRAII() { + // Body moved to a static method to encourage the compiler to inline away + // instances of this class. + cleanup(Info, OldStackSize); + } + private: + static void cleanup(EvalInfo &Info, unsigned OldStackSize) { + unsigned NewEnd = OldStackSize; + for (unsigned I = OldStackSize, N = Info.CleanupStack.size(); + I != N; ++I) { + if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) { + // Full-expression cleanup of a lifetime-extended temporary: nothing + // to do, just move this cleanup to the right place in the stack. + std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]); + ++NewEnd; + } else { + // End the lifetime of the object. + Info.CleanupStack[I].endLifetime(); + } + } + Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd, + Info.CleanupStack.end()); + } + }; + typedef ScopeRAII<false> BlockScopeRAII; + typedef ScopeRAII<true> FullExpressionRAII; } bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, @@ -610,32 +805,16 @@ CallStackFrame::~CallStackFrame() { Info.CurrentCall = Caller; } -/// Produce a string describing the given constexpr call. -static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { - unsigned ArgIndex = 0; - bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && - !isa<CXXConstructorDecl>(Frame->Callee) && - cast<CXXMethodDecl>(Frame->Callee)->isInstance(); - - if (!IsMemberCall) - Out << *Frame->Callee << '('; - - for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), - E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { - if (ArgIndex > (unsigned)IsMemberCall) - Out << ", "; - - const ParmVarDecl *Param = *I; - const APValue &Arg = Frame->Arguments[ArgIndex]; - Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); - - if (ArgIndex == 0 && IsMemberCall) - Out << "->" << *Frame->Callee << '('; - } - - Out << ')'; +APValue &CallStackFrame::createTemporary(const void *Key, + bool IsLifetimeExtended) { + APValue &Result = Temporaries[Key]; + assert(Result.isUninit() && "temporary created multiple times"); + Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); + return Result; } +static void describeCall(CallStackFrame *Frame, raw_ostream &Out); + void EvalInfo::addCallStack(unsigned Limit) { // Determine which calls to skip, if any. unsigned ActiveCalls = CallStackDepth - 1; @@ -884,19 +1063,11 @@ namespace { return false; return LHS.Path == RHS.Path; } - - /// Kinds of constant expression checking, for diagnostics. - enum CheckConstantExpressionKind { - CCEK_Constant, ///< A normal constant. - CCEK_ReturnValue, ///< A constexpr function return value. - CCEK_MemberInit ///< A constexpr constructor mem-initializer. - }; } static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, const Expr *E, - CheckConstantExpressionKind CCEK = CCEK_Constant, bool AllowNonLiteralTypes = false); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); @@ -908,23 +1079,66 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); +static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info); //===----------------------------------------------------------------------===// // Misc utilities //===----------------------------------------------------------------------===// +/// Produce a string describing the given constexpr call. +static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { + unsigned ArgIndex = 0; + bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && + !isa<CXXConstructorDecl>(Frame->Callee) && + cast<CXXMethodDecl>(Frame->Callee)->isInstance(); + + if (!IsMemberCall) + Out << *Frame->Callee << '('; + + if (Frame->This && IsMemberCall) { + APValue Val; + Frame->This->moveInto(Val); + Val.printPretty(Out, Frame->Info.Ctx, + Frame->This->Designator.MostDerivedType); + // FIXME: Add parens around Val if needed. + Out << "->" << *Frame->Callee << '('; + IsMemberCall = false; + } + + for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), + E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { + if (ArgIndex > (unsigned)IsMemberCall) + Out << ", "; + + const ParmVarDecl *Param = *I; + const APValue &Arg = Frame->Arguments[ArgIndex]; + Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); + + if (ArgIndex == 0 && IsMemberCall) + Out << "->" << *Frame->Callee << '('; + } + + Out << ')'; +} + /// Evaluate an expression to see if it had side-effects, and discard its /// result. /// \return \c true if the caller should keep evaluating. static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { APValue Scratch; - if (!Evaluate(Scratch, Info, E)) { - Info.EvalStatus.HasSideEffects = true; - return Info.keepEvaluatingAfterFailure(); - } + if (!Evaluate(Scratch, Info, E)) + // We don't need the value, but we might have skipped a side effect here. + return Info.noteSideEffect(); return true; } +/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just +/// return its existing value. +static int64_t getExtValue(const APSInt &Value) { + return Value.isSigned() ? Value.getSExtValue() + : static_cast<int64_t>(Value.getZExtValue()); +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -956,6 +1170,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) { const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E); return CLE->isFileScope() && CLE->isLValue(); } + case Expr::MaterializeTemporaryExprClass: + // A materialized temporary might have been lifetime-extended to static + // storage duration. + return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static; // A string literal has static storage duration. case Expr::StringLiteralClass: case Expr::PredefinedExprClass: @@ -1020,7 +1238,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Don't allow references to temporaries to escape. return false; } - assert((Info.CheckingPotentialConstantExpression || + assert((Info.checkingPotentialConstantExpression() || LVal.getLValueCallIndex() == 0) && "have call index for global lvalue"); @@ -1057,10 +1275,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. -static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { +static bool CheckLiteralType(EvalInfo &Info, const Expr *E, + const LValue *This = 0) { if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) return true; + // C++1y: A constant initializer for an object o [...] may also invoke + // constexpr constructors for o and its subobjects even if those objects + // are of non-literal class types. + if (Info.getLangOpts().CPlusPlus1y && This && + Info.EvaluatingDecl == This->getLValueBase()) + return true; + // Prvalue constant expressions must be of literal types. if (Info.getLangOpts().CPlusPlus11) Info.Diag(E, diag::note_constexpr_nonliteral) @@ -1075,6 +1301,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { /// check that the expression is of literal type. static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value) { + if (Value.isUninit()) { + Info.Diag(DiagLoc, diag::note_constexpr_uninitialized) + << true << Type; + return false; + } + // Core issue 1454: For a literal constant expression of array or class type, // each subobject of its value shall have been initialized by a constant // expression. @@ -1129,7 +1361,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { } static bool IsLiteralLValue(const LValue &Value) { - return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex; + if (Value.CallIndex) + return false; + const Expr *E = Value.Base.dyn_cast<const Expr*>(); + return E && !isa<MaterializeTemporaryExpr>(E); } static bool IsWeakLValue(const LValue &Value) { @@ -1252,6 +1487,27 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, return true; } +static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, + APValue &Value, const FieldDecl *FD) { + assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield"); + + if (!Value.isInt()) { + // Trying to store a pointer-cast-to-integer into a bitfield. + // FIXME: In this case, we should provide the diagnostic for casting + // a pointer to an integer. + assert(Value.isLValue() && "integral value neither int nor lvalue?"); + Info.Diag(E); + return false; + } + + APSInt &Int = Value.getInt(); + unsigned OldBitWidth = Int.getBitWidth(); + unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx); + if (NewBitWidth < OldBitWidth) + Int = Int.trunc(NewBitWidth).extend(OldBitWidth); + return true; +} + static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, llvm::APInt &Res) { APValue SVal; @@ -1299,6 +1555,155 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, return false; } +/// Perform the given integer operation, which is known to need at most BitWidth +/// bits, and check for overflow in the original type (if that type was not an +/// unsigned type). +template<typename Operation> +static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E, + const APSInt &LHS, const APSInt &RHS, + unsigned BitWidth, Operation Op) { + if (LHS.isUnsigned()) + return Op(LHS, RHS); + + APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); + APSInt Result = Value.trunc(LHS.getBitWidth()); + if (Result.extend(BitWidth) != Value) { + if (Info.checkingForOverflow()) + Info.Ctx.getDiagnostics().Report(E->getExprLoc(), + diag::warn_integer_constant_overflow) + << Result.toString(10) << E->getType(); + else + HandleOverflow(Info, E, Value, E->getType()); + } + return Result; +} + +/// Perform the given binary integer operation. +static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, + BinaryOperatorKind Opcode, APSInt RHS, + APSInt &Result) { + switch (Opcode) { + default: + Info.Diag(E); + return false; + case BO_Mul: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, + std::multiplies<APSInt>()); + return true; + case BO_Add: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::plus<APSInt>()); + return true; + case BO_Sub: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::minus<APSInt>()); + return true; + case BO_And: Result = LHS & RHS; return true; + case BO_Xor: Result = LHS ^ RHS; return true; + case BO_Or: Result = LHS | RHS; return true; + case BO_Div: + case BO_Rem: + if (RHS == 0) { + Info.Diag(E, diag::note_expr_divide_by_zero); + return false; + } + // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. + if (RHS.isNegative() && RHS.isAllOnesValue() && + LHS.isSigned() && LHS.isMinSignedValue()) + HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); + Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + return true; + case BO_Shl: { + if (Info.getLangOpts().OpenCL) + // OpenCL 6.3j: shift values are effectively % word size of LHS. + RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), + static_cast<uint64_t>(LHS.getBitWidth() - 1)), + RHS.isUnsigned()); + else if (RHS.isSigned() && RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such + // a shift is not a constant expression. + Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + RHS = -RHS; + goto shift_right; + } + shift_left: + // C++11 [expr.shift]p1: Shift width must be less than the bit width of + // the shifted type. + unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + if (SA != RHS) { + Info.CCEDiag(E, diag::note_constexpr_large_shift) + << RHS << E->getType() << LHS.getBitWidth(); + } else if (LHS.isSigned()) { + // C++11 [expr.shift]p2: A signed left shift must have a non-negative + // operand, and must not overflow the corresponding unsigned type. + if (LHS.isNegative()) + Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; + else if (LHS.countLeadingZeros() < SA) + Info.CCEDiag(E, diag::note_constexpr_lshift_discards); + } + Result = LHS << SA; + return true; + } + case BO_Shr: { + if (Info.getLangOpts().OpenCL) + // OpenCL 6.3j: shift values are effectively % word size of LHS. + RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), + static_cast<uint64_t>(LHS.getBitWidth() - 1)), + RHS.isUnsigned()); + else if (RHS.isSigned() && RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such a + // shift is not a constant expression. + Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + RHS = -RHS; + goto shift_left; + } + shift_right: + // C++11 [expr.shift]p1: Shift width must be less than the bit width of the + // shifted type. + unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + if (SA != RHS) + Info.CCEDiag(E, diag::note_constexpr_large_shift) + << RHS << E->getType() << LHS.getBitWidth(); + Result = LHS >> SA; + return true; + } + + case BO_LT: Result = LHS < RHS; return true; + case BO_GT: Result = LHS > RHS; return true; + case BO_LE: Result = LHS <= RHS; return true; + case BO_GE: Result = LHS >= RHS; return true; + case BO_EQ: Result = LHS == RHS; return true; + case BO_NE: Result = LHS != RHS; return true; + } +} + +/// Perform the given binary floating-point operation, in-place, on LHS. +static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, + APFloat &LHS, BinaryOperatorKind Opcode, + const APFloat &RHS) { + switch (Opcode) { + default: + Info.Diag(E); + return false; + case BO_Mul: + LHS.multiply(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Add: + LHS.add(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Sub: + LHS.subtract(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Div: + LHS.divide(RHS, APFloat::rmNearestTiesToEven); + break; + } + + if (LHS.isInfinity() || LHS.isNaN()) + Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN(); + return true; +} + /// Cast an lvalue referring to a base subobject to a derived class, by /// truncating the lvalue's path to the given length. static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, @@ -1369,6 +1774,19 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, return true; } +static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E, + QualType Type, LValue &Result) { + for (CastExpr::path_const_iterator PathI = E->path_begin(), + PathE = E->path_end(); + PathI != PathE; ++PathI) { + if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), + *PathI)) + return false; + Type = (*PathI)->getType(); + } + return true; +} + /// Update LVal to refer to the given field, which must be a member of the type /// currently described by LVal. static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, @@ -1470,7 +1888,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { // Assume arguments of a potential constant expression are unknown // constant expressions. - if (Info.CheckingPotentialConstantExpression) + if (Info.checkingPotentialConstantExpression()) return false; if (!Frame || !Frame->Arguments) { Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); @@ -1482,11 +1900,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If this is a local variable, dig out its value. if (Frame) { - Result = &Frame->Temporaries[VD]; - // If we've carried on past an unevaluatable local variable initializer, - // we can't go any further. This can happen during potential constant - // expression checking. - return !Result->isUninit(); + Result = Frame->getTemporary(VD); + assert(Result && "missing value for local variable"); + return true; } // Dig out the initializer, and use the declaration which it's attached to. @@ -1494,16 +1910,16 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, if (!Init || Init->isValueDependent()) { // If we're checking a potential constant expression, the variable could be // initialized later. - if (!Info.CheckingPotentialConstantExpression) + if (!Info.checkingPotentialConstantExpression()) Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); return false; } // If we're currently evaluating the initializer of this declaration, use that // in-flight value. - if (Info.EvaluatingDecl == VD) { + if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) { Result = Info.EvaluatingDeclValue; - return !Result->isUninit(); + return true; } // Never evaluate the initializer of a weak variable. We can't be sure that @@ -1615,7 +2031,7 @@ static void expandArray(APValue &Array, unsigned Index) { Array.swap(NewValue); } -/// Kinds of access we can perform on an object. +/// Kinds of access we can perform on an object, for diagnostics. enum AccessKinds { AK_Read, AK_Assign, @@ -1637,7 +2053,7 @@ struct CompleteObject { assert(Value && "missing value for complete object"); } - operator bool() const { return Value; } + LLVM_EXPLICIT operator bool() const { return Value; } }; /// Find the designated sub-object of an rvalue. @@ -1656,16 +2072,33 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, Info.Diag(E); return handler.failed(); } - if (Sub.Entries.empty()) - return handler.found(*Obj.Value, Obj.Type); - if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit()) - // This object might be initialized later. - return handler.failed(); APValue *O = Obj.Value; QualType ObjType = Obj.Type; + const FieldDecl *LastField = 0; + // Walk the designator's path to find the subobject. - for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { + for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { + if (O->isUninit()) { + if (!Info.checkingPotentialConstantExpression()) + Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + return handler.failed(); + } + + if (I == N) { + if (!handler.found(*O, ObjType)) + return false; + + // If we modified a bit-field, truncate it to the right width. + if (handler.AccessKind != AK_Read && + LastField && LastField->isBitField() && + !truncateBitfieldValue(Info, E, *O, LastField)) + return false; + + return true; + } + + LastField = 0; if (ObjType->isArrayType()) { // Next subobject is an array element. const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); @@ -1767,6 +2200,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } return handler.failed(); } + + LastField = Field; } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); @@ -1778,15 +2213,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if (WasConstQualified) ObjType.addConst(); } - - if (O->isUninit()) { - if (!Info.CheckingPotentialConstantExpression) - Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; - return handler.failed(); - } } - - return handler.found(*O, ObjType); } namespace { @@ -1963,9 +2390,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, NoteLValueLocation(Info, LVal.Base); return CompleteObject(); } - } else if (AK != AK_Read) { - Info.Diag(E, diag::note_constexpr_modify_global); - return CompleteObject(); } // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type @@ -1983,7 +2407,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // Compute value storage location and type of base object. APValue *BaseVal = 0; - QualType BaseType; + QualType BaseType = getType(LVal.Base); if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -2004,7 +2428,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, } // Accesses of volatile-qualified objects are not allowed. - BaseType = VD->getType(); if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) @@ -2019,8 +2442,16 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // Unless we're looking at a local variable or argument in a constexpr call, // the variable we're reading must be const. if (!Frame) { - assert(AK == AK_Read && "can't modify non-local"); - if (VD->isConstexpr()) { + if (Info.getLangOpts().CPlusPlus1y && + VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) { + // OK, we can read and modify an object if we're in the process of + // evaluating its initializer, because its lifetime began in this + // evaluation. + } else if (AK != AK_Read) { + // All the remaining cases only permit reading. + Info.Diag(E, diag::note_constexpr_modify_global); + return CompleteObject(); + } else if (VD->isConstexpr()) { // OK, we can read this variable. } else if (BaseType->isIntegralOrEnumerationType()) { if (!BaseType.isConstQualified()) { @@ -2060,12 +2491,45 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); if (!Frame) { - Info.Diag(E); - return CompleteObject(); - } + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(Base)) { + assert(MTE->getStorageDuration() == SD_Static && + "should have a frame for a non-global materialized temporary"); + + // Per C++1y [expr.const]p2: + // an lvalue-to-rvalue conversion [is not allowed unless it applies to] + // - a [...] glvalue of integral or enumeration type that refers to + // a non-volatile const object [...] + // [...] + // - a [...] glvalue of literal type that refers to a non-volatile + // object whose lifetime began within the evaluation of e. + // + // C++11 misses the 'began within the evaluation of e' check and + // instead allows all temporaries, including things like: + // int &&r = 1; + // int x = ++r; + // constexpr int k = r; + // Therefore we use the C++1y rules in C++11 too. + const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); + const ValueDecl *ED = MTE->getExtendingDecl(); + if (!(BaseType.isConstQualified() && + BaseType->isIntegralOrEnumerationType()) && + !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { + Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK; + Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); + return CompleteObject(); + } - BaseType = Base->getType(); - BaseVal = &Frame->Temporaries[Base]; + BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + assert(BaseVal && "got reference to unevaluated temporary"); + } else { + Info.Diag(E); + return CompleteObject(); + } + } else { + BaseVal = Frame->getTemporary(Base); + assert(BaseVal && "missing value for temporary"); + } // Volatile temporary objects cannot be accessed in constant expressions. if (BaseType.isVolatileQualified()) { @@ -2080,10 +2544,22 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, } } - // In C++1y, we can't safely access any mutable state when checking a - // potential constant expression. + // During the construction of an object, it is not yet 'const'. + // FIXME: We don't set up EvaluatingDecl for local variables or temporaries, + // and this doesn't do quite the right thing for const subobjects of the + // object under construction. + if (LVal.getLValueBase() == Info.EvaluatingDecl) { + BaseType = Info.Ctx.getCanonicalType(BaseType); + BaseType.removeLocalConst(); + } + + // In C++1y, we can't safely access any mutable state when we might be + // evaluating after an unmodeled side effect or an evaluation failure. + // + // FIXME: Not all local state is mutable. Allow local constant subobjects + // to be read here (but take care with 'mutable' fields). if (Frame && Info.getLangOpts().CPlusPlus1y && - Info.CheckingPotentialConstantExpression) + (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure())) return CompleteObject(); return CompleteObject(BaseVal, BaseType); @@ -2159,6 +2635,124 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { } namespace { +struct CompoundAssignSubobjectHandler { + EvalInfo &Info; + const Expr *E; + QualType PromotedLHSType; + BinaryOperatorKind Opcode; + const APValue &RHS; + + static const AccessKinds AccessKind = AK_Assign; + + typedef bool result_type; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + return false; + } + return true; + } + + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + switch (Subobj.getKind()) { + case APValue::Int: + return found(Subobj.getInt(), SubobjType); + case APValue::Float: + return found(Subobj.getFloat(), SubobjType); + case APValue::ComplexInt: + case APValue::ComplexFloat: + // FIXME: Implement complex compound assignment. + Info.Diag(E); + return false; + case APValue::LValue: + return foundPointer(Subobj, SubobjType); + default: + // FIXME: can this happen? + Info.Diag(E); + return false; + } + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + if (!SubobjType->isIntegerType() || !RHS.isInt()) { + // We don't support compound assignment on integer-cast-to-pointer + // values. + Info.Diag(E); + return false; + } + + APSInt LHS = HandleIntToIntCast(Info, E, PromotedLHSType, + SubobjType, Value); + if (!handleIntIntBinOp(Info, E, LHS, Opcode, RHS.getInt(), LHS)) + return false; + Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + return checkConst(SubobjType) && + HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType, + Value) && + handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) && + HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value); + } + bool foundPointer(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + QualType PointeeType; + if (const PointerType *PT = SubobjType->getAs<PointerType>()) + PointeeType = PT->getPointeeType(); + + if (PointeeType.isNull() || !RHS.isInt() || + (Opcode != BO_Add && Opcode != BO_Sub)) { + Info.Diag(E); + return false; + } + + int64_t Offset = getExtValue(RHS.getInt()); + if (Opcode == BO_Sub) + Offset = -Offset; + + LValue LVal; + LVal.setFrom(Info.Ctx, Subobj); + if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset)) + return false; + LVal.moveInto(Subobj); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements here"); + } +}; +} // end anonymous namespace + +const AccessKinds CompoundAssignSubobjectHandler::AccessKind; + +/// Perform a compound assignment of LVal <op>= RVal. +static bool handleCompoundAssignment( + EvalInfo &Info, const Expr *E, + const LValue &LVal, QualType LValType, QualType PromotedLValType, + BinaryOperatorKind Opcode, const APValue &RVal) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); + return false; + } + + CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType); + CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode, + RVal }; + return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); +} + +namespace { struct IncDecSubobjectHandler { EvalInfo &Info; const Expr *E; @@ -2326,54 +2920,53 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, /// lvalue referring to the result. /// /// \param Info - Information about the ongoing evaluation. -/// \param BO - The member pointer access operation. -/// \param LV - Filled in with a reference to the resulting object. +/// \param LV - An lvalue referring to the base of the member pointer. +/// \param RHS - The member pointer expression. /// \param IncludeMember - Specifies whether the member itself is included in /// the resulting LValue subobject designator. This is not possible when /// creating a bound member function. /// \return The field or method declaration to which the member pointer refers, /// or 0 if evaluation fails. static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, - const BinaryOperator *BO, + QualType LVType, LValue &LV, + const Expr *RHS, bool IncludeMember = true) { - assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI); - - bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV); - if (!EvalObjOK && !Info.keepEvaluatingAfterFailure()) - return 0; - MemberPtr MemPtr; - if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info)) + if (!EvaluateMemberPointer(RHS, MemPtr, Info)) return 0; // C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to // member value, the behavior is undefined. - if (!MemPtr.getDecl()) - return 0; - - if (!EvalObjOK) + if (!MemPtr.getDecl()) { + // FIXME: Specific diagnostic. + Info.Diag(RHS); return 0; + } if (MemPtr.isDerivedMember()) { // This is a member of some derived class. Truncate LV appropriately. // The end of the derived-to-base path for the base object must match the // derived-to-base path for the member pointer. if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() > - LV.Designator.Entries.size()) + LV.Designator.Entries.size()) { + Info.Diag(RHS); return 0; + } unsigned PathLengthToMember = LV.Designator.Entries.size() - MemPtr.Path.size(); for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) { const CXXRecordDecl *LVDecl = getAsBaseClass( LV.Designator.Entries[PathLengthToMember + I]); const CXXRecordDecl *MPDecl = MemPtr.Path[I]; - if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) + if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) { + Info.Diag(RHS); return 0; + } } // Truncate the lvalue to the appropriate derived class. - if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(), + if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(), PathLengthToMember)) return 0; } else if (!MemPtr.Path.empty()) { @@ -2382,7 +2975,6 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, MemPtr.Path.size() + IncludeMember); // Walk down to the appropriate base class. - QualType LVType = BO->getLHS()->getType(); if (const PointerType *PT = LVType->getAs<PointerType>()) LVType = PT->getPointeeType(); const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl(); @@ -2390,23 +2982,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // The first class in the path is that of the lvalue. for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) { const CXXRecordDecl *Base = MemPtr.Path[N - I - 1]; - if (!HandleLValueDirectBase(Info, BO, LV, RD, Base)) + if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base)) return 0; RD = Base; } // Finally cast to the class containing the member. - if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord())) + if (!HandleLValueDirectBase(Info, RHS, LV, RD, + MemPtr.getContainingRecord())) return 0; } // Add the member. Note that we cannot build bound member functions here. if (IncludeMember) { if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) { - if (!HandleLValueMember(Info, BO, LV, FD)) + if (!HandleLValueMember(Info, RHS, LV, FD)) return 0; } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) { - if (!HandleLValueIndirectMember(Info, BO, LV, IFD)) + if (!HandleLValueIndirectMember(Info, RHS, LV, IFD)) return 0; } else { llvm_unreachable("can't construct reference to bound member function"); @@ -2416,6 +3009,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, return MemPtr.getDecl(); } +static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, + const BinaryOperator *BO, + LValue &LV, + bool IncludeMember = true) { + assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI); + + if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) { + if (Info.keepEvaluatingAfterFailure()) { + MemberPtr MemPtr; + EvaluateMemberPointer(BO->getRHS(), MemPtr, Info); + } + return 0; + } + + return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV, + BO->getRHS(), IncludeMember); +} + /// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on /// the provided lvalue, which currently refers to the base object. static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E, @@ -2465,7 +3076,9 @@ enum EvalStmtResult { /// Hit a 'continue' statement. ESR_Continue, /// Hit a 'break' statement. - ESR_Break + ESR_Break, + /// Still scanning for 'case' or 'default' statement. + ESR_CaseNotFound }; } @@ -2477,7 +3090,14 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { LValue Result; Result.set(VD, Info.CurrentCall->Index); - APValue &Val = Info.CurrentCall->Temporaries[VD]; + APValue &Val = Info.CurrentCall->createTemporary(VD, true); + + if (!VD->getInit()) { + Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized) + << false << VD->getType(); + Val = APValue(); + return false; + } if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) { // Wipe out any partially-computed value, to allow tracking that this @@ -2493,18 +3113,21 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { /// Evaluate a condition (either a variable declaration or an expression). static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, const Expr *Cond, bool &Result) { + FullExpressionRAII Scope(Info); if (CondDecl && !EvaluateDecl(Info, CondDecl)) return false; return EvaluateAsBooleanCondition(Cond, Result, Info); } static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S); + const Stmt *S, const SwitchCase *SC = 0); /// Evaluate the body of a loop, and translate the result as appropriate. static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, - const Stmt *Body) { - switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + const Stmt *Body, + const SwitchCase *Case = 0) { + BlockScopeRAII Scope(Info); + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) { case ESR_Break: return ESR_Succeeded; case ESR_Succeeded: @@ -2512,21 +3135,149 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, return ESR_Continue; case ESR_Failed: case ESR_Returned: + case ESR_CaseNotFound: + return ESR; + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + +/// Evaluate a switch statement. +static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, + const SwitchStmt *SS) { + BlockScopeRAII Scope(Info); + + // Evaluate the switch condition. + APSInt Value; + { + FullExpressionRAII Scope(Info); + if (SS->getConditionVariable() && + !EvaluateDecl(Info, SS->getConditionVariable())) + return ESR_Failed; + if (!EvaluateInteger(SS->getCond(), Value, Info)) + return ESR_Failed; + } + + // Find the switch case corresponding to the value of the condition. + // FIXME: Cache this lookup. + const SwitchCase *Found = 0; + for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (isa<DefaultStmt>(SC)) { + Found = SC; + continue; + } + + const CaseStmt *CS = cast<CaseStmt>(SC); + APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); + APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) + : LHS; + if (LHS <= Value && Value <= RHS) { + Found = SC; + break; + } + } + + if (!Found) + return ESR_Succeeded; + + // Search the switch body for the switch case and evaluate it from there. + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + case ESR_Failed: + case ESR_Returned: return ESR; + case ESR_CaseNotFound: + // This can only happen if the switch case is nested within a statement + // expression. We have no intention of supporting that. + Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); + return ESR_Failed; } llvm_unreachable("Invalid EvalStmtResult!"); } // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S) { - // FIXME: Mark all temporaries in the current frame as destroyed at - // the end of each full-expression. + const Stmt *S, const SwitchCase *Case) { + if (!Info.nextStep(S)) + return ESR_Failed; + + // If we're hunting down a 'case' or 'default' label, recurse through + // substatements until we hit the label. + if (Case) { + // FIXME: We don't start the lifetime of objects whose initialization we + // jump over. However, such objects must be of class type with a trivial + // default constructor that initialize all subobjects, so must be empty, + // so this almost never matters. + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + // FIXME: Precompute which substatement of a compound statement we + // would jump to, and go straight there rather than performing a + // linear scan each time. + case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: + case Stmt::DoStmtClass: + break; + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + if (Case == S) + Case = 0; + break; + + case Stmt::IfStmtClass: { + // FIXME: Precompute which side of an 'if' we would jump to, and go + // straight there rather than scanning both sides. + const IfStmt *IS = cast<IfStmt>(S); + + // Wrap the evaluation in a block scope, in case it's a DeclStmt + // preceded by our switch label. + BlockScopeRAII Scope(Info); + + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case); + if (ESR != ESR_CaseNotFound || !IS->getElse()) + return ESR; + return EvaluateStmt(Result, Info, IS->getElse(), Case); + } + + case Stmt::WhileStmtClass: { + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + break; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, FS->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + if (FS->getInc()) { + FullExpressionRAII IncScope(Info); + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + break; + } + + case Stmt::DeclStmtClass: + // FIXME: If the variable has initialization that can't be jumped over, + // bail out of any immediately-surrounding compound-statement too. + default: + return ESR_CaseNotFound; + } + } + switch (S->getStmtClass()) { default: if (const Expr *E = dyn_cast<Expr>(S)) { // Don't bother evaluating beyond an expression-statement which couldn't // be evaluated. + FullExpressionRAII Scope(Info); if (!EvaluateIgnoredValue(Info, E)) return ESR_Failed; return ESR_Succeeded; @@ -2541,34 +3292,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::DeclStmtClass: { const DeclStmt *DS = cast<DeclStmt>(S); for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(), - DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) { + // Each declaration initialization is its own full-expression. + // FIXME: This isn't quite right; if we're performing aggregate + // initialization, each braced subexpression is its own full-expression. + FullExpressionRAII Scope(Info); if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure()) return ESR_Failed; + } return ESR_Succeeded; } case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); + FullExpressionRAII Scope(Info); if (RetExpr && !Evaluate(Result, Info, RetExpr)) return ESR_Failed; return ESR_Returned; } case Stmt::CompoundStmtClass: { + BlockScopeRAII Scope(Info); + const CompoundStmt *CS = cast<CompoundStmt>(S); for (CompoundStmt::const_body_iterator BI = CS->body_begin(), BE = CS->body_end(); BI != BE; ++BI) { - EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); - if (ESR != ESR_Succeeded) + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case); + if (ESR == ESR_Succeeded) + Case = 0; + else if (ESR != ESR_CaseNotFound) return ESR; } - return ESR_Succeeded; + return Case ? ESR_CaseNotFound : ESR_Succeeded; } case Stmt::IfStmtClass: { const IfStmt *IS = cast<IfStmt>(S); // Evaluate the condition, as either a var decl or as an expression. + BlockScopeRAII Scope(Info); bool Cond; if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) return ESR_Failed; @@ -2584,6 +3346,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::WhileStmtClass: { const WhileStmt *WS = cast<WhileStmt>(S); while (true) { + BlockScopeRAII Scope(Info); bool Continue; if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(), Continue)) @@ -2602,10 +3365,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const DoStmt *DS = cast<DoStmt>(S); bool Continue; do { - EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case); if (ESR != ESR_Continue) return ESR; + Case = 0; + FullExpressionRAII CondScope(Info); if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) return ESR_Failed; } while (Continue); @@ -2614,12 +3379,14 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::ForStmtClass: { const ForStmt *FS = cast<ForStmt>(S); + BlockScopeRAII Scope(Info); if (FS->getInit()) { EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit()); if (ESR != ESR_Succeeded) return ESR; } while (true) { + BlockScopeRAII Scope(Info); bool Continue = true; if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(), FS->getCond(), Continue)) @@ -2631,14 +3398,18 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, if (ESR != ESR_Continue) return ESR; - if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) - return ESR_Failed; + if (FS->getInc()) { + FullExpressionRAII IncScope(Info); + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } } return ESR_Succeeded; } case Stmt::CXXForRangeStmtClass: { const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S); + BlockScopeRAII Scope(Info); // Initialize the __range variable. EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt()); @@ -2652,13 +3423,17 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, while (true) { // Condition: __begin != __end. - bool Continue = true; - if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) - return ESR_Failed; - if (!Continue) - break; + { + bool Continue = true; + FullExpressionRAII CondExpr(Info); + if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) + return ESR_Failed; + if (!Continue) + break; + } // User's variable declaration, initialized by *__begin. + BlockScopeRAII InnerScope(Info); ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt()); if (ESR != ESR_Succeeded) return ESR; @@ -2676,11 +3451,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, return ESR_Succeeded; } + case Stmt::SwitchStmtClass: + return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S)); + case Stmt::ContinueStmtClass: return ESR_Continue; case Stmt::BreakStmtClass: return ESR_Break; + + case Stmt::LabelStmtClass: + return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case); + + case Stmt::AttributedStmtClass: + // As a general principle, C++11 attributes can be ignored without + // any semantic impact. + return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(), + Case); + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case); } } @@ -2718,10 +3509,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Definition) { // Potential constant expressions can contain calls to declared, but not yet // defined, constexpr functions. - if (Info.CheckingPotentialConstantExpression && !Definition && + if (Info.checkingPotentialConstantExpression() && !Definition && Declaration->isConstexpr()) return false; + // Bail out with no diagnostic if the function declaration itself is invalid. + // We will have produced a relevant diagnostic while parsing it. + if (Declaration->isInvalidDecl()) + return false; + // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) return true; @@ -2774,6 +3570,27 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return false; CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data()); + + // For a trivial copy or move assignment, perform an APValue copy. This is + // essential for unions, where the operations performed by the assignment + // operator cannot be represented as statements. + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee); + if (MD && MD->isDefaulted() && MD->isTrivial()) { + assert(This && + (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())); + LValue RHS; + RHS.setFrom(Info.Ctx, ArgValues[0]); + APValue RHSValue; + if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), + RHS, RHSValue)) + return false; + if (!handleAssignment(Info, Args[0], *This, MD->getThisType(Info.Ctx), + RHSValue)) + return false; + This->moveInto(Result); + return true; + } + EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); if (ESR == ESR_Succeeded) { if (Callee->getResultType()->isVoidType()) @@ -2806,8 +3623,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); - if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) - return false; + { + FullExpressionRAII InitScope(Info); + if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) + return false; + } return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } @@ -2831,6 +3651,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); + // A scope for temporaries lifetime-extended by reference members. + BlockScopeRAII LifetimeExtendedScope(Info); + bool Success = true; unsigned BasesSeen = 0; #ifndef NDEBUG @@ -2842,6 +3665,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, APValue *Value = &Result; // Determine the subobject to initialize. + FieldDecl *FD = 0; if ((*I)->isBaseInitializer()) { QualType BaseType((*I)->getBaseClass(), 0); #ifndef NDEBUG @@ -2856,7 +3680,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, BaseType->getAsCXXRecordDecl(), &Layout)) return false; Value = &Result.getStructBase(BasesSeen++); - } else if (FieldDecl *FD = (*I)->getMember()) { + } else if ((FD = (*I)->getMember())) { if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout)) return false; if (RD->isUnion()) { @@ -2871,7 +3695,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(), CE = IFD->chain_end(); C != CE; ++C) { - FieldDecl *FD = cast<FieldDecl>(*C); + FD = cast<FieldDecl>(*C); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had // preceding zero-initialization, and we're now initializing a union @@ -2897,9 +3721,10 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, llvm_unreachable("unknown base initializer kind"); } - if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(), - (*I)->isBaseInitializer() - ? CCEK_Constant : CCEK_MemberInit)) { + FullExpressionRAII InitScope(Info); + if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) || + (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(), + *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.keepEvaluatingAfterFailure()) @@ -2934,7 +3759,7 @@ private: // expression, then the conditional operator is not either. template<typename ConditionalOperator> void CheckPotentialConstantConditional(const ConditionalOperator *E) { - assert(Info.CheckingPotentialConstantExpression); + assert(Info.checkingPotentialConstantExpression()); // Speculatively evaluate both arms. { @@ -2959,7 +3784,7 @@ private: bool HandleConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) { - if (Info.CheckingPotentialConstantExpression) + if (Info.checkingPotentialConstantExpression()) CheckPotentialConstantConditional(E); return false; } @@ -3008,15 +3833,19 @@ public: RetTy VisitUnaryPlus(const UnaryOperator *E) { return StmtVisitorTy::Visit(E->getSubExpr()); } RetTy VisitChooseExpr(const ChooseExpr *E) - { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); } + { return StmtVisitorTy::Visit(E->getChosenSubExpr()); } RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E) { return StmtVisitorTy::Visit(E->getResultExpr()); } RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } - RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) - { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + // The initializer may not have been parsed yet, or might be erroneous. + if (!E->getExpr()) + return Error(E); + return StmtVisitorTy::Visit(E->getExpr()); + } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -3056,7 +3885,7 @@ public: RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { // Evaluate and cache the common expression. We treat it as a temporary, // even though it's not quite the same thing. - if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()], + if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false), Info, E->getCommon())) return false; @@ -3076,33 +3905,30 @@ public: // Always assume __builtin_constant_p(...) ? ... : ... is a potential // constant expression; we can't check whether it's potentially foldable. - if (Info.CheckingPotentialConstantExpression && IsBcpCall) + if (Info.checkingPotentialConstantExpression() && IsBcpCall) return false; - FoldConstant Fold(Info); - - if (!HandleConditionalOperator(E)) + FoldConstant Fold(Info, IsBcpCall); + if (!HandleConditionalOperator(E)) { + Fold.keepDiagnostics(); return false; - - if (IsBcpCall) - Fold.Fold(Info); + } return true; } RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - APValue &Value = Info.CurrentCall->Temporaries[E]; - if (Value.isUninit()) { - const Expr *Source = E->getSourceExpr(); - if (!Source) - return Error(E); - if (Source == E) { // sanity checking. - assert(0 && "OpaqueValueExpr recursively refers to itself"); - return Error(E); - } - return StmtVisitorTy::Visit(Source); + if (APValue *Value = Info.CurrentCall->getTemporary(E)) + return DerivedSuccess(*Value, E); + + const Expr *Source = E->getSourceExpr(); + if (!Source) + return Error(E); + if (Source == E) { // sanity checking. + assert(0 && "OpaqueValueExpr recursively refers to itself"); + return Error(E); } - return DerivedSuccess(Value, E); + return StmtVisitorTy::Visit(Source); } RetTy VisitCallExpr(const CallExpr *E) { @@ -3240,8 +4066,13 @@ public: default: break; - case CK_AtomicToNonAtomic: - case CK_NonAtomicToAtomic: + case CK_AtomicToNonAtomic: { + APValue AtomicVal; + if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info)) + return false; + return DerivedSuccess(AtomicVal, E); + } + case CK_NoOp: case CK_UserDefinedConversion: return StmtVisitorTy::Visit(E->getSubExpr()); @@ -3282,6 +4113,41 @@ public: return DerivedSuccess(RVal, UO); } + RetTy VisitStmtExpr(const StmtExpr *E) { + // We will have checked the full-expressions inside the statement expression + // when they were completed, and don't need to check them again now. + if (Info.checkingForOverflow()) + return Error(E); + + BlockScopeRAII Scope(Info); + const CompoundStmt *CS = E->getSubStmt(); + for (CompoundStmt::const_body_iterator BI = CS->body_begin(), + BE = CS->body_end(); + /**/; ++BI) { + if (BI + 1 == BE) { + const Expr *FinalExpr = dyn_cast<Expr>(*BI); + if (!FinalExpr) { + Info.Diag((*BI)->getLocStart(), + diag::note_constexpr_stmt_expr_unsupported); + return false; + } + return this->Visit(FinalExpr); + } + + APValue ReturnValue; + EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI); + if (ESR != ESR_Succeeded) { + // FIXME: If the statement-expression terminated due to 'return', + // 'break', or 'continue', it would be nice to propagate that to + // the outer statement evaluation rather than bailing out. + if (ESR != ESR_Failed) + Info.Diag((*BI)->getLocStart(), + diag::note_constexpr_stmt_expr_unsupported); + return false; + } + } + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); @@ -3374,24 +4240,14 @@ public: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: { + case CK_UncheckedDerivedToBase: if (!this->Visit(E->getSubExpr())) return false; // Now figure out the necessary offset to add to the base LV to get from // the derived class to the base class. - QualType Type = E->getSubExpr()->getType(); - - for (CastExpr::path_const_iterator PathI = E->path_begin(), - PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(), - *PathI)) - return false; - Type = (*PathI)->getType(); - } - - return true; - } + return HandleLValueBasePath(this->Info, E, E->getSubExpr()->getType(), + Result); } } }; @@ -3420,8 +4276,12 @@ public: // * BlockExpr // * CallExpr for a MakeStringConstant builtin // - Locals and temporaries +// * MaterializeTemporaryExpr // * Any Expr, with a CallIndex indicating the function in which the temporary -// was evaluated. +// was evaluated, for cases where the MaterializeTemporaryExpr is missing +// from the AST (FIXME). +// * A MaterializeTemporaryExpr that has static storage duration, with no +// CallIndex, for a lifetime-extended temporary. // plus an offset in bytes. //===----------------------------------------------------------------------===// namespace { @@ -3511,17 +4371,78 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { APValue *V; if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) return false; + if (V->isUninit()) { + if (!Info.checkingPotentialConstantExpression()) + Info.Diag(E, diag::note_constexpr_use_uninit_reference); + return false; + } return Success(*V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - if (E->getType()->isRecordType()) - return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); + // Walk through the expression to find the materialized temporary itself. + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Inner = E->GetTemporaryExpr()-> + skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + + // If we passed any comma operators, evaluate their LHSs. + for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I) + if (!EvaluateIgnoredValue(Info, CommaLHSs[I])) + return false; + + // A materialized temporary with static storage duration can appear within the + // result of a constant expression evaluation, so we need to preserve its + // value for use outside this evaluation. + APValue *Value; + if (E->getStorageDuration() == SD_Static) { + Value = Info.Ctx.getMaterializedTemporaryValue(E, true); + *Value = APValue(); + Result.set(E); + } else { + Value = &Info.CurrentCall-> + createTemporary(E, E->getStorageDuration() == SD_Automatic); + Result.set(E, Info.CurrentCall->Index); + } - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, - Result, E->GetTemporaryExpr()); + QualType Type = Inner->getType(); + + // Materialize the temporary itself. + if (!EvaluateInPlace(*Value, Info, Result, Inner) || + (E->getStorageDuration() == SD_Static && + !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) { + *Value = APValue(); + return false; + } + + // Adjust our lvalue to refer to the desired subobject. + for (unsigned I = Adjustments.size(); I != 0; /**/) { + --I; + switch (Adjustments[I].Kind) { + case SubobjectAdjustment::DerivedToBaseAdjustment: + if (!HandleLValueBasePath(Info, Adjustments[I].DerivedToBase.BasePath, + Type, Result)) + return false; + Type = Adjustments[I].DerivedToBase.BasePath->getType(); + break; + + case SubobjectAdjustment::FieldAdjustment: + if (!HandleLValueMember(Info, E, Result, Adjustments[I].Field)) + return false; + Type = Adjustments[I].Field->getType(); + break; + + case SubobjectAdjustment::MemberPointerAdjustment: + if (!HandleMemberPointerAccess(this->Info, Type, Result, + Adjustments[I].Ptr.RHS)) + return false; + Type = Adjustments[I].Ptr.MPT->getPointeeType(); + break; + } + } + + return true; } bool @@ -3576,11 +4497,9 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return false; - int64_t IndexValue - = Index.isSigned() ? Index.getSExtValue() - : static_cast<int64_t>(Index.getZExtValue()); - return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue); + return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), + getExtValue(Index)); } bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { @@ -3634,14 +4553,10 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator( if (!Evaluate(RHS, this->Info, CAO->getRHS())) return false; - // FIXME: - //return handleCompoundAssignment( - // this->Info, CAO, - // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), - // RHS, CAO->getRHS()->getType(), - // CAO->getOpForCompoundAssignment(CAO->getOpcode()), - // CAO->getComputationResultType()); - return Error(CAO); + return handleCompoundAssignment( + this->Info, CAO, + Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), + CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS); } bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { @@ -3705,6 +4620,9 @@ public: return Error(E); } bool VisitCXXThisExpr(const CXXThisExpr *E) { + // Can't look at 'this' when checking a potential constant expression. + if (Info.checkingPotentialConstantExpression()) + return false; if (!Info.CurrentCall->This) return Error(E); Result = *Info.CurrentCall->This; @@ -3737,9 +4655,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { llvm::APSInt Offset; if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK) return false; - int64_t AdditionalOffset - = Offset.isSigned() ? Offset.getSExtValue() - : static_cast<int64_t>(Offset.getZExtValue()); + + int64_t AdditionalOffset = getExtValue(Offset); if (E->getOpcode() == BO_Sub) AdditionalOffset = -AdditionalOffset; @@ -3779,7 +4696,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return true; case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: { + case CK_UncheckedDerivedToBase: if (!EvaluatePointer(E->getSubExpr(), Result, Info)) return false; if (!Result.Base && Result.Offset.isZero()) @@ -3787,19 +4704,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { // Now figure out the necessary offset to add to the base LV to get from // the derived class to the base class. - QualType Type = - E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(); - - for (CastExpr::path_const_iterator PathI = E->path_begin(), - PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), - *PathI)) - return false; - Type = (*PathI)->getType(); - } - - return true; - } + return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()-> + castAs<PointerType>()->getPointeeType(), + Result); case CK_BaseToDerived: if (!Visit(E->getSubExpr())) @@ -3839,7 +4746,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return false; } else { Result.set(SubExpr, Info.CurrentCall->Index); - if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr], + if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), Info, Result, SubExpr)) return false; } @@ -3862,7 +4769,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (IsStringLiteralCall(E)) return Success(E); - return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->isBuiltinCall()) { + case Builtin::BI__builtin_addressof: + return EvaluateLValue(E->getArg(0), Result, Info); + + default: + return ExprEvaluatorBaseTy::VisitCallExpr(E); + } } //===----------------------------------------------------------------------===// @@ -3976,6 +4889,7 @@ namespace { bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); }; } @@ -4091,10 +5005,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { } bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - // Cannot constant-evaluate std::initializer_list inits. - if (E->initializesStdInitializerList()) - return false; - const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -4156,8 +5066,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, isa<CXXDefaultInitExpr>(Init)); - if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, - Subobject, Init)) { + APValue &FieldVal = Result.getStructField(Field->getFieldIndex()); + if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) || + (Field->isBitField() && !truncateBitfieldValue(Info, Init, + FieldVal, *Field))) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -4210,6 +5122,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { Result); } +bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *E) { + const ConstantArrayType *ArrayType = + Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); + + LValue Array; + if (!EvaluateLValue(E->getSubExpr(), Array, Info)) + return false; + + // Get a pointer to the first element of the array. + Array.addArray(Info, E, ArrayType); + + // FIXME: Perform the checks on the field types in SemaInit. + RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl(); + RecordDecl::field_iterator Field = Record->field_begin(); + if (Field == Record->field_end()) + return Error(E); + + // Start pointer. + if (!Field->getType()->isPointerType() || + !Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) + return Error(E); + + // FIXME: What if the initializer_list type has base classes, etc? + Result = APValue(APValue::UninitStruct(), 0, 2); + Array.moveInto(Result.getStructField(0)); + + if (++Field == Record->field_end()) + return Error(E); + + if (Field->getType()->isPointerType() && + Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) { + // End pointer. + if (!HandleLValueArrayAdjustment(Info, E, Array, + ArrayType->getElementType(), + ArrayType->getSize().getZExtValue())) + return false; + Array.moveInto(Result.getStructField(1)); + } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType())) + // Length. + Result.getStructField(1) = APValue(APSInt(ArrayType->getSize())); + else + return Error(E); + + if (++Field != Record->field_end()) + return Error(E); + + return true; +} + static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result, EvalInfo &Info) { assert(E->isRValue() && E->getType()->isRecordType() && @@ -4234,7 +5198,8 @@ public: /// Visit an expression which constructs the value of this temporary. bool VisitConstructExpr(const Expr *E) { Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E); + return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false), + Info, Result, E); } bool VisitCastExpr(const CastExpr *E) { @@ -4393,7 +5358,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { while (CountElts < NumElements) { // Handle nested vector initialization. if (CountInits < NumInits - && E->getInit(CountInits)->getType()->isExtVectorType()) { + && E->getInit(CountInits)->getType()->isVectorType()) { APValue v; if (!EvaluateVector(E->getInit(CountInits), v, Info)) return Error(E); @@ -4951,7 +5916,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { } else if (ArgType->isPointerType() || Arg->isGLValue()) { LValue LV; Expr::EvalStatus Status; - EvalInfo Info(Ctx, Status); + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info) : EvaluatePointer(Arg, LV, Info)) && !Status.HasSideEffects) @@ -5045,9 +6010,37 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); + // FIXME: BI__builtin_clrsb + // FIXME: BI__builtin_clrsbl + // FIXME: BI__builtin_clrsbll + + case Builtin::BI__builtin_clz: + case Builtin::BI__builtin_clzl: + case Builtin::BI__builtin_clzll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + if (!Val) + return Error(E); + + return Success(Val.countLeadingZeros(), E); + } + case Builtin::BI__builtin_constant_p: return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E); + case Builtin::BI__builtin_ctz: + case Builtin::BI__builtin_ctzl: + case Builtin::BI__builtin_ctzll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + if (!Val) + return Error(E); + + return Success(Val.countTrailingZeros(), E); + } + case Builtin::BI__builtin_eh_return_data_regno: { int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand); @@ -5057,6 +6050,81 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_expect: return Visit(E->getArg(0)); + case Builtin::BI__builtin_ffs: + case Builtin::BI__builtin_ffsl: + case Builtin::BI__builtin_ffsll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + unsigned N = Val.countTrailingZeros(); + return Success(N == Val.getBitWidth() ? 0 : N + 1, E); + } + + case Builtin::BI__builtin_fpclassify: { + APFloat Val(0.0); + if (!EvaluateFloat(E->getArg(5), Val, Info)) + return false; + unsigned Arg; + switch (Val.getCategory()) { + case APFloat::fcNaN: Arg = 0; break; + case APFloat::fcInfinity: Arg = 1; break; + case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break; + case APFloat::fcZero: Arg = 4; break; + } + return Visit(E->getArg(Arg)); + } + + case Builtin::BI__builtin_isinf_sign: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isInfinity() ? (Val.isNegative() ? -1 : 1) : 0, E); + } + + case Builtin::BI__builtin_isinf: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isInfinity() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isfinite: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isFinite() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isnan: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isNaN() ? 1 : 0, E); + } + |