diff options
author | dim <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
commit | cc73504950eb7b5dff2dded9bedd67bc36d64641 (patch) | |
tree | 5b9c2fa9d79942fbdce3d618e37e27c18263af9a /lib | |
parent | 554bcb69c2d785a011a30e7db87a36a87fe7db10 (diff) | |
download | FreeBSD-src-cc73504950eb7b5dff2dded9bedd67bc36d64641.zip FreeBSD-src-cc73504950eb7b5dff2dded9bedd67bc36d64641.tar.gz |
Vendor import of clang trunk r162107:
http://llvm.org/svn/llvm-project/cfe/trunk@162107
Diffstat (limited to 'lib')
61 files changed, 1869 insertions, 865 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index a74ef14..2d7c9bd 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -367,8 +367,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; else - Base.get<const Expr*>()->printPretty(Out, Ctx, 0, - Ctx.getPrintingPolicy()); + Base.get<const Expr*>()->printPretty(Out, 0, Ctx.getPrintingPolicy()); if (!O.isZero()) { Out << " + " << (O / S); if (IsReference) @@ -389,7 +388,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ ElemTy = VD->getType(); } else { const Expr *E = Base.get<const Expr*>(); - E->printPretty(Out, Ctx, 0,Ctx.getPrintingPolicy()); + E->printPretty(Out, 0, Ctx.getPrintingPolicy()); ElemTy = E->getType(); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ad48dff..c021323 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -66,6 +66,12 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (D->isImplicit()) return NULL; + // User can not attach documentation to implicit instantiations. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + // TODO: handle comments for function parameters properly. if (isa<ParmVarDecl>(D)) return NULL; @@ -145,7 +151,6 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) == SourceMgr.getLineNumber(CommentBeginDecomp.first, CommentBeginDecomp.second)) { - (*Comment)->setDecl(D); return *Comment; } } @@ -185,13 +190,13 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Text.find_first_of(",;{}#@") != StringRef::npos) return NULL; - (*Comment)->setDecl(D); return *Comment; } -const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { - // If we have a 'templated' declaration for a template, adjust 'D' to - // refer to the actual template. +namespace { +/// If we have a 'templated' declaration for a template, adjust 'D' to +/// refer to the actual template. +const Decl *adjustDeclToTemplate(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) D = FTD; @@ -200,6 +205,14 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { D = CTD; } // FIXME: Alias templates? + return D; +} +} // unnamed namespace + +const RawComment *ASTContext::getRawCommentForAnyRedecl( + const Decl *D, + const Decl **OriginalDecl) const { + D = adjustDeclToTemplate(D); // Check whether we have cached a comment for this declaration already. { @@ -207,13 +220,17 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { RedeclComments.find(D); if (Pos != RedeclComments.end()) { const RawCommentAndCacheFlags &Raw = Pos->second; - if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) + if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { + if (OriginalDecl) + *OriginalDecl = Raw.getOriginalDecl(); return Raw.getRaw(); + } } } // Search for comments attached to declarations in the redeclaration chain. const RawComment *RC = NULL; + const Decl *OriginalDeclForRC = NULL; for (Decl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I) { @@ -223,16 +240,19 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { const RawCommentAndCacheFlags &Raw = Pos->second; if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { RC = Raw.getRaw(); + OriginalDeclForRC = Raw.getOriginalDecl(); break; } } else { RC = getRawCommentForDeclNoCache(*I); + OriginalDeclForRC = *I; RawCommentAndCacheFlags Raw; if (RC) { Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromDecl); } else Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl); + Raw.setOriginalDecl(*I); RedeclComments[*I] = Raw; if (RC) break; @@ -242,10 +262,14 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { // If we found a comment, it should be a documentation comment. assert(!RC || RC->isDocumentation()); + if (OriginalDecl) + *OriginalDecl = OriginalDeclForRC; + // Update cache for every declaration in the redeclaration chain. RawCommentAndCacheFlags Raw; Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromRedecl); + Raw.setOriginalDecl(OriginalDeclForRC); for (Decl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); @@ -259,11 +283,24 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(const Decl *D) const { } comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const { - const RawComment *RC = getRawCommentForAnyRedecl(D); + D = adjustDeclToTemplate(D); + const Decl *Canonical = D->getCanonicalDecl(); + llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos = + ParsedComments.find(Canonical); + if (Pos != ParsedComments.end()) + return Pos->second; + + const Decl *OriginalDecl; + const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); if (!RC) return NULL; - return RC->getParsed(*this); + if (D != OriginalDecl) + return getCommentForDecl(OriginalDecl); + + comments::FullComment *FC = RC->parse(*this, D); + ParsedComments[Canonical] = FC; + return FC; } void @@ -5437,7 +5474,8 @@ ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, QualifiedTemplateName *QTN = QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (!QTN) { - QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); + QTN = new (*this, llvm::alignOf<QualifiedTemplateName>()) + QualifiedTemplateName(NNS, TemplateKeyword, Template); QualifiedTemplateNames.InsertNode(QTN, InsertPos); } @@ -5464,10 +5502,12 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); if (CanonNNS == NNS) { - QTN = new (*this,4) DependentTemplateName(NNS, Name); + QTN = new (*this, llvm::alignOf<DependentTemplateName>()) + DependentTemplateName(NNS, Name); } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Name); - QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon); + QTN = new (*this, llvm::alignOf<DependentTemplateName>()) + DependentTemplateName(NNS, Name, Canon); DependentTemplateName *CheckQTN = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); assert(!CheckQTN && "Dependent type name canonicalization broken"); @@ -5498,10 +5538,12 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); if (CanonNNS == NNS) { - QTN = new (*this,4) DependentTemplateName(NNS, Operator); + QTN = new (*this, llvm::alignOf<DependentTemplateName>()) + DependentTemplateName(NNS, Operator); } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); - QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + QTN = new (*this, llvm::alignOf<DependentTemplateName>()) + DependentTemplateName(NNS, Operator, Canon); DependentTemplateName *CheckQTN = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 35fcd41..a605f1a 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -1149,7 +1149,7 @@ class TemplateDiff { if (!E) OS << "(no argument)"; else - E->printPretty(OS, Context, 0, Policy); return; + E->printPretty(OS, 0, Policy); return; } /// PrintTemplateTemplate - Handles printing of template template arguments, diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index d8ce1f3..dc7a0bd 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -15,9 +15,9 @@ namespace comments { // TODO: tablegen -bool CommandTraits::isVerbatimBlockCommand(StringRef BeginName, +bool CommandTraits::isVerbatimBlockCommand(StringRef StartName, StringRef &EndName) const { - const char *Result = llvm::StringSwitch<const char *>(BeginName) + const char *Result = llvm::StringSwitch<const char *>(StartName) .Case("code", "endcode") .Case("verbatim", "endverbatim") .Case("htmlonly", "endhtmlonly") @@ -44,7 +44,7 @@ bool CommandTraits::isVerbatimBlockCommand(StringRef BeginName, I = VerbatimBlockCommands.begin(), E = VerbatimBlockCommands.end(); I != E; ++I) - if (I->BeginName == BeginName) { + if (I->StartName == StartName) { EndName = I->EndName; return true; } @@ -115,10 +115,10 @@ bool CommandTraits::isDeclarationCommand(StringRef Name) const { .Default(false); } -void CommandTraits::addVerbatimBlockCommand(StringRef BeginName, +void CommandTraits::addVerbatimBlockCommand(StringRef StartName, StringRef EndName) { VerbatimBlockCommand VBC; - VBC.BeginName = BeginName; + VBC.StartName = StartName; VBC.EndName = EndName; VerbatimBlockCommands.push_back(VBC); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index eec2e9d..2f21e4c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1294,15 +1294,20 @@ static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, } CXXMethodDecl * -CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD) { +CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase) { if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl()) return this; // Lookup doesn't work for destructors, so handle them separately. if (isa<CXXDestructorDecl>(this)) { CXXMethodDecl *MD = RD->getDestructor(); - if (MD && recursivelyOverrides(MD, this)) - return MD; + if (MD) { + if (recursivelyOverrides(MD, this)) + return MD; + if (MayBeBase && recursivelyOverrides(this, MD)) + return MD; + } return NULL; } @@ -1313,6 +1318,8 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD) { continue; if (recursivelyOverrides(MD, this)) return MD; + if (MayBeBase && recursivelyOverrides(this, MD)) + return MD; } for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index aad0ca1..7f47604 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -26,7 +26,6 @@ using namespace clang; namespace { class DeclPrinter : public DeclVisitor<DeclPrinter> { raw_ostream &Out; - ASTContext &Context; PrintingPolicy Policy; unsigned Indentation; bool PrintInstantiation; @@ -38,11 +37,9 @@ namespace { void Print(AccessSpecifier AS); public: - DeclPrinter(raw_ostream &Out, ASTContext &Context, - const PrintingPolicy &Policy, - unsigned Indentation = 0, - bool PrintInstantiation = false) - : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation), + DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation = 0, bool PrintInstantiation = false) + : Out(Out), Policy(Policy), Indentation(Indentation), PrintInstantiation(PrintInstantiation) { } void VisitDeclContext(DeclContext *DC, bool Indent = true); @@ -96,7 +93,7 @@ void Decl::print(raw_ostream &Out, unsigned Indentation, void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation, bool PrintInstantiation) const { - DeclPrinter Printer(Out, getASTContext(), Policy, Indentation, PrintInstantiation); + DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation); Printer.Visit(const_cast<Decl*>(this)); } @@ -171,13 +168,17 @@ void DeclContext::dumpDeclContext() const { DC = DC->getParent(); ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); - DeclPrinter Printer(llvm::errs(), Ctx, Ctx.getPrintingPolicy(), 0); + DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), 0); Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); } +void Decl::dump() const { + dump(llvm::errs()); +} + void Decl::dump(raw_ostream &Out) const { PrintingPolicy Policy = getASTContext().getPrintingPolicy(); - Policy.Dump = true; + Policy.DumpSourceManager = &getASTContext().getSourceManager(); print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true); } @@ -191,8 +192,8 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) { if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) { - Attr *A = *i; - A->printPretty(Out, Context); + Attr *A = *i; + A->printPretty(Out, Policy); } } } @@ -231,7 +232,7 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (isa<ObjCIvarDecl>(*D)) continue; - if (!Policy.Dump) { + if (!Policy.DumpSourceManager) { // Skip over implicit declarations in pretty-printing mode. if (D->isImplicit()) continue; // FIXME: Ugly hack so we don't pretty-print the builtin declaration @@ -381,7 +382,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { Out << *D; if (Expr *Init = D->getInitExpr()) { Out << " = "; - Init->printPretty(Out, Context, 0, Policy, Indentation); + Init->printPretty(Out, 0, Policy, Indentation); } } @@ -420,7 +421,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += "("; if (FT) { llvm::raw_string_ostream POut(Proto); - DeclPrinter ParamPrinter(POut, Context, SubPolicy, Indentation); + DeclPrinter ParamPrinter(POut, SubPolicy, Indentation); for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { if (i) POut << ", "; ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); @@ -466,7 +467,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (FT->getExceptionSpecType() == EST_ComputedNoexcept) { Proto += "("; llvm::raw_string_ostream EOut(Proto); - FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy, + FT->getNoexceptExpr()->printPretty(EOut, 0, SubPolicy, Indentation); EOut.flush(); Proto += EOut.str(); @@ -522,7 +523,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { SimpleInit = Init; if (SimpleInit) - SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + SimpleInit->printPretty(Out, 0, Policy, Indentation); else { for (unsigned I = 0; I != NumArgs; ++I) { if (isa<CXXDefaultArgExpr>(Args[I])) @@ -530,7 +531,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (I) Out << ", "; - Args[I]->printPretty(Out, Context, 0, Policy, Indentation); + Args[I]->printPretty(Out, 0, Policy, Indentation); } } } @@ -554,7 +555,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { // This is a K&R function definition, so we need to print the // parameters. Out << '\n'; - DeclPrinter ParamPrinter(Out, Context, SubPolicy, Indentation); + DeclPrinter ParamPrinter(Out, SubPolicy, Indentation); Indentation += Policy.Indentation; for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { Indent(); @@ -565,7 +566,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } else Out << ' '; - D->getBody()->printPretty(Out, Context, 0, SubPolicy, Indentation); + D->getBody()->printPretty(Out, 0, SubPolicy, Indentation); Out << '\n'; } } @@ -580,7 +581,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (D->isBitField()) { Out << " : "; - D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation); + D->getBitWidth()->printPretty(Out, 0, Policy, Indentation); } Expr *Init = D->getInClassInitializer(); @@ -589,7 +590,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { Out << " "; else Out << " = "; - Init->printPretty(Out, Context, 0, Policy, Indentation); + Init->printPretty(Out, 0, Policy, Indentation); } prettyPrintAttributes(D); } @@ -625,7 +626,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { else if (D->getInitStyle() == VarDecl::CInit) { Out << " = "; } - Init->printPretty(Out, Context, 0, Policy, Indentation); + Init->printPretty(Out, 0, Policy, Indentation); if (D->getInitStyle() == VarDecl::CallInit) Out << ")"; } @@ -639,7 +640,7 @@ void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Out << "__asm ("; - D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); + D->getAsmString()->printPretty(Out, 0, Policy, Indentation); Out << ")"; } @@ -650,9 +651,9 @@ void DeclPrinter::VisitImportDecl(ImportDecl *D) { void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { Out << "static_assert("; - D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation); + D->getAssertExpr()->printPretty(Out, 0, Policy, Indentation); Out << ", "; - D->getMessage()->printPretty(Out, Context, 0, Policy, Indentation); + D->getMessage()->printPretty(Out, 0, Policy, Indentation); Out << ")"; } @@ -786,8 +787,7 @@ void DeclPrinter::PrintTemplateParameters( Args->get(i).print(Policy, Out); } else if (NTTP->hasDefaultArgument()) { Out << " = "; - NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, - Indentation); + NTTP->getDefaultArgument()->printPretty(Out, 0, Policy, Indentation); } } else if (const TemplateTemplateParmDecl *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) { @@ -871,7 +871,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->getBody()) { Out << ' '; - OMD->getBody()->printPretty(Out, Context, 0, Policy); + OMD->getBody()->printPretty(Out, 0, Policy); Out << '\n'; } } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 5aebc2b..a7e8999 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -43,7 +43,8 @@ TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc, unsigned NumParams, SourceLocation RAngleLoc) { unsigned Size = sizeof(TemplateParameterList) + sizeof(NamedDecl *) * NumParams; - unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment; + unsigned Align = std::max(llvm::alignOf<TemplateParameterList>(), + llvm::alignOf<NamedDecl*>()); void *Mem = C.Allocate(Size, Align); return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, NumParams, RAngleLoc); diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index c1432b5..84f3fc4 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -1022,12 +1022,17 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, }; } +void Decl::dumpXML() const { + dump(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/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index dbf267b..49b119b 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -18,6 +18,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" +#include "llvm/Support/AlignOf.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -33,7 +34,8 @@ NestedNameSpecifier::FindOrInsert(const ASTContext &Context, NestedNameSpecifier *NNS = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); if (!NNS) { - NNS = new (Context, 4) NestedNameSpecifier(Mockup); + NNS = new (Context, llvm::alignOf<NestedNameSpecifier>()) + NestedNameSpecifier(Mockup); Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); } @@ -107,7 +109,9 @@ NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { NestedNameSpecifier * NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { if (!Context.GlobalNestedNameSpecifier) - Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); + Context.GlobalNestedNameSpecifier = + new (Context, llvm::alignOf<NestedNameSpecifier>()) + NestedNameSpecifier(); return Context.GlobalNestedNameSpecifier; } @@ -630,4 +634,3 @@ NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const { memcpy(Mem, Buffer, BufferSize); return NestedNameSpecifierLoc(Representation, Mem); } - diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index c704cab..a5a3287 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -65,7 +65,7 @@ bool mergedCommentIsTrailingComment(StringRef Comment) { RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, bool Merged) : Range(SR), RawTextValid(false), BriefTextValid(false), - IsAlmostTrailingComment(false), + IsAttached(false), IsAlmostTrailingComment(false), BeginLineValid(false), EndLineValid(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { @@ -87,16 +87,6 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, } } -const Decl *RawComment::getDecl() const { - if (DeclOrParsedComment.isNull()) - return NULL; - - if (const Decl *D = DeclOrParsedComment.dyn_cast<const Decl *>()) - return D; - - return DeclOrParsedComment.get<comments::FullComment *>()->getDecl(); -} - unsigned RawComment::getBeginLine(const SourceManager &SM) const { if (BeginLineValid) return BeginLine; @@ -169,7 +159,8 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { return BriefTextPtr; } -comments::FullComment *RawComment::parse(const ASTContext &Context) const { +comments::FullComment *RawComment::parse(const ASTContext &Context, + const Decl *D) const { // Make sure that RawText is valid. getRawText(Context.getSourceManager()); @@ -179,13 +170,11 @@ comments::FullComment *RawComment::parse(const ASTContext &Context) const { RawText.begin(), RawText.end()); comments::Sema S(Context.getAllocator(), Context.getSourceManager(), Context.getDiagnostics(), Traits); - S.setDecl(getDecl()); + S.setDecl(D); comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(), Context.getDiagnostics(), Traits); - comments::FullComment *FC = P.parseFullComment(); - DeclOrParsedComment = FC; - return FC; + return P.parseFullComment(); } namespace { diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index d877c3f..77452c9 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -584,22 +584,27 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, } MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, - bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, - ArrayRef<unsigned> lineends, StringRef asmstr, + SourceLocation lbraceloc, bool issimple, bool isvolatile, + ArrayRef<Token> asmtoks, ArrayRef<IdentifierInfo*> inputs, + ArrayRef<IdentifierInfo*> outputs, StringRef asmstr, ArrayRef<StringRef> clobbers, SourceLocation endloc) - : Stmt(MSAsmStmtClass), AsmLoc(asmloc), EndLoc(endloc), + : Stmt(MSAsmStmtClass), AsmLoc(asmloc), LBraceLoc(lbraceloc), EndLoc(endloc), AsmStr(asmstr.str()), IsSimple(issimple), IsVolatile(isvolatile), - NumAsmToks(asmtoks.size()), NumLineEnds(lineends.size()), - NumClobbers(clobbers.size()) { + NumAsmToks(asmtoks.size()), NumInputs(inputs.size()), + NumOutputs(outputs.size()), NumClobbers(clobbers.size()) { + + unsigned NumExprs = NumOutputs + NumInputs; + + Names = new (C) IdentifierInfo*[NumExprs]; + for (unsigned i = 0, e = NumOutputs; i != e; ++i) + Names[i] = outputs[i]; + for (unsigned i = NumOutputs, e = NumExprs; i != e; ++i) + Names[i] = inputs[i]; AsmToks = new (C) Token[NumAsmToks]; for (unsigned i = 0, e = NumAsmToks; i != e; ++i) AsmToks[i] = asmtoks[i]; - LineEnds = new (C) unsigned[NumLineEnds]; - for (unsigned i = 0, e = NumLineEnds; i != e; ++i) - LineEnds[i] = lineends[i]; - Clobbers = new (C) StringRef[NumClobbers]; for (unsigned i = 0, e = NumClobbers; i != e; ++i) { // FIXME: Avoid the allocation/copy if at all possible. diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 2f7cb55..c0960ce 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -30,17 +30,15 @@ using namespace clang; namespace { class StmtPrinter : public StmtVisitor<StmtPrinter> { raw_ostream &OS; - ASTContext &Context; unsigned IndentLevel; clang::PrinterHelper* Helper; PrintingPolicy Policy; public: - StmtPrinter(raw_ostream &os, ASTContext &C, PrinterHelper* helper, + StmtPrinter(raw_ostream &os, PrinterHelper* helper, const PrintingPolicy &Policy, unsigned Indentation = 0) - : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), - Policy(Policy) {} + : OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy) {} void PrintStmt(Stmt *S) { PrintStmt(S, Policy.Indentation); @@ -181,7 +179,7 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { first = false; } // TODO: check this - (*it)->printPretty(OS, Context); + (*it)->printPretty(OS, Policy); } OS << "]] "; PrintStmt(Node->getSubStmt(), 0); @@ -432,7 +430,12 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) { // FIXME: Implement MS style inline asm statement printer. - Indent() << "asm ()"; + Indent() << "__asm "; + if (Node->hasBraces()) + OS << "{\n"; + OS << *(Node->getAsmString()) << "\n"; + if (Node->hasBraces()) + Indent() << "}\n"; } void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { @@ -1390,7 +1393,7 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { std::string TypeS; if (Expr *Size = E->getArraySize()) { llvm::raw_string_ostream s(TypeS); - Size->printPretty(s, Context, Helper, Policy); + Size->printPretty(s, Helper, Policy); s.flush(); TypeS = "[" + TypeS + "]"; } @@ -1799,13 +1802,12 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { // Stmt method implementations //===----------------------------------------------------------------------===// -void Stmt::dumpPretty(ASTContext& Context) const { - printPretty(llvm::errs(), Context, 0, - PrintingPolicy(Context.getLangOpts())); +void Stmt::dumpPretty(ASTContext &Context) const { + printPretty(llvm::errs(), 0, PrintingPolicy(Context.getLangOpts())); } -void Stmt::printPretty(raw_ostream &OS, ASTContext& Context, - PrinterHelper* Helper, +void Stmt::printPretty(raw_ostream &OS, + PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation) const { if (this == 0) { @@ -1813,12 +1815,12 @@ void Stmt::printPretty(raw_ostream &OS, ASTContext& Context, return; } - if (Policy.Dump && &Context) { - dump(OS, Context.getSourceManager()); + if (Policy.DumpSourceManager) { + dump(OS, *Policy.DumpSourceManager); return; } - StmtPrinter P(OS, Context, Helper, Policy, Indentation); + StmtPrinter P(OS, Helper, Policy, Indentation); P.Visit(const_cast<Stmt*>(this)); } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index f8dd396..95ff4ed 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -556,8 +556,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const ASTTemplateArgumentListInfo * ASTTemplateArgumentListInfo::Create(ASTContext &C, const TemplateArgumentListInfo &List) { - std::size_t size = sizeof(CXXDependentScopeMemberExpr) + - ASTTemplateArgumentListInfo::sizeFor(List.size()); + std::size_t size = ASTTemplateArgumentListInfo::sizeFor(List.size()); void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>()); ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo(); TAI->initializeFrom(List); @@ -642,6 +641,7 @@ ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) { std::size_t ASTTemplateKWAndArgsInfo::sizeFor(unsigned NumTemplateArgs) { // Add space for the template keyword location. + // FIXME: There's room for this in the padding before the template args in + // 64-bit builds. return Base::sizeFor(NumTemplateArgs) + sizeof(SourceLocation); } - diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index e689502..8065b2d 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -145,6 +145,9 @@ DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const { assert(DiagStatePoints.front().Loc.isInvalid() && "Should have created a DiagStatePoint for command-line"); + if (!SourceMgr) + return DiagStatePoints.end() - 1; + FullSourceLoc Loc(L, *SourceMgr); if (Loc.isInvalid()) return DiagStatePoints.end() - 1; @@ -167,8 +170,9 @@ void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) && "Cannot map errors into warnings!"); assert(!DiagStatePoints.empty()); + assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location"); - FullSourceLoc Loc(L, *SourceMgr); + FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc(); FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc; // Don't allow a mapping to a warning override an error/fatal mapping. if (Map == diag::MAP_WARNING) { diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 883864f..1d495f1 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -3083,9 +3083,8 @@ public: unsigned &NumAliases) const; virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { - // FIXME: Check if this is complete switch (*Name) { - default: + default: break; case 'l': // r0-r7 case 'h': // r8-r15 case 'w': // VFP Floating point register single precision diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 65c782e..59ed313 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -229,6 +229,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } + + case Builtin::BI__builtin_conj: + case Builtin::BI__builtin_conjf: + case Builtin::BI__builtin_conjl: { + ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); + Value *Real = ComplexVal.first; + Value *Imag = ComplexVal.second; + Value *Zero = + Imag->getType()->isFPOrFPVectorTy() + ? llvm::ConstantFP::getZeroValueForNegation(Imag->getType()) + : llvm::Constant::getNullValue(Imag->getType()); + + Imag = Builder.CreateFSub(Zero, Imag, "sub"); + return RValue::getComplex(std::make_pair(Real, Imag)); + } + case Builtin::BI__builtin_creal: + case Builtin::BI__builtin_crealf: + case Builtin::BI__builtin_creall: { + ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); + return RValue::get(ComplexVal.first); + } + + case Builtin::BI__builtin_cimag: + case Builtin::BI__builtin_cimagf: + case Builtin::BI__builtin_cimagl: { + ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); + return RValue::get(ComplexVal.second); + } + case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: @@ -1720,8 +1749,29 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty), Ops, "vld1"); - case ARM::BI__builtin_neon_vld1_lane_v: - case ARM::BI__builtin_neon_vld1q_lane_v: { + case ARM::BI__builtin_neon_vld1q_lane_v: + // Handle 64-bit integer elements as a special case. Use shuffles of + // one-element vectors to avoid poor code for i64 in the backend. + if (VTy->getElementType()->isIntegerTy(64)) { + // Extract the other lane. + Ops[1] = Builder.CreateBitCast(Ops[1], Ty); + int Lane = cast<ConstantInt>(Ops[2])->getZExtValue(); + Value *SV = llvm::ConstantVector::get(ConstantInt::get(Int32Ty, 1-Lane)); + Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV); + // Load the value as a one-element vector. + Ty = llvm::VectorType::get(VTy->getElementType(), 1); + Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty); + Value *Ld = Builder.CreateCall2(F, Ops[0], + GetPointeeAlignmentValue(E->getArg(0))); + // Combine them. + SmallVector<Constant*, 2> Indices; + Indices.push_back(ConstantInt::get(Int32Ty, 1-Lane)); + Indices.push_back(ConstantInt::get(Int32Ty, Lane)); + SV = llvm::ConstantVector::get(Indices); + return Builder.CreateShuffleVector(Ops[1], Ld, SV, "vld1q_lane"); + } + // fall through + case ARM::BI__builtin_neon_vld1_lane_v: { Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ty = llvm::PointerType::getUnqual(VTy->getElementType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -2086,8 +2136,19 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty), Ops, ""); - case ARM::BI__builtin_neon_vst1_lane_v: - case ARM::BI__builtin_neon_vst1q_lane_v: { + case ARM::BI__builtin_neon_vst1q_lane_v: + // Handle 64-bit integer elements as a special case. Use a shuffle to get + // a one-element vector and avoid poor code for i64 in the backend. + if (VTy->getElementType()->isIntegerTy(64)) { + Ops[1] = Builder.CreateBitCast(Ops[1], Ty); + Value *SV = llvm::ConstantVector::get(cast<llvm::Constant>(Ops[2])); + Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV); + Ops[2] = GetPointeeAlignmentValue(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, + Ops[1]->getType()), Ops); + } + // fall through + case ARM::BI__builtin_neon_vst1_lane_v: { Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 00127ac..fd1c7a3 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -94,8 +94,10 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I = RegionMap.find(Context); - if (I != RegionMap.end()) - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(&*I->second)); + if (I != RegionMap.end()) { + llvm::Value *V = I->second; + return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + } // Check namespace. if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) @@ -227,8 +229,8 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (it != DIFileCache.end()) { // Verify that the information still exists. - if (&*it->second) - return llvm::DIFile(cast<llvm::MDNode>(it->second)); + if (llvm::Value *V = it->second) + return llvm::DIFile(cast<llvm::MDNode>(V)); } llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname()); @@ -525,8 +527,10 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) { // See if we already have the parent. llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I = RegionMap.find(Context); - if (I != RegionMap.end()) - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(&*I->second)); + if (I != RegionMap.end()) { + llvm::Value *V = I->second; + return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + } // Check namespace. if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) @@ -1660,8 +1664,8 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) { TypeCache.find(Ty.getAsOpaquePtr()); if (it != TypeCache.end()) { // Verify that the debug info still exists. - if (&*it->second) - return llvm::DIType(cast<llvm::MDNode>(it->second)); + if (llvm::Value *V = it->second) + return llvm::DIType(cast<llvm::MDNode>(V)); } return llvm::DIType(); @@ -1679,8 +1683,8 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { CompletedTypeCache.find(Ty.getAsOpaquePtr()); if (it != CompletedTypeCache.end()) { // Verify that the debug info still exists. - if (&*it->second) - return llvm::DIType(cast<llvm::MDNode>(it->second)); + if (llvm::Value *V = it->second) + return llvm::DIType(cast<llvm::MDNode>(V)); } return llvm::DIType(); @@ -1942,7 +1946,8 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI = SPCache.find(FD->getCanonicalDecl()); if (MI != SPCache.end()) { - llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second)); + llvm::Value *V = MI->second; + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) return SP; } @@ -1953,7 +1958,8 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI = SPCache.find(NextFD->getCanonicalDecl()); if (MI != SPCache.end()) { - llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second)); + llvm::Value *V = MI->second; + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) return SP; } @@ -2013,7 +2019,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator FI = SPCache.find(FD->getCanonicalDecl()); if (FI != SPCache.end()) { - llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(&*FI->second)); + llvm::Value *V = FI->second; + llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V)); if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) { llvm::MDNode *SPN = SP; LexicalBlockStack.push_back(SPN); @@ -2701,15 +2708,15 @@ void CGDebugInfo::finalize(void) { = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) { llvm::DIType Ty, RepTy; // Verify that the debug info still exists. - if (&*VI->second) - Ty = llvm::DIType(cast<llvm::MDNode>(VI->second)); + if (llvm::Value *V = VI->second) + Ty = llvm::DIType(cast<llvm::MDNode>(V)); llvm::DenseMap<void *, llvm::WeakVH>::iterator it = TypeCache.find(VI->first); if (it != TypeCache.end()) { // Verify that the debug info still exists. - if (&*it->second) - RepTy = llvm::DIType(cast<llvm::MDNode>(it->second)); + if (llvm::Value *V = it->second) + RepTy = llvm::DIType(cast<llvm::MDNode>(V)); } if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ecee7b4..1fe4c18 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -938,6 +938,50 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) { llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, llvm::MDNode *TBAAInfo) { + + // For better performance, handle vector loads differently. + if (Ty->isVectorType()) { + llvm::Value *V; + const llvm::Type *EltTy = + cast<llvm::PointerType>(Addr->getType())->getElementType(); + + const llvm::VectorType *VTy = cast<llvm::VectorType>(EltTy); + + // Handle vectors of size 3, like size 4 for better performance. + if (VTy->getNumElements() == 3) { + + // Bitcast to vec4 type. + llvm::VectorType *vec4Ty = llvm::VectorType::get(VTy->getElementType(), + 4); + llvm::PointerType *ptVec4Ty = + llvm::PointerType::get(vec4Ty, + (cast<llvm::PointerType>( + Addr->getType()))->getAddressSpace()); + llvm::Value *Cast = Builder.CreateBitCast(Addr, ptVec4Ty, + "castToVec4"); + // Now load value. + llvm::Value *LoadVal = Builder.CreateLoad(Cast, Volatile, "loadVec4"); + + // Shuffle vector to get vec3. + llvm::SmallVector<llvm::Constant*, 3> Mask; + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(getLLVMContext()), + 0)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(getLLVMContext()), + 1)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(getLLVMContext()), + 2)); + + llvm::Value *MaskV = llvm::ConstantVector::get(Mask); + V = Builder.CreateShuffleVector(LoadVal, + llvm::UndefValue::get(vec4Ty), + MaskV, "extractVec"); + return EmitFromMemory(V, Ty); + } + } + llvm::LoadInst *Load = Builder.CreateLoad(Addr); if (Volatile) Load->setVolatile(true); @@ -984,6 +1028,42 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, QualType Ty, llvm::MDNode *TBAAInfo, bool isInit) { + + // Handle vectors differently to get better performance. + if (Ty->isVectorType()) { + llvm::Type *SrcTy = Value->getType(); + llvm::VectorType *VecTy = cast<llvm::VectorType>(SrcTy); + // Handle vec3 special. + if (VecTy->getNumElements() == 3) { + llvm::LLVMContext &VMContext = getLLVMContext(); + + // Our source is a vec3, do a shuffle vector to make it a vec4. + llvm::SmallVector<llvm::Constant*, 4> Mask; + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), + 0)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), + 1)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), + 2)); + Mask.push_back(llvm::UndefValue::get(llvm::Type::getInt32Ty(VMContext))); + + llvm::Value *MaskV = llvm::ConstantVector::get(Mask); + Value = Builder.CreateShuffleVector(Value, + llvm::UndefValue::get(VecTy), + MaskV, "extractVec"); + SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4); + } + llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType()); + if (DstPtr->getElementType() != SrcTy) { + llvm::Type *MemTy = + llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace()); + Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); + } + } + Value = EmitToMemory(Value, Ty); llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 7c2c9f1..31ea1b5 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -123,7 +123,14 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, return false; } - + + // We can devirtualize calls on an object accessed by a class member access + // expression, since by C++11 [basic.life]p6 we know that it can't refer to + // a derived class object constructed in the same location. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) + if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) + return VD->getType()->isRecordType(); + // We can always devirtualize calls on temporary object expressions. if (isa<CXXConstructExpr>(Base)) return true; diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 467c779..d78908d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1691,14 +1691,36 @@ void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) { std::vector<llvm::Value*> Args; std::vector<llvm::Type *> ArgTypes; + std::string Constraints; + + // Clobbers + for (unsigned i = 0, e = S.getNumClobbers(); i != e; ++i) { + StringRef Clobber = S.getClobber(i); + + if (Clobber != "memory" && Clobber != "cc") + Clobber = Target.getNormalizedGCCRegisterName(Clobber); + + if (i != 0) + Constraints += ','; + + Constraints += "~{"; + Constraints += Clobber; + Constraints += '}'; + } + // Add machine specific clobbers std::string MachineClobbers = Target.getClobbers(); + if (!MachineClobbers.empty()) { + if (!Constraints.empty()) + Constraints += ','; + Constraints += MachineClobbers; + } llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, ArgTypes, false); llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, *S.getAsmString(), MachineClobbers, true); + llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true); llvm::CallInst *Result = Builder.CreateCall(IA, Args); Result->addAttribute(~0, llvm::Attribute::NoUnwind); Result->addAttribute(~0, llvm::Attribute::IANSDialect); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index a46f313..c2b8e4d 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -128,7 +128,7 @@ class LValue { // The alignment to use when accessing this lvalue. (For vector elements, // this is the alignment of the whole vector.) - unsigned short Alignment; + int64_t Alignment; // objective-c's ivar bool Ivar:1; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index b4234cf..ed67f7b 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -5723,6 +5723,9 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Plugin)); } + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); if (D.CCCIsCXX && diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index bb1a4e6..0f0d835 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -89,7 +89,7 @@ namespace { class ASTDeclNodeLister : public ASTConsumer, public RecursiveASTVisitor<ASTDeclNodeLister> { - typedef RecursiveASTVisitor<ASTPrinter> base; + typedef RecursiveASTVisitor<ASTDeclNodeLister> base; public: ASTDeclNodeLister(raw_ostream *Out = NULL) diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 58a6b8d..3e66613 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -447,7 +447,7 @@ Offset PTHWriter::EmitCachedSpellings() { void PTHWriter::GeneratePTH(const std::string &MainFile) { // Generate the prologue. - Out << "cfe-pth"; + Out << "cfe-pth" << '\0'; Emit32(PTHManager::Version); // Leave 4 words for the prologue. diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index f104f96..67738e9 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -452,14 +452,14 @@ PTHManager *PTHManager::Create(const std::string &file, const unsigned char *BufEnd = (unsigned char*)File->getBufferEnd(); // Check the prologue of the file. - if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 3 + 4) || - memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth") - 1) != 0) { + if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) || + memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth")) != 0) { Diags.Report(diag::err_invalid_pth_file) << file; return 0; } // Read the PTH version. - const unsigned char *p = BufBeg + (sizeof("cfe-pth") - 1); + const unsigned char *p = BufBeg + (sizeof("cfe-pth")); unsigned Version = ReadLE32(p); if (Version < PTHManager::Version) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b830d9c..cb865cc 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -68,7 +68,6 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { .Default(false); } - /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -193,6 +192,11 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } + // Type safety attributes have their own grammar. + if (AttrName->isStr("type_tag_for_datatype")) { + ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } ConsumeParen(); // ignore the left paren loc for now @@ -866,7 +870,8 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition) { for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { - LAs[i]->addDecl(D); + if (D) + LAs[i]->addDecl(D); ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition); delete LAs[i]; } @@ -1019,6 +1024,70 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, *EndLoc = T.getCloseLocation(); } +void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + T.skipToEnd(); + return; + } + IdentifierInfo *ArgumentKind = Tok.getIdentifierInfo(); + SourceLocation ArgumentKindLoc = ConsumeToken(); + + if (Tok.isNot(tok::comma)) { + Diag(Tok, diag::err_expected_comma); + T.skipToEnd(); + return; + } + ConsumeToken(); + + SourceRange MatchingCTypeRange; + TypeResult MatchingCType = ParseTypeName(&MatchingCTypeRange); + if (MatchingCType.isInvalid()) { + T.skipToEnd(); + return; + } + + bool LayoutCompatible = false; + bool MustBeNull = false; + while (Tok.is(tok::comma)) { + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + T.skipToEnd(); + return; + } + IdentifierInfo *Flag = Tok.getIdentifierInfo(); + if (Flag->isStr("layout_compatible")) + LayoutCompatible = true; + else if (Flag->isStr("must_be_null")) + MustBeNull = true; + else { + Diag(Tok, diag::err_type_safety_unknown_flag) << Flag; + T.skipToEnd(); + return; + } + ConsumeToken(); // consume flag + } + + if (!T.consumeClose()) { + Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc, + ArgumentKind, ArgumentKindLoc, + MatchingCType.release(), LayoutCompatible, + MustBeNull, AttributeList::AS_GNU); + } + + if (EndLoc) + *EndLoc = T.getCloseLocation(); +} + /// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets /// of a C++11 attribute-specifier in a location where an attribute is not /// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index d2e4309..df9b996 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1495,8 +1495,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRange) { - ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, T.getOpenLocation(), - FirstPart.take(), + ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), T.getCloseLocation()); @@ -1505,7 +1504,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // Similarly, we need to do the semantic analysis for a for-range // statement immediately in order to close over temporaries correctly. } else if (ForEach) { - ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(), + ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc, FirstPart.take(), Collection.take(), T.getCloseLocation()); @@ -1657,112 +1656,98 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SourceManager &SrcMgr = PP.getSourceManager(); SourceLocation EndLoc = AsmLoc; SmallVector<Token, 4> AsmToks; - SmallVector<unsigned, 4> LineEnds; - do { - bool InBraces = false; - unsigned short savedBraceCount = 0; - bool InAsmComment = false; - FileID FID; - unsigned LineNo = 0; - unsigned NumTokensRead = 0; - SourceLocation LBraceLoc; - - if (Tok.is(tok::l_brace)) { - // Braced inline asm: consume the opening brace. - InBraces = true; - savedBraceCount = BraceCount; - EndLoc = LBraceLoc = ConsumeBrace(); - ++NumTokensRead; - } else { - // Single-line inline asm; compute which line it is on. - std::pair<FileID, unsigned> ExpAsmLoc = - SrcMgr.getDecomposedExpansionLoc(EndLoc); - FID = ExpAsmLoc.first; - LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); - } - SourceLocation TokLoc = Tok.getLocation(); - do { - // If we hit EOF, we're done, period. - if (Tok.is(tok::eof)) - break; + bool InBraces = false; + unsigned short savedBraceCount = 0; + bool InAsmComment = false; + FileID FID; + unsigned LineNo = 0; + unsigned NumTokensRead = 0; + SourceLocation LBraceLoc; + + if (Tok.is(tok::l_brace)) { + // Braced inline asm: consume the opening brace. + InBraces = true; + savedBraceCount = BraceCount; + EndLoc = LBraceLoc = ConsumeBrace(); + ++NumTokensRead; + } else { + // Single-line inline asm; compute which line it is on. + std::pair<FileID, unsigned> ExpAsmLoc = + SrcMgr.getDecomposedExpansionLoc(EndLoc); + FID = ExpAsmLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); + } - // The asm keyword is a statement separator, so multiple asm statements - // are allowed. - if (!InAsmComment && Tok.is(tok::kw_asm)) - break; + SourceLocation TokLoc = Tok.getLocation(); + do { + // If we hit EOF, we're done, period. + if (Tok.is(tok::eof)) + break; - if (!InAsmComment && Tok.is(tok::semi)) { - // A semicolon in an asm is the start of a comment. - InAsmComment = true; - if (InBraces) { - // Compute which line the comment is on. - std::pair<FileID, unsigned> ExpSemiLoc = - SrcMgr.getDecomposedExpansionLoc(TokLoc); - FID = ExpSemiLoc.first; - LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); - } - } else if (!InBraces || InAsmComment) { - // If end-of-line is significant, check whether this token is on a - // new line. - std::pair<FileID, unsigned> ExpLoc = - SrcMgr.getDecomposedExpansionLoc(TokLoc); - if (ExpLoc.first != FID || - SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { - // If this is a single-line __asm, we're done. - if (!InBraces) - break; - // We're no longer in a comment. - InAsmComment = false; - } else if (!InAsmComment && Tok.is(tok::r_brace)) { - // Single-line asm always ends when a closing brace is seen. - // FIXME: This is compatible with Apple gcc's -fasm-blocks; what - // does MSVC do here? - break; - } + if (!InAsmComment && Tok.is(tok::semi)) { + // A semicolon in an asm is the start of a comment. + InAsmComment = true; + if (InBraces) { + // Compute which line the comment is on. + std::pair<FileID, unsigned> ExpSemiLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + FID = ExpSemiLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); } - if (!InAsmComment && InBraces && Tok.is(tok::r_brace) && - BraceCount == (savedBraceCount + 1)) { - // Consume the closing brace, and finish - EndLoc = ConsumeBrace(); + } else if (!InBraces || InAsmComment) { + // If end-of-line is significant, check whether this token is on a + // new line. + std::pair<FileID, unsigned> ExpLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + if (ExpLoc.first != FID || + SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { + // If this is a single-line __asm, we're done. + if (!InBraces) + break; + // We're no longer in a comment. + InAsmComment = false; + } else if (!InAsmComment && Tok.is(tok::r_brace)) { + // Single-line asm always ends when a closing brace is seen. + // FIXME: This is compatible with Apple gcc's -fasm-blocks; what + // does MSVC do here? break; } - - // Consume the next token; make sure we don't modify the brace count etc. - // if we are in a comment. - EndLoc = TokLoc; - if (InAsmComment) - PP.Lex(Tok); - else { - AsmToks.push_back(Tok); - ConsumeAnyToken(); - } - TokLoc = Tok.getLocation(); - ++NumTokensRead; - } while (1); - - LineEnds.push_back(AsmToks.size()); - - if (InBraces && BraceCount != savedBraceCount) { - // __asm without closing brace (this can happen at EOF). - Diag(Tok, diag::err_expected_rbrace); - Diag(LBraceLoc, diag::note_matching) << "{"; - return StmtError(); - } else if (NumTokensRead == 0) { - // Empty __asm. - Diag(Tok, diag::err_expected_lbrace); - return StmtError(); } - // Multiple adjacent asm's form together into a single asm statement - // in the AST. - if (!Tok.is(tok::kw_asm)) + if (!InAsmComment && InBraces && Tok.is(tok::r_brace) && + BraceCount == (savedBraceCount + 1)) { + // Consume the closing brace, and finish + EndLoc = ConsumeBrace(); break; - EndLoc = ConsumeToken(); + } + + // Consume the next token; make sure we don't modify the brace count etc. + // if we are in a comment. + EndLoc = TokLoc; + if (InAsmComment) + PP.Lex(Tok); + else { + AsmToks.push_back(Tok); + ConsumeAnyToken(); + } + TokLoc = Tok.getLocation(); + ++NumTokensRead; } while (1); + if (InBraces && BraceCount != savedBraceCount) { + // __asm without closing brace (this can happen at EOF). + Diag(Tok, diag::err_expected_rbrace); + Diag(LBraceLoc, diag::note_matching) << "{"; + return StmtError(); + } else if (NumTokensRead == 0) { + // Empty __asm. + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + // FIXME: We should be passing source locations for better diagnostics. - return Actions.ActOnMSAsmStmt(AsmLoc, llvm::makeArrayRef(AsmToks), - llvm::makeArrayRef(LineEnds), EndLoc); + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, + llvm::makeArrayRef(AsmToks), EndLoc); } /// ParseAsmStatement - Parse a GNU extended asm statement. diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp index 9f42fca..dcd003f 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/RewriteModernObjC.cpp @@ -241,7 +241,7 @@ namespace { // Get the new text. std::string SStr; llvm::raw_string_ostream S(SStr); - New->printPretty(S, *Context, 0, PrintingPolicy(LangOpts)); + New->printPretty(S, 0, PrintingPolicy(LangOpts)); const std::string &Str = S.str(); // If replacement succeeded or warning disabled return with no warning. @@ -2549,8 +2549,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { // The pretty printer for StringLiteral handles escape characters properly. std::string prettyBufS; llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, *Context, 0, - PrintingPolicy(LangOpts)); + Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); Preamble += prettyBuf.str(); Preamble += ","; Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; @@ -4341,7 +4340,7 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, std::string SStr; llvm::raw_string_ostream constructorExprBuf(SStr); - GlobalConstructionExp->printPretty(constructorExprBuf, *Context, 0, + GlobalConstructionExp->printPretty(constructorExprBuf, 0, PrintingPolicy(LangOpts)); globalBuf += constructorExprBuf.str(); globalBuf += ";\n"; @@ -5610,7 +5609,7 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // Get the new text. std::string SStr; llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf, *Context); + Replacement->printPretty(Buf); const std::string &Str = Buf.str(); printf("CAST = %s\n", &Str[0]); diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 425cd77..37c17e6 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -227,7 +227,7 @@ namespace { // Get the new text. std::string SStr; llvm::raw_string_ostream S(SStr); - New->printPretty(S, *Context, 0, PrintingPolicy(LangOpts)); + New->printPretty(S, 0, PrintingPolicy(LangOpts)); const std::string &Str = S.str(); // If replacement succeeded or warning disabled return with no warning. @@ -1720,8 +1720,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { CK, syncExpr); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); - syncExpr->printPretty(syncExprBuf, *Context, 0, - PrintingPolicy(LangOpts)); + syncExpr->printPretty(syncExprBuf, 0, PrintingPolicy(LangOpts)); syncBuf += syncExprBuf.str(); syncBuf += ");"; @@ -2553,8 +2552,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { // The pretty printer for StringLiteral handles escape characters properly. std::string prettyBufS; llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, *Context, 0, - PrintingPolicy(LangOpts)); + Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts)); Preamble += prettyBuf.str(); Preamble += ","; Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; @@ -4885,7 +4883,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // Get the new text. std::string SStr; llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf, *Context); + Replacement->printPretty(Buf); const std::string &Str = Buf.str(); printf("CAST = %s\n", &Str[0]); diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 0f209fd..7c79879 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -21,6 +21,8 @@ using namespace clang; size_t AttributeList::allocated_size() const { if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; + else if (IsTypeTagForDatatype) + return AttributeFactory::TypeTagForDatatypeAllocSize; return (sizeof(AttributeList) + NumArgs * sizeof(Expr*)); } diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 8199751..d8d51e7 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1477,6 +1477,21 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range; } +static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + QualType SrcType = SrcExpr.get()->getType(); + if (const PointerType *SrcPtrTy = SrcType->getAs<PointerType>()) + if (SrcPtrTy->isObjCSelType()) { + QualType DT = DestType; + if (isa<PointerType>(DestType)) + DT = DestType->getPointeeType(); + if (!DT.getUnqualifiedType()->isVoidType()) + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::warn_cast_pointer_from_sel) + << SrcType << DestType << SrcExpr.get()->getSourceRange(); + } +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -1721,7 +1736,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (CStyle && DestType->isObjCObjectPointerType()) { return TC_Success; } - + if (CStyle) + DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); + // Not casting away constness, so the only remaining check is for compatible // pointer categories. @@ -2058,6 +2075,7 @@ void CastOperation::CheckCStyleCast() { return; } } + DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); Kind = Self.PrepareScalarCast(SrcExpr, DestType); if (SrcExpr.isInvalid()) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 2594648..2559f00 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -513,6 +513,13 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args, I = FDecl->specific_attr_begin<NonNullAttr>(), E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I) CheckNonNullArguments(*I, Args, Loc); + + // Type safety checking. + for (specific_attr_iterator<ArgumentWithTypeTagAttr> + i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(), + e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>(); i != e; ++i) { + CheckArgumentWithTypeTag(*i, Args); + } } /// CheckConstructorCall - Check a constructor call for correctness and safety @@ -3170,7 +3177,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; - DstArg->printPretty(OS, Context, 0, getPrintingPolicy()); + DstArg->printPretty(OS, 0, getPrintingPolicy()); OS << ")"; Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) @@ -3267,10 +3274,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; - DstArg->printPretty(OS, Context, 0, getPrintingPolicy()); + DstArg->printPretty(OS, 0, getPrintingPolicy()); OS << ") - "; OS << "strlen("; - DstArg->printPretty(OS, Context, 0, getPrintingPolicy()); + DstArg->printPretty(OS, 0, getPrintingPolicy()); OS << ") - 1"; Diag(SL, diag::note_strncat_wrong_size) @@ -5468,3 +5475,410 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line); } } + +//===--- Layout compatibility ----------------------------------------------// + +namespace { + +bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); + +/// \brief Check if two enumeration types are layout-compatible. +bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { + // C++11 [dcl.enum] p8: + // Two enumeration types are layout-compatible if they have the same + // underlying type. + return ED1->isComplete() && ED2->isComplete() && + C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); +} + +/// \brief Check if two fields are layout-compatible. +bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { + if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) + return false; + + if (Field1->isBitField() != Field2->isBitField()) + return false; + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + unsigned Bits1 = Field1->getBitWidthValue(C); + unsigned Bits2 = Field2->getBitWidthValue(C); + + if (Bits1 != Bits2) + return false; + } + + return true; +} + +/// \brief Check if two standard-layout structs are layout-compatible. +/// (C++11 [class.mem] p17) +bool isLayoutCompatibleStruct(ASTContext &C, + RecordDecl *RD1, + RecordDecl *RD2) { + // If both records are C++ classes, check that base classes match. + if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) { + // If one of records is a CXXRecordDecl we are in C++ mode, + // thus the other one is a CXXRecordDecl, too. + const CXXRecordDecl *D2CXX = cast<CXXRecordDecl>(RD2); + // Check number of base classes. + if (D1CXX->getNumBases() != D2CXX->getNumBases()) + return false; + + // Check the base classes. + for (CXXRecordDecl::base_class_const_iterator + Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; + ++Base1, ++Base2) { + if (!isLayoutCompatible(C, Base1->getType(), Base2->getType())) + return false; + } + } else if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2)) { + // If only RD2 is a C++ class, it should have zero base classes. + if (D2CXX->getNumBases() > 0) + return false; + } + + // Check the fields. + RecordDecl::field_iterator Field2 = RD2->field_begin(), + Field2End = RD2->field_end(), + Field1 = RD1->field_begin(), + Field1End = RD1->field_end(); + for ( ; Field1 != Field1End && Field2 != Field2End; ++Field1, ++Field2) { + if (!isLayoutCompatible(C, *Field1, *Field2)) + return false; + } + if (Field1 != Field1End || Field2 != Field2End) + return false; + + return true; +} + +/// \brief Check if two standard-layout unions are layout-compatible. +/// (C++11 [class.mem] p18) +bool isLayoutCompatibleUnion(ASTContext &C, + RecordDecl *RD1, + RecordDecl *RD2) { + llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields; + for (RecordDecl::field_iterator Field2 = RD2->field_begin(), + Field2End = RD2->field_end(); + Field2 != Field2End; ++Field2) { + UnmatchedFields.insert(*Field2); + } + + for (RecordDecl::field_iterator Field1 = RD1->field_begin(), + Field1End = RD1->field_end(); + Field1 != Field1End; ++Field1) { + llvm::SmallPtrSet<FieldDecl *, 8>::iterator + I = UnmatchedFields.begin(), + E = UnmatchedFields.end(); + + for ( ; I != E; ++I) { + if (isLayoutCompatible(C, *Field1, *I)) { + bool Result = UnmatchedFields.erase(*I); + (void) Result; + assert(Result); + break; + } + } + if (I == E) + return false; + } + + return UnmatchedFields.empty(); +} + +bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { + if (RD1->isUnion() != RD2->isUnion()) + return false; + + if (RD1->isUnion()) + return isLayoutCompatibleUnion(C, RD1, RD2); + else + return isLayoutCompatibleStruct(C, RD1, RD2); +} + +/// \brief Check if two types are layout-compatible in C++11 sense. +bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return false; + + // C++11 [basic.types] p11: + // If two types T1 and T2 are the same type, then T1 and T2 are + // layout-compatible types. + if (C.hasSameType(T1, T2)) + return true; + + T1 = T1.getCanonicalType().getUnqualifiedType(); + T2 = T2.getCanonicalType().getUnqualifiedType(); + + const Type::TypeClass TC1 = T1->getTypeClass(); + const Type::TypeClass TC2 = T2->getTypeClass(); + + if (TC1 != TC2) + return false; + + if (TC1 == Type::Enum) { + return isLayoutCompatible(C, + cast<EnumType>(T1)->getDecl(), + cast<EnumType>(T2)->getDecl()); + } else if (TC1 == Type::Record) { + if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType()) + return false; + + return isLayoutCompatible(C, + cast<RecordType>(T1)->getDecl(), + cast<RecordType>(T2)->getDecl()); + } + + return false; +} +} + +//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// + +namespace { +/// \brief Given a type tag expression find the type tag itself. +/// +/// \param TypeExpr Type tag expression, as it appears in user's code. +/// +/// \param VD Declaration of an identifier that appears in a type tag. +/// +/// \param MagicValue Type tag magic value. +bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, + const ValueDecl **VD, uint64_t *MagicValue) { + while(true) { + if (!TypeExpr) + return false; + + TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts(); + + switch (TypeExpr->getStmtClass()) { + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr); + if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) { + TypeExpr = UO->getSubExpr(); + continue; + } + return false; + } + + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr); + *VD = DRE->getDecl(); + return true; + } + + case Stmt::IntegerLiteralClass: { + const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr); + llvm::APInt MagicValueAPInt = IL->getValue(); + if (MagicValueAPInt.getActiveBits() <= 64) { + *MagicValue = MagicValueAPInt.getZExtValue(); + return true; + } else + return false; + } + + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: { + const AbstractConditionalOperator *ACO = + cast<AbstractConditionalOperator>(TypeExpr); + bool Result; + if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) { + if (Result) + TypeExpr = ACO->getTrueExpr(); + else + TypeExpr = ACO->getFalseExpr(); + continue; + } + return false; + } + + case Stmt::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr); + if (BO->getOpcode() == BO_Comma) { + TypeExpr = BO->getRHS(); + continue; + } + return false; + } + + default: + return false; + } + } +} + +/// \brief Retrieve the C type corresponding to type tag TypeExpr. +/// +/// \param TypeExpr Expression that specifies a type tag. +/// +/// \param MagicValues Registered magic values. +/// +/// \param FoundWrongKind Set to true if a type tag was found, but of a wrong +/// kind. +/// +/// \param TypeInfo Information about the corresponding C type. +/// +/// \returns true if the corresponding C type was found. +bool GetMatchingCType( + const IdentifierInfo *ArgumentKind, + const Expr *TypeExpr, const ASTContext &Ctx, + const llvm::DenseMap<Sema::TypeTagMagicValue, + Sema::TypeTagData> *MagicValues, + bool &FoundWrongKind, + Sema::TypeTagData &TypeInfo) { + FoundWrongKind = false; + + // Variable declaration that has type_tag_for_datatype attribute. + const ValueDecl *VD = NULL; + + uint64_t MagicValue; + + if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue)) + return false; + + if (VD) { + for (specific_attr_iterator<TypeTagForDatatypeAttr> + I = VD->specific_attr_begin<TypeTagForDatatypeAttr>(), + E = VD->specific_attr_end<TypeTagForDatatypeAttr>(); + I != E; ++I) { + if (I->getArgumentKind() != ArgumentKind) { + FoundWrongKind = true; + return false; + } + TypeInfo.Type = I->getMatchingCType(); + TypeInfo.LayoutCompatible = I->getLayoutCompatible(); + TypeInfo.MustBeNull = I->getMustBeNull(); + return true; + } + return false; + } + + if (!MagicValues) + return false; + + llvm::DenseMap<Sema::TypeTagMagicValue, + Sema::TypeTagData>::const_iterator I = + MagicValues->find(std::make_pair(ArgumentKind, MagicValue)); + if (I == MagicValues->end()) + return false; + + TypeInfo = I->second; + return true; +} +} // unnamed namespace + +void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, + uint64_t MagicValue, QualType Type, + bool LayoutCompatible, + bool MustBeNull) { + if (!TypeTagForDatatypeMagicValues) + TypeTagForDatatypeMagicValues.reset( + new llvm::DenseMap<TypeTagMagicValue, TypeTagData>); + + TypeTagMagicValue Magic(ArgumentKind, MagicValue); + (*TypeTagForDatatypeMagicValues)[Magic] = + TypeTagData(Type, LayoutCompatible, MustBeNull); +} + +namespace { +bool IsSameCharType(QualType T1, QualType T2) { + const BuiltinType *BT1 = T1->getAs<BuiltinType>(); + if (!BT1) + return false; + + const BuiltinType *BT2 = T2->getAs<BuiltinType>(); + if (!BT2) + return false; + + BuiltinType::Kind T1Kind = BT1->getKind(); + BuiltinType::Kind T2Kind = BT2->getKind(); + + return (T1Kind == BuiltinType::SChar && T2Kind == BuiltinType::Char_S) || + (T1Kind == BuiltinType::UChar && T2Kind == BuiltinType::Char_U) || + (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || + (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); +} +} // unnamed namespace + +void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, + const Expr * const *ExprArgs) { + const IdentifierInfo *ArgumentKind = Attr->getArgumentKind(); + bool IsPointerAttr = Attr->getIsPointer(); + + const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; + bool FoundWrongKind; + TypeTagData TypeInfo; + if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, + TypeTagForDatatypeMagicValues.get(), + FoundWrongKind, TypeInfo)) { + if (FoundWrongKind) + Diag(TypeTagExpr->getExprLoc(), + diag::warn_type_tag_for_datatype_wrong_kind) + << TypeTagExpr->getSourceRange(); + return; + } + + const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; + if (IsPointerAttr) { + // Skip implicit cast of pointer to `void *' (as a function argument). + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) + if (ICE->getType()->isVoidPointerType()) + ArgumentExpr = ICE->getSubExpr(); + } + QualType ArgumentType = ArgumentExpr->getType(); + + // Passing a `void*' pointer shouldn't trigger a warning. + if (IsPointerAttr && ArgumentType->isVoidPointerType()) + return; + + if (TypeInfo.MustBeNull) { + // Type tag with matching void type requires a null pointer. + if (!ArgumentExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) { + Diag(ArgumentExpr->getExprLoc(), + diag::warn_type_safety_null_pointer_required) + << ArgumentKind->getName() + << ArgumentExpr->getSourceRange() + << TypeTagExpr->getSourceRange(); + } + return; + } + + QualType RequiredType = TypeInfo.Type; + if (IsPointerAttr) + RequiredType = Context.getPointerType(RequiredType); + + bool mismatch = false; + if (!TypeInfo.LayoutCompatible) { + mismatch = !Context.hasSameType(ArgumentType, RequiredType); + + // C++11 [basic.fundamental] p1: + // Plain char, signed char, and unsigned char are three distinct types. + // + // But we treat plain `char' as equivalent to `signed char' or `unsigned + // char' depending on the current char signedness mode. + if (mismatch) + if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(), + RequiredType->getPointeeType())) || + (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType))) + mismatch = false; + } else + if (IsPointerAttr) + mismatch = !isLayoutCompatible(Context, + ArgumentType->getPointeeType(), + RequiredType->getPointeeType()); + else + mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType); + + if (mismatch) + Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch) + << ArgumentType << ArgumentKind->getName() + << TypeInfo.LayoutCompatible << RequiredType + << ArgumentExpr->getSourceRange() + << TypeTagExpr->getSourceRange(); +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9fa757d..adf1327 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4476,7 +4476,6 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { Builder.AddResultTypeChunk("NSDictionary *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"{")); Builder.AddPlaceholderChunk("key"); - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_Colon); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("object, ..."); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3aae99a..ea181de 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6174,6 +6174,7 @@ namespace { Decl *OrigDecl; bool isRecordType; bool isPODType; + bool isReferenceType; public: typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; @@ -6182,9 +6183,11 @@ namespace { S(S), OrigDecl(OrigDecl) { isPODType = false; isRecordType = false; + isReferenceType = false; if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) { isPODType = VD->getType().isPODType(S.Context); isRecordType = VD->getType()->isRecordType(); + isReferenceType = VD->getType()->isReferenceType(); } } @@ -6192,9 +6195,9 @@ namespace { // to determine which DeclRefExpr's to check. Assume that the casts // are present and continue visiting the expression. void HandleExpr(Expr *E) { - // Skip checking T a = a where T is not a record type. Doing so is a - // way to silence uninitialized warnings. - if (isRecordType) + // Skip checking T a = a where T is not a record or reference type. + // Doing so is a way to silence uninitialized warnings. + if (isRecordType || isReferenceType) if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) HandleDeclRefExpr(DRE); @@ -6309,11 +6312,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } // Check for self-references within variable initializers. - // Variables declared within a function/method body are handled - // by a dataflow analysis. + // Variables declared within a function/method body (except for references) + // are handled by a dataflow analysis. // Record types initialized by initializer list are handled here. // Initialization by constructors are handled in TryConstructorInitialization. - if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal() && + if ((!VDecl->hasLocalStorage() || VDecl->getType()->isReferenceType()) && (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType())) CheckSelfReference(RealDecl, Init); @@ -6754,6 +6757,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, diag::err_abstract_type_in_decl, AbstractVariableType)) Var->setInvalidDecl(); + if (!Type->isDependentType() && !Var->isInvalidDecl() && + Var->getStorageClass() == SC_PrivateExtern) + Diag(Var->getLocation(), diag::warn_private_extern); + return; case VarDecl::TentativeDefinition: @@ -7027,6 +7034,42 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { // Note that we are no longer parsing the initializer for this declaration. ParsingInitForAutoVars.erase(ThisDecl); + + // Now we have parsed the initializer and can update the table of magic + // tag values. + if (ThisDecl && ThisDecl->hasAttr<TypeTagForDatatypeAttr>()) { + const VarDecl *VD = dyn_cast<VarDecl>(ThisDecl); + if (VD && VD->getType()->isIntegralOrEnumerationType()) { + for (specific_attr_iterator<TypeTagForDatatypeAttr> + I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(), + E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>(); + I != E; ++I) { + const Expr *MagicValueExpr = VD->getInit(); + if (!MagicValueExpr) { + continue; + } + llvm::APSInt MagicValueInt; + if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) { + Diag(I->getRange().getBegin(), + diag::err_type_tag_for_datatype_not_ice) + << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); + continue; + } + if (MagicValueInt.getActiveBits() > 64) { + Diag(I->getRange().getBegin(), + diag::err_type_tag_for_datatype_too_large) + << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); + continue; + } + uint64_t MagicValue = MagicValueInt.getZExtValue(); + RegisterTypeTagForDatatype(I->getArgumentKind(), + MagicValue, + I->getMatchingCType(), + I->getLayoutCompatible(), + I->getMustBeNull()); + } + } + } } Sema::DeclGroupPtrTy @@ -7623,7 +7666,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { << FD->getName() << "dllimport"; } } - ActOnDocumentableDecl(FD); + // We want to attach documentation to original Decl (which might be + // a function template). + ActOnDocumentableDecl(D); return FD; } @@ -7750,7 +7795,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Verify that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !dcl->isInvalidDecl() && - !hasAnyUnrecoverableErrorsInThisFunction()) + !hasAnyUnrecoverableErrorsInThisFunction() && + !PP.isCodeCompletionEnabled()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) { @@ -9907,6 +9953,13 @@ void Sema::ActOnFields(Scope* S, } } } + if (isa<ObjCContainerDecl>(EnclosingDecl) && + RequireNonAbstractType(FD->getLocation(), FD->getType(), + diag::err_abstract_type_in_decl, + AbstractIvarType)) { + // Ivars can not have abstract class types + FD->setInvalidDecl(); + } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); } else if (FDTy->isObjCObjectType()) { @@ -9915,8 +9968,7 @@ void Sema::ActOnFields(Scope* S, << FixItHint::CreateInsertion(FD->getLocation(), "*"); QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); - } - else if (!getLangOpts().CPlusPlus) { + } else if (!getLangOpts().CPlusPlus) { if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported) { // It's an error in ARC if a field has lifetime. // We don't want to report this in a system header, though, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 22bff86..caa7b2f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -221,6 +221,53 @@ static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, return true; } +/// \brief Check if IdxExpr is a valid argument index for a function or +/// instance method D. May output an error. +/// +/// \returns true if IdxExpr is a valid index. +static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D, + StringRef AttrName, + SourceLocation AttrLoc, + unsigned AttrArgNum, + const Expr *IdxExpr, + uint64_t &Idx) +{ + assert(isFunctionOrMethod(D) && hasFunctionProto(D)); + + // In C++ the implicit 'this' function parameter also counts. + // Parameters are counted from one. + const bool HasImplicitThisParam = isInstanceMethod(D); + const unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; + const unsigned FirstIdx = 1; + + llvm::APSInt IdxInt; + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { + S.Diag(AttrLoc, diag::err_attribute_argument_n_not_int) + << AttrName << AttrArgNum << IdxExpr->getSourceRange(); + return false; + } + + Idx = IdxInt.getLimitedValue(); + if (Idx < FirstIdx || (!isFunctionOrMethodVariadic(D) && Idx > NumArgs)) { + S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds) + << AttrName << AttrArgNum << IdxExpr->getSourceRange(); + return false; + } + Idx--; // Convert to zero-based. + if (HasImplicitThisParam) { + if (Idx == 0) { + S.Diag(AttrLoc, + diag::err_attribute_invalid_implicit_this_argument) + << AttrName << IdxExpr->getSourceRange(); + return false; + } + --Idx; + } + + return true; +} + /// /// \brief Check if passed in Decl is a field or potentially shared global var /// \return true if the Decl is a field or potentially shared global variable @@ -3523,25 +3570,16 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_Pcs: { - Expr *Arg = Attr.getArg(0); - StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (!Str || !Str->isAscii()) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) - << "pcs" << 1; - Attr.setInvalid(); - return; - } - - StringRef StrRef = Str->getString(); PcsAttr::PCSType PCS; - if (StrRef == "aapcs") + switch (CC) { + case CC_AAPCS: PCS = PcsAttr::AAPCS; - else if (StrRef == "aapcs-vfp") + break; + case CC_AAPCS_VFP: PCS = PcsAttr::AAPCS_VFP; - else { - S.Diag(Attr.getLoc(), diag::err_invalid_pcs); - Attr.setInvalid(); - return; + break; + default: + llvm_unreachable("unexpected calling convention in pcs attribute"); } D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS)); @@ -3560,10 +3598,9 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { if (attr.isInvalid()) return true; - if ((attr.getNumArgs() != 0 && - !(attr.getKind() == AttributeList::AT_Pcs && attr.getNumArgs() == 1)) || - attr.getParameterName()) { - Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0; + if (attr.getNumArgs() != ReqArgs || attr.getParameterName()) { + Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << ReqArgs; attr.setInvalid(); return true; } @@ -3594,7 +3631,10 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { CC = CC_AAPCS_VFP; break; } - // FALLS THROUGH + + attr.setInvalid(); + Diag(attr.getLoc(), diag::err_invalid_pcs); + return true; } default: llvm_unreachable("unexpected attribute kind"); } @@ -3703,6 +3743,79 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ } } +static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + StringRef AttrName = Attr.getName()->getName(); + if (!Attr.getParameterName()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier) + << Attr.getName() << /* arg num = */ 1; + return; + } + + if (Attr.getNumArgs() != 2) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << /* required args = */ 3; + return; + } + + IdentifierInfo *ArgumentKind = Attr.getParameterName(); + + if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + uint64_t ArgumentIdx; + if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName, + Attr.getLoc(), 2, + Attr.getArg(0), ArgumentIdx)) + return; + + uint64_t TypeTagIdx; + if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName, + Attr.getLoc(), 3, + Attr.getArg(1), TypeTagIdx)) + return; + + bool IsPointer = (AttrName == "pointer_with_type_tag"); + if (IsPointer) { + // Ensure that buffer has a pointer type. + QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx); + if (!BufferTy->isPointerType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) + << AttrName; + } + } + + D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(Attr.getRange(), + S.Context, + ArgumentKind, + ArgumentIdx, + TypeTagIdx, + IsPointer)); +} + +static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + IdentifierInfo *PointerKind = Attr.getParameterName(); + if (!PointerKind) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier) + << "type_tag_for_datatype" << 1; + return; + } + + QualType MatchingCType = S.GetTypeFromParser(Attr.getMatchingCType(), NULL); + + D->addAttr(::new (S.Context) TypeTagForDatatypeAttr( + Attr.getRange(), + S.Context, + PointerKind, + MatchingCType, + Attr.getLayoutCompatible(), + Attr.getMustBeNull())); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -4333,6 +4446,14 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, handleAcquiredAfterAttr(S, D, Attr); break; + // Type safety attributes. + case AttributeList::AT_ArgumentWithTypeTag: + handleArgumentWithTypeTagAttr(S, D, Attr); + break; + case AttributeList::AT_TypeTagForDatatype: + handleTypeTagForDatatypeAttr(S, D, Attr); + break; + default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1d45a68..eeac9b8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9807,7 +9807,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, if (!Failed && !Cond) { llvm::SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); - AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy()); + AssertMessage->printPretty(Msg, 0, getPrintingPolicy()); Diag(StaticAssertLoc, diag::err_static_assert_failed) << Msg.str() << AssertExpr->getSourceRange(); Failed = true; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 63bfa9d..e6266fb 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -242,8 +242,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { case EST_ComputedNoexcept: OS << "noexcept("; - OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, - getPrintingPolicy()); + OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy()); OS << ")"; break; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6a503ee..3875ba1 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9461,7 +9461,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If needed, diagnose invalid gotos and switches in the block. if (getCurFunction()->NeedsScopeChecking() && - !hasAnyUnrecoverableErrorsInThisFunction()) + !hasAnyUnrecoverableErrorsInThisFunction() && + !PP.isCodeCompletionEnabled()) DiagnoseInvalidJumps(cast<CompoundStmt>(Body)); BSI->TheDecl->setBody(cast<CompoundStmt>(Body)); diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 53f22f6..8f445e2 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1137,7 +1137,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, goto fail; // There's an implicit 'isa' ivar on all objects. // But we only actually find it this way on objects of type 'id', - // apparently.ghjg + // apparently. if (OTy->isObjCId() && Member->isStr("isa")) { Diag(MemberLoc, diag::warn_objc_isa_use); return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a874489..9382f7d 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -57,7 +57,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, StandardConversionSequence &SCS, bool CStyle, bool AllowObjCWritebackConversion); - + static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, QualType &ToType, bool InOverloadResolution, diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d22deb2..86884b7 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -28,6 +28,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -35,11 +36,15 @@ #include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -1516,7 +1521,6 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc) { @@ -1698,9 +1702,9 @@ static bool ObjCEnumerationCollection(Expr *Collection) { && Collection->getType()->getAs<ObjCObjectPointerType>() != 0; } -/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement. +/// ActOnCXXForRangeStmt - Check and build a C++11 for-range statement. /// -/// C++0x [stmt.ranged]: +/// C++11 [stmt.ranged]: /// A range-based for statement is equivalent to /// /// { @@ -1717,15 +1721,14 @@ static bool ObjCEnumerationCollection(Expr *Collection) { /// The body of the loop is not available yet, since it cannot be analysed until /// we have determined the type of the for-range-declaration. StmtResult -Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc, +Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc) { if (!First || !Range) return StmtError(); if (ObjCEnumerationCollection(Range)) - return ActOnObjCForCollectionStmt(ForLoc, LParenLoc, First, Range, - RParenLoc); + return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc); DeclStmt *DS = dyn_cast<DeclStmt>(First); assert(DS && "first part of for range not a decl stmt"); @@ -2759,165 +2762,225 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, return Owned(NS); } -// needSpaceAsmToken - This function handles whitespace around asm punctuation. -// Returns true if a space should be emitted. -static inline bool needSpaceAsmToken(Token currTok) { - static Token prevTok; - - // No need for space after prevToken. - switch(prevTok.getKind()) { - default: - break; - case tok::l_square: - case tok::r_square: - case tok::l_brace: - case tok::r_brace: - case tok::colon: - prevTok = currTok; - return false; - } +// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These +// require special handling. +static bool isMSAsmKeyword(StringRef Name) { + bool Ret = llvm::StringSwitch<bool>(Name) + .Cases("EVEN", "ALIGN", true) // Alignment directives. + .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes. + .Case("_emit", true) // _emit Pseudoinstruction. + .Default(false); + return Ret; +} - // No need for a space before currToken. - switch(currTok.getKind()) { - default: - break; - case tok::l_square: - case tok::r_square: - case tok::l_brace: - case tok::r_brace: - case tok::comma: - case tok::colon: - prevTok = currTok; - return false; - } - prevTok = currTok; - return true; +static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { + StringRef Asm; + SmallString<512> TokenBuf; + TokenBuf.resize(512); + bool StringInvalid = false; + Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid); + assert (!StringInvalid && "Expected valid string!"); + return Asm; } static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple, SourceLocation AsmLoc, ArrayRef<Token> AsmToks, - ArrayRef<unsigned> LineEnds, const TargetInfo &TI, + std::vector<llvm::BitVector> &AsmRegs, + std::vector<llvm::BitVector> &AsmNames, std::vector<std::string> &AsmStrings) { assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); - // Assume simple asm stmt until we parse a non-register identifer. + // Assume simple asm stmt until we parse a non-register identifer (or we just + // need to bail gracefully). IsSimple = true; - for (unsigned i = 0, e = LineEnds.size(); i != e; ++i) { - SmallString<512> Asm; + SmallString<512> Asm; + unsigned NumAsmStrings = 0; + for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) { + + // Determine if this should be considered a new asm. + bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() || + AsmToks[i].is(tok::kw_asm); + + // Emit the previous asm string. + if (i && isNewAsm) { + AsmStrings[NumAsmStrings++] = Asm.c_str(); + if (AsmToks[i].is(tok::kw_asm)) { + ++i; // Skip __asm + assert (i != e && "Expected another token."); + } + } - // Check the operands. - for (unsigned j = (i == 0) ? 0 : LineEnds[i-1], e = LineEnds[i]; j != e; ++j) { + // Start a new asm string with the opcode. + if (isNewAsm) { + AsmRegs[NumAsmStrings].resize(AsmToks.size()); + AsmNames[NumAsmStrings].resize(AsmToks.size()); - IdentifierInfo *II; - if (j == 0 || (i > 0 && j == LineEnds[i-1])) { - II = AsmToks[j].getIdentifierInfo(); - Asm = II->getName().str(); - continue; + StringRef Piece = AsmToks[i].getIdentifierInfo()->getName(); + // MS-style inline asm keywords require special handling. + if (isMSAsmKeyword(Piece)) + IsSimple = false; + + // TODO: Verify this is a valid opcode. + Asm = Piece; + continue; + } + + if (i && AsmToks[i].hasLeadingSpace()) + Asm += ' '; + + // Check the operand(s). + switch (AsmToks[i].getKind()) { + default: + IsSimple = false; + Asm += getSpelling(SemaRef, AsmToks[i]); + break; + case tok::comma: Asm += ","; break; + case tok::colon: Asm += ":"; break; + case tok::l_square: Asm += "["; break; + case tok::r_square: Asm += "]"; break; + case tok::l_brace: Asm += "{"; break; + case tok::r_brace: Asm += "}"; break; + case tok::numeric_constant: + Asm += getSpelling(SemaRef, AsmToks[i]); + break; + case tok::identifier: { + IdentifierInfo *II = AsmToks[i].getIdentifierInfo(); + StringRef Name = II->getName(); + + // Valid register? + if (TI.isValidGCCRegisterName(Name)) { + AsmRegs[NumAsmStrings].set(i); + Asm += Name; + break; } - if (needSpaceAsmToken(AsmToks[j])) - Asm += " "; + IsSimple = false; - switch (AsmToks[j].getKind()) { - default: - //llvm_unreachable("Unknown token."); + // MS-style inline asm keywords require special handling. + if (isMSAsmKeyword(Name)) { + IsSimple = false; + Asm += Name; break; - case tok::comma: Asm += ","; break; - case tok::colon: Asm += ":"; break; - case tok::l_square: Asm += "["; break; - case tok::r_square: Asm += "]"; break; - case tok::l_brace: Asm += "{"; break; - case tok::r_brace: Asm += "}"; break; - case tok::numeric_constant: { - SmallString<32> TokenBuf; - TokenBuf.resize(32); - bool StringInvalid = false; - Asm += SemaRef.PP.getSpelling(AsmToks[j], TokenBuf, &StringInvalid); - assert (!StringInvalid && "Expected valid string!"); + } + + // FIXME: Why are we missing this segment register? + if (Name == "fs") { + Asm += Name; break; } - case tok::identifier: { - II = AsmToks[j].getIdentifierInfo(); - StringRef Name = II->getName(); - // Valid registers don't need modification. - if (TI.isValidGCCRegisterName(Name)) { - Asm += Name; - break; - } + // Lookup the identifier. + // TODO: Someone with more experience with clang should verify this the + // proper way of doing a symbol lookup. + DeclarationName DeclName(II); + Scope *CurScope = SemaRef.getCurScope(); + LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName); + if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/)) + break; - // TODO: Lookup the identifier. - IsSimple = false; + assert (R.isSingleResult() && "Expected a single result?!"); + NamedDecl *Decl = R.getFoundDecl(); + switch (Decl->getKind()) { + default: + assert(0 && "Unknown decl kind."); + break; + case Decl::Var: { + case Decl::ParmVar: + AsmNames[NumAsmStrings].set(i); + + VarDecl *Var = cast<VarDecl>(Decl); + QualType Ty = Var->getType(); + (void)Ty; // Avoid warning. + // TODO: Patch identifier with valid operand. One potential idea is to + // probe the backend with type information to guess the possible + // operand. + break; + } } - } // AsmToks[i].getKind() + break; + } } - AsmStrings[i] = Asm.c_str(); } + + // Emit the final (and possibly only) asm string. + AsmStrings[NumAsmStrings] = Asm.c_str(); } // Build the unmodified MSAsmString. static std::string buildMSAsmString(Sema &SemaRef, ArrayRef<Token> AsmToks, - ArrayRef<unsigned> LineEnds) { + unsigned &NumAsmStrings) { assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + NumAsmStrings = 0; + SmallString<512> Asm; - SmallString<512> TokenBuf; - TokenBuf.resize(512); - unsigned AsmLineNum = 0; for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { - const char *ThisTokBuf = &TokenBuf[0]; - bool StringInvalid = false; - unsigned ThisTokLen = - Lexer::getSpelling(AsmToks[i], ThisTokBuf, SemaRef.getSourceManager(), - SemaRef.getLangOpts(), &StringInvalid); - if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]) && - needSpaceAsmToken(AsmToks[i])) - Asm += ' '; - Asm += StringRef(ThisTokBuf, ThisTokLen); - if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) { - Asm += '\n'; - ++AsmLineNum; + bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() || + AsmToks[i].is(tok::kw_asm); + + if (isNewAsm) { + ++NumAsmStrings; + if (i) + Asm += '\n'; + if (AsmToks[i].is(tok::kw_asm)) { + i++; // Skip __asm + assert (i != e && "Expected another token"); + } } + + if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm) + Asm += ' '; + + Asm += getSpelling(SemaRef, AsmToks[i]); } return Asm.c_str(); } StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, + SourceLocation LBraceLoc, ArrayRef<Token> AsmToks, - ArrayRef<unsigned> LineEnds, SourceLocation EndLoc) { // MS-style inline assembly is not fully supported, so emit a warning. Diag(AsmLoc, diag::warn_unsupported_msasm); SmallVector<StringRef,4> Clobbers; + std::set<std::string> ClobberRegs; + SmallVector<IdentifierInfo*, 4> Inputs; + SmallVector<IdentifierInfo*, 4> Outputs; // Empty asm statements don't need to instantiate the AsmParser, etc. if (AsmToks.empty()) { StringRef AsmString; MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true, - /* IsVolatile */ true, AsmToks, LineEnds, + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, AsmString, Clobbers, EndLoc); return Owned(NS); } - std::string AsmString = buildMSAsmString(*this, AsmToks, LineEnds); + unsigned NumAsmStrings; + std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings); bool IsSimple; + std::vector<llvm::BitVector> Regs; + std::vector<llvm::BitVector> Names; std::vector<std::string> PatchedAsmStrings; - PatchedAsmStrings.resize(LineEnds.size()); + + Regs.resize(NumAsmStrings); + Names.resize(NumAsmStrings); + PatchedAsmStrings.resize(NumAsmStrings); // Rewrite operands to appease the AsmParser. - patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, LineEnds, - Context.getTargetInfo(), PatchedAsmStrings); + patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, + Context.getTargetInfo(), Regs, Names, PatchedAsmStrings); // patchMSAsmStrings doesn't correctly patch non-simple asm statements. if (!IsSimple) { MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true, - /* IsVolatile */ true, AsmToks, LineEnds, + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, AsmString, Clobbers, EndLoc); return Owned(NS); } @@ -2947,7 +3010,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - OwningPtr<llvm::MCStreamer> Str; + OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); OwningPtr<llvm::MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); OwningPtr<llvm::MCTargetAsmParser> @@ -2956,13 +3019,63 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, Parser->setAssemblerDialect(1); Parser->setTargetParser(*TargetParser.get()); - // TODO: Start parsing. + // Prime the lexer. + Parser->Lex(); + + // Parse the opcode. + StringRef IDVal; + Parser->ParseIdentifier(IDVal); + + // Canonicalize the opcode to lower case. + SmallString<128> Opcode; + for (unsigned i = 0, e = IDVal.size(); i != e; ++i) + Opcode.push_back(tolower(IDVal[i])); + + // Parse the operands. + llvm::SMLoc IDLoc; + SmallVector<llvm::MCParsedAsmOperand*, 8> Operands; + bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc, + Operands); + assert (!HadError && "Unexpected error parsing instruction"); + + // Match the MCInstr. + SmallVector<llvm::MCInst, 2> Instrs; + HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs); + assert (!HadError && "Unexpected error matching instruction"); + assert ((Instrs.size() == 1) && "Expected only a single instruction."); + + // Get the instruction descriptor. + llvm::MCInst Inst = Instrs[0]; + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode()); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); + + // Build the list of clobbers. + for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) { + const llvm::MCOperand &Op = Inst.getOperand(i); + if (!Op.isReg()) + continue; + + std::string Reg; + llvm::raw_string_ostream OS(Reg); + IP->printRegName(OS, Op.getReg()); + + StringRef Clobber(OS.str()); + if (!Context.getTargetInfo().isValidClobber(Clobber)) + return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) << + Clobber); + ClobberRegs.insert(Reg); + } } + for (std::set<std::string>::iterator I = ClobberRegs.begin(), + E = ClobberRegs.end(); I != E; ++I) + Clobbers.push_back(*I); MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, IsSimple, /* IsVolatile */ true, - AsmToks, LineEnds, AsmString, Clobbers, EndLoc); - + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, + AsmString, Clobbers, EndLoc); return Owned(NS); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c8e4501..4dbf3e4 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -5518,6 +5518,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + // Add alignment attributes if necessary; these attributes are checked when + // the ASTContext lays out the structure. + if (TUK == TUK_Definition) { + AddAlignmentAttributesForRecord(Specialization); + AddMsStructLayoutForRecord(Specialization); + } + if (ModulePrivateLoc.isValid()) Diag(Specialization->getLocation(), diag::err_module_private_specialization) << (isPartialSpecialization? 1 : 0) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index c7cbc41..20e755f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -988,12 +988,11 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, SourceLocation TagLocation = KeywordLoc; - // FIXME: type might be anonymous. IdentifierInfo *Id = TD->getIdentifier(); // TODO: should we even warn on struct/class mismatches for this? Seems // like it's likely to produce a lot of spurious errors. - if (Keyword != ETK_None && Keyword != ETK_Typename) { + if (Id && Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, TagLocation, *Id)) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 20fe036..54f8dba 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2258,6 +2258,51 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ASM = ArrayType::Normal; D.setInvalidType(true); } + + // C99 6.7.5.2p1: The optional type qualifiers and the keyword static + // shall appear only in a declaration of a function parameter with an + // array type, ... + if (ASM == ArrayType::Static || ATI.TypeQuals) { + if (!(D.isPrototypeContext() || + D.getContext() == Declarator::KNRTypeListContext)) { + S.Diag(DeclType.Loc, diag::err_array_static_outside_prototype) << + (ASM == ArrayType::Static ? "'static'" : "type qualifier"); + // Remove the 'static' and the type qualifiers. + if (ASM == ArrayType::Static) + ASM = ArrayType::Normal; + ATI.TypeQuals = 0; + D.setInvalidType(true); + } + + // C99 6.7.5.2p1: ... and then only in the outermost array type + // derivation. + unsigned x = chunkIndex; + while (x != 0) { + // Walk outwards along the declarator chunks. + x--; + const DeclaratorChunk &DC = D.getTypeObject(x); + switch (DC.Kind) { + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Array: + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) << + (ASM == ArrayType::Static ? "'static'" : "type qualifier"); + if (ASM == ArrayType::Static) + ASM = ArrayType::Normal; + ATI.TypeQuals = 0; + D.setInvalidType(true); + break; + case DeclaratorChunk::Function: + case DeclaratorChunk::BlockPointer: + // These are invalid anyway, so just ignore. + break; + } + } + } + T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; @@ -3224,7 +3269,6 @@ namespace { assert(Chunk.Kind == DeclaratorChunk::Function); TL.setLocalRangeBegin(Chunk.Loc); TL.setLocalRangeEnd(Chunk.EndLoc); - TL.setTrailingReturn(Chunk.Fun.hasTrailingReturnType()); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 90d5840..619ad33 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1185,10 +1185,10 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, + SourceLocation LBraceLoc, ArrayRef<Token> AsmToks, - ArrayRef<unsigned> LineEnds, SourceLocation EndLoc) { - return getSema().ActOnMSAsmStmt(AsmLoc, AsmToks, LineEnds, EndLoc); + return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc); } /// \brief Build a new Objective-C \@try statement. @@ -1277,12 +1277,11 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, Stmt *Element, Expr *Collection, SourceLocation RParenLoc, Stmt *Body) { - StmtResult ForEachStmt = getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + StmtResult ForEachStmt = getSema().ActOnObjCForCollectionStmt(ForLoc, Element, Collection, RParenLoc); @@ -4205,7 +4204,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, QualType ResultType; - if (TL.getTrailingReturn()) { + if (T->hasTrailingReturn()) { if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(), TL.getParmArray(), TL.getNumArgs(), @@ -4262,7 +4261,6 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); - NewTL.setTrailingReturn(TL.getTrailingReturn()); for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) NewTL.setArg(i, ParamDecls[i]); @@ -4286,7 +4284,6 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); - NewTL.setTrailingReturn(false); return Result; } @@ -5612,12 +5609,9 @@ StmtResult TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { ArrayRef<Token> AsmToks = llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks()); - ArrayRef<unsigned> LineEnds = - llvm::makeArrayRef(S->getLineEnds(), S->getNumLineEnds()); - // No need to transform the asm string literal. - return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), AsmToks, LineEnds, - S->getEndLoc()); + return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), S->getLBraceLoc(), + AsmToks, S->getEndLoc()); } template<typename Derived> @@ -5808,7 +5802,6 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt( // Build a new statement. return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), - /*FIXME:*/S->getForLoc(), Element.get(), Collection.get(), S->getRParenLoc(), diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index beef338..3adbc57 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4259,7 +4259,6 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); - TL.setTrailingReturn(Record[Idx++]); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx)); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index b7718c4..425d2e3 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -486,7 +486,6 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record); Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record); - Record.push_back(TL.getTrailingReturn()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddDeclRef(TL.getArg(i), Record); } diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 30f45c7..5edcf09 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -235,17 +235,20 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, ProgramStateRef StNonNull, StNull; llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(L)); - // FIXME: Do we want to record the non-null assumption here? if (StNull && !StNonNull) { if (!BT_call_null) BT_call_null.reset( new BuiltinBug("Called function pointer is null (null dereference)")); emitBadCall(BT_call_null.get(), C, Callee); } + + C.addTransition(StNonNull); } void CallAndMessageChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); + // If this is a call to a C++ method, check if the callee is null or // undefined. if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { @@ -258,11 +261,9 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, return; } - ProgramStateRef State = C.getState(); ProgramStateRef StNonNull, StNull; llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V)); - // FIXME: Do we want to record the non-null assumption here? if (StNull && !StNonNull) { if (!BT_cxx_call_null) BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer " @@ -270,6 +271,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr()); return; } + + State = StNonNull; } // Don't check for uninitialized field values in arguments if the @@ -291,6 +294,9 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, Call.getArgExpr(i), /*IsFirstArgument=*/i == 0, checkUninitFields, Call, *BT)) return; + + // If we make it here, record our assumptions about the callee. + C.addTransition(State); } void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index fea5733..b636efb 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -25,7 +25,8 @@ using namespace ento; namespace { class DynamicTypePropagation: - public Checker< check::PostCall, + public Checker< check::PreCall, + check::PostCall, check::PostStmt<ImplicitCastExpr> > { const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, CheckerContext &C) const; @@ -34,11 +35,70 @@ class DynamicTypePropagation: const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, CheckerContext &C) const; public: + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; }; } +static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, + CheckerContext &C) { + assert(Region); + assert(MD); + + ASTContext &Ctx = C.getASTContext(); + QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); + + ProgramStateRef State = C.getState(); + State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false); + C.addTransition(State); + return; +} + +void DynamicTypePropagation::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { + // C++11 [class.cdtor]p4: When a virtual function is called directly or + // indirectly from a constructor or from a destructor, including during + // the construction or destruction of the class’s non-static data members, + // and the object to which the call applies is the object under + // construction or destruction, the function called is the final overrider + // in the constructor's or destructor's class and not one overriding it in + // a more-derived class. + + switch (Ctor->getOriginExpr()->getConstructionKind()) { + case CXXConstructExpr::CK_Complete: + case CXXConstructExpr::CK_Delegating: + // No additional type info necessary. + return; + case CXXConstructExpr::CK_NonVirtualBase: + case CXXConstructExpr::CK_VirtualBase: + if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) + recordFixedType(Target, Ctor->getDecl(), C); + return; + } + + return; + } + + if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { + // C++11 [class.cdtor]p4 (see above) + + const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); + if (!Target) + return; + + // FIXME: getRuntimeDefinition() can be expensive. It would be better to do + // this when we are entering the stack frame for the destructor. + const Decl *D = Dtor->getRuntimeDefinition().getDecl(); + if (!D) + return; + + recordFixedType(Target, cast<CXXDestructorDecl>(D), C); + return; + } +} + void DynamicTypePropagation::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // We can obtain perfect type info for return values from some calls. @@ -82,6 +142,31 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, break; } } + + return; + } + + if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { + // We may need to undo the effects of our pre-call check. + switch (Ctor->getOriginExpr()->getConstructionKind()) { + case CXXConstructExpr::CK_Complete: + case CXXConstructExpr::CK_Delegating: + // No additional work necessary. + // Note: This will leave behind the actual type of the object for + // complete constructors, but arguably that's a good thing, since it + // means the dynamic type info will be correct even for objects + // constructed with operator new. + return; + case CXXConstructExpr::CK_NonVirtualBase: + case CXXConstructExpr::CK_VirtualBase: + if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { + // We just finished a base constructor. Now we can use the subclass's + // type when resolving virtual calls. + const Decl *D = C.getLocationContext()->getDecl(); + recordFixedType(Target, cast<CXXConstructorDecl>(D), C); + } + return; + } } } diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 5503b23..3c00d99 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1107,18 +1107,6 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { if (S) break; - // Enable this code once the semantics of NSDeallocateObject are resolved - // for GC. <rdar://problem/6619988> -#if 0 - // Handle: NSDeallocateObject(id anObject); - // This method does allow 'nil' (although we don't check it now). - if (strcmp(FName, "NSDeallocateObject") == 0) { - return RetTy == Ctx.VoidTy - ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc) - : getPersistentStopSummary(); - } -#endif - if (RetTy->isPointerType()) { // For CoreFoundation ('CF') types. if (cocoa::isRefType(RetTy, "CF", FName)) { @@ -1591,28 +1579,12 @@ void RetainSummaryManager::InitializeMethodSummaries() { addClassMethSummary("NSWindow", "alloc", NoTrackYet); -#if 0 - addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", - "styleMask", "backing", "defer", NULL); - - addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", - "styleMask", "backing", "defer", "screen", NULL); -#endif - // For NSPanel (which subclasses NSWindow), allocated objects are not // self-owned. // FIXME: For now we don't track NSPanels. object for the same reason // as for NSWindow objects. addClassMethSummary("NSPanel", "alloc", NoTrackYet); -#if 0 - addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", - "styleMask", "backing", "defer", NULL); - - addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", - "styleMask", "backing", "defer", "screen", NULL); -#endif - // Don't track allocated autorelease pools yet, as it is okay to prematurely // exit a method. addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); @@ -1636,62 +1608,6 @@ void RetainSummaryManager::InitializeMethodSummaries() { } //===----------------------------------------------------------------------===// -// AutoreleaseBindings - State used to track objects in autorelease pools. -//===----------------------------------------------------------------------===// -#define AUTORELEASE_POOL_MODELING (0) -// We do not currently have complete modeling of autorelease pools. - -#if AUTORELEASE_POOL_MODELING - -typedef llvm::ImmutableMap<SymbolRef, unsigned> ARCounts; -typedef llvm::ImmutableMap<SymbolRef, ARCounts> ARPoolContents; -typedef llvm::ImmutableList<SymbolRef> ARStack; - -static int AutoRCIndex = 0; -static int AutoRBIndex = 0; - -namespace { class AutoreleasePoolContents {}; } -namespace { class AutoreleaseStack {}; } - -namespace clang { -namespace ento { -template<> struct ProgramStateTrait<AutoreleaseStack> - : public ProgramStatePartialTrait<ARStack> { - static inline void *GDMIndex() { return &AutoRBIndex; } -}; - -template<> struct ProgramStateTrait<AutoreleasePoolContents> - : public ProgramStatePartialTrait<ARPoolContents> { - static inline void *GDMIndex() { return &AutoRCIndex; } -}; -} // end GR namespace -} // end clang namespace - -static SymbolRef GetCurrentAutoreleasePool(ProgramStateRef state) { - ARStack stack = state->get<AutoreleaseStack>(); - return stack.isEmpty() ? SymbolRef() : stack.getHead(); -} - -static ProgramStateRef -SendAutorelease(ProgramStateRef state, - ARCounts::Factory &F, - SymbolRef sym) { - SymbolRef pool = GetCurrentAutoreleasePool(state); - const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool); - ARCounts newCnts(0); - - if (cnts) { - const unsigned *cnt = (*cnts).lookup(sym); - newCnts = F.add(*cnts, sym, cnt ? *cnt + 1 : 1); - } - else - newCnts = F.add(F.getEmptyMap(), sym, 1); - - return state->set<AutoreleasePoolContents>(pool, newCnts); -} -#endif - -//===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// namespace { @@ -2431,11 +2347,6 @@ class RetainCountChecker mutable OwningPtr<RetainSummaryManager> Summaries; mutable OwningPtr<RetainSummaryManager> SummariesGC; - -#if AUTORELEASE_POOL_MODELING - mutable ARCounts::Factory ARCountFactory; -#endif - mutable SummaryLogTy SummaryLog; mutable bool ShouldResetSummaryLog; @@ -2892,15 +2803,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, ResultTy)); // FIXME: Add a flag to the checker where allocations are assumed to - // *not* fail. (The code below is out-of-date, though.) -#if 0 - if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) { - bool isFeasible; - state = state.assume(loc::SymbolVal(Sym), true, isFeasible); - assert(isFeasible && "Cannot assume fresh symbol is non-null."); - } -#endif - + // *not* fail. break; } @@ -3011,9 +2914,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case NewAutoreleasePool: assert(!C.isObjCGCEnabled()); -#if AUTORELEASE_POOL_MODELING - state = state->add<AutoreleaseStack>(sym); -#endif return state; case MayEscape: @@ -3030,13 +2930,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case Autorelease: if (C.isObjCGCEnabled()) return state; - // Update the autorelease counts. - // TODO: AutoreleasePoolContents are not currently used. We will need to - // call SendAutorelease after it's wired up. -#if AUTORELEASE_POOL_MODELING - state = SendAutorelease(state, ARCountFactory, sym); -#endif V = V.autorelease(); break; @@ -3719,35 +3613,6 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, C.addTransition(state, Pred); } -//===----------------------------------------------------------------------===// -// Debug printing of refcount bindings and autorelease pools. -//===----------------------------------------------------------------------===// - -#if AUTORELEASE_POOL_MODELING -static void PrintPool(raw_ostream &Out, SymbolRef Sym, - ProgramStateRef State) { - Out << ' '; - if (Sym) - Sym->dumpToStream(Out); - else - Out << "<pool>"; - Out << ":{"; - - // Get the contents of the pool. - if (const ARCounts *Cnts = State->get<AutoreleasePoolContents>(Sym)) - for (ARCounts::iterator I = Cnts->begin(), E = Cnts->end(); I != E; ++I) - Out << '(' << I.getKey() << ',' << I.getData() << ')'; - Out << '}'; -} - -static bool UsesAutorelease(ProgramStateRef state) { - // A state uses autorelease if it allocated an autorelease pool or if it has - // objects in the caller's autorelease pool. - return !state->get<AutoreleaseStack>().isEmpty() || - state->get<AutoreleasePoolContents>(SymbolRef()); -} -#endif - void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { @@ -3761,20 +3626,6 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, I->second.print(Out); Out << NL; } - -#if AUTORELEASE_POOL_MODELING - // Print the autorelease stack. - if (UsesAutorelease(State)) { - Out << Sep << NL << "AR pool stack:"; - ARStack Stack = State->get<AutoreleaseStack>(); - - PrintPool(Out, SymbolRef(), State); // Print the caller's pool. - for (ARStack::iterator I = Stack.begin(), E = Stack.end(); I != E; ++I) - PrintPool(Out, *I, State); - - Out << NL; - } -#endif } //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 5aac640..efeba17 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -16,7 +16,7 @@ void AnalysisManager::anchor() { } AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, const LangOptions &lang, - PathDiagnosticConsumer *pd, + const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, @@ -33,7 +33,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnalysisInliningMode IMode, bool NoRetry) : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, /*addInitializers=*/true), - Ctx(ctx), Diags(diags), LangOpts(lang), PD(pd), + Ctx(ctx), Diags(diags), LangOpts(lang), + PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), MaxNodes(maxnodes), MaxVisit(maxvisit), @@ -49,29 +50,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } -AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - AnalysisManager &ParentAM) - : AnaCtxMgr(ParentAM.AnaCtxMgr.getUseUnoptimizedCFG(), - ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors, - ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers), - Ctx(ctx), Diags(diags), - LangOpts(ParentAM.LangOpts), PD(ParentAM.getPathDiagnosticConsumer()), - CreateStoreMgr(ParentAM.CreateStoreMgr), - CreateConstraintMgr(ParentAM.CreateConstraintMgr), - CheckerMgr(ParentAM.CheckerMgr), - MaxNodes(ParentAM.MaxNodes), - MaxVisit(ParentAM.MaxVisit), - VisualizeEGDot(ParentAM.VisualizeEGDot), - VisualizeEGUbi(ParentAM.VisualizeEGUbi), - PurgeDead(ParentAM.PurgeDead), - EagerlyAssume(ParentAM.EagerlyAssume), - TrimGraph(ParentAM.TrimGraph), - EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph), - IPAMode(ParentAM.IPAMode), - InlineMaxStackDepth(ParentAM.InlineMaxStackDepth), - InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize), - InliningMode(ParentAM.InliningMode), - NoRetryExhausted(ParentAM.NoRetryExhausted) -{ - AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); +AnalysisManager::~AnalysisManager() { + FlushDiagnostics(); + for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), + E = PathConsumers.end(); I != E; ++I) { + delete *I; + } +} + +void AnalysisManager::FlushDiagnostics() { + PathDiagnosticConsumer::FilesMade filesMade; + for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), + E = PathConsumers.end(); + I != E; ++I) { + (*I)->FlushDiagnostics(&filesMade); + } } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 7ba2fa7..571baec 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1345,6 +1345,9 @@ BugReport::~BugReport() { for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) { delete *I; } + while (!interestingSymbols.empty()) { + popInterestingSymbolsAndRegions(); + } } const Decl *BugReport::getDeclWithIssue() const { @@ -1386,11 +1389,11 @@ void BugReport::markInteresting(SymbolRef sym) { return; // If the symbol wasn't already in our set, note a configuration change. - if (interestingSymbols.insert(sym).second) + if (getInterestingSymbols().insert(sym).second) ++ConfigurationChangeToken; if (const SymbolMetadata *meta = dyn_cast<SymbolMetadata>(sym)) - interestingRegions.insert(meta->getRegion()); + getInterestingRegions().insert(meta->getRegion()); } void BugReport::markInteresting(const MemRegion *R) { @@ -1399,11 +1402,11 @@ void BugReport::markInteresting(const MemRegion *R) { // If the base region wasn't already in our set, note a configuration change. R = R->getBaseRegion(); - if (interestingRegions.insert(R).second) + if (getInterestingRegions().insert(R).second) ++ConfigurationChangeToken; if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) - interestingSymbols.insert(SR->getSymbol()); + getInterestingSymbols().insert(SR->getSymbol()); } void BugReport::markInteresting(SVal V) { @@ -1411,30 +1414,58 @@ void BugReport::markInteresting(SVal V) { markInteresting(V.getAsSymbol()); } -bool BugReport::isInteresting(SVal V) const { +bool BugReport::isInteresting(SVal V) { return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol()); } -bool BugReport::isInteresting(SymbolRef sym) const { +bool BugReport::isInteresting(SymbolRef sym) { if (!sym) return false; // We don't currently consider metadata symbols to be interesting // even if we know their region is interesting. Is that correct behavior? - return interestingSymbols.count(sym); + return getInterestingSymbols().count(sym); } -bool BugReport::isInteresting(const MemRegion *R) const { +bool BugReport::isInteresting(const MemRegion *R) { if (!R) return false; R = R->getBaseRegion(); - bool b = interestingRegions.count(R); + bool b = getInterestingRegions().count(R); if (b) return true; if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) - return interestingSymbols.count(SR->getSymbol()); + return getInterestingSymbols().count(SR->getSymbol()); return false; } - + +void BugReport::lazyInitializeInterestingSets() { + if (interestingSymbols.empty()) { + interestingSymbols.push_back(new Symbols()); + interestingRegions.push_back(new Regions()); + } +} + +BugReport::Symbols &BugReport::getInterestingSymbols() { + lazyInitializeInterestingSets(); + return *interestingSymbols.back(); +} + +BugReport::Regions &BugReport::getInterestingRegions() { + lazyInitializeInterestingSets(); + return *interestingRegions.back(); +} + +void BugReport::pushInterestingSymbolsAndRegions() { + interestingSymbols.push_back(new Symbols(getInterestingSymbols())); + interestingRegions.push_back(new Regions(getInterestingRegions())); +} + +void BugReport::popInterestingSymbolsAndRegions() { + delete interestingSymbols.back(); + interestingSymbols.pop_back(); + delete interestingRegions.back(); + interestingRegions.pop_back(); +} const Stmt *BugReport::getStmt() const { if (!ErrorNode) @@ -1793,12 +1824,13 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, - SmallVectorImpl<BugReport *> &bugReports) { + PathDiagnosticConsumer &PC, + ArrayRef<BugReport *> &bugReports) { assert(!bugReports.empty()); SmallVector<const ExplodedNode *, 10> errorNodes; - for (SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(), - E = bugReports.end(); I != E; ++I) { + for (ArrayRef<BugReport*>::iterator I = bugReports.begin(), + E = bugReports.end(); I != E; ++I) { errorNodes.push_back((*I)->getErrorNode()); } @@ -1818,8 +1850,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, const ExplodedNode *N = GPair.second.first; // Start building the path diagnostic... - PathDiagnosticBuilder PDB(*this, R, BackMap.get(), - getPathDiagnosticConsumer()); + PathDiagnosticBuilder PDB(*this, R, BackMap.get(), &PC); // Register additional node visitors. R->addVisitor(new NilReceiverBRVisitor()); @@ -1867,6 +1898,8 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, case PathDiagnosticConsumer::Minimal: GenerateMinimalPathDiagnostic(PD, PDB, N, visitors); break; + case PathDiagnosticConsumer::None: + llvm_unreachable("PathDiagnosticConsumer::None should never appear here"); } // Clean up the visitors we used. @@ -2022,53 +2055,21 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, return exampleReport; } -//===----------------------------------------------------------------------===// -// DiagnosticCache. This is a hack to cache analyzer diagnostics. It -// uses global state, which eventually should go elsewhere. -//===----------------------------------------------------------------------===// -namespace { -class DiagCacheItem : public llvm::FoldingSetNode { - llvm::FoldingSetNodeID ID; -public: - DiagCacheItem(BugReport *R, PathDiagnostic *PD) { - R->Profile(ID); - PD->Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &id) { - id = ID; - } - - llvm::FoldingSetNodeID &getID() { return ID; } -}; -} - -static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) { - // FIXME: Eventually this diagnostic cache should reside in something - // like AnalysisManager instead of being a static variable. This is - // really unsafe in the long term. - typedef llvm::FoldingSet<DiagCacheItem> DiagnosticCache; - static DiagnosticCache DC; - - void *InsertPos; - DiagCacheItem *Item = new DiagCacheItem(R, PD); - - if (DC.FindNodeOrInsertPos(Item->getID(), InsertPos)) { - delete Item; - return true; - } - - DC.InsertNode(Item, InsertPos); - return false; -} - void BugReporter::FlushReport(BugReportEquivClass& EQ) { SmallVector<BugReport*, 10> bugReports; BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports); - if (!exampleReport) - return; - - PathDiagnosticConsumer* PD = getPathDiagnosticConsumer(); + if (exampleReport) { + const PathDiagnosticConsumers &C = getPathDiagnosticConsumers(); + for (PathDiagnosticConsumers::const_iterator I=C.begin(), + E=C.end(); I != E; ++I) { + FlushReport(exampleReport, **I, bugReports); + } + } +} + +void BugReporter::FlushReport(BugReport *exampleReport, + PathDiagnosticConsumer &PD, + ArrayRef<BugReport*> bugReports) { // FIXME: Make sure we use the 'R' for the path that was actually used. // Probably doesn't make a difference in practice. @@ -2077,65 +2078,39 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { OwningPtr<PathDiagnostic> D(new PathDiagnostic(exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), - !PD || PD->useVerboseDescription() + PD.useVerboseDescription() ? exampleReport->getDescription() : exampleReport->getShortDescription(), BT.getCategory())); - if (!bugReports.empty()) - GeneratePathDiagnostic(*D.get(), bugReports); - - // Get the meta data. - const BugReport::ExtraTextList &Meta = - exampleReport->getExtraText(); - for (BugReport::ExtraTextList::const_iterator i = Meta.begin(), - e = Meta.end(); i != e; ++i) { - D->addMeta(*i); - } - - // Emit a summary diagnostic to the regular Diagnostics engine. - BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = exampleReport->getRanges(); - DiagnosticsEngine &Diag = getDiagnostic(); - - if (!IsCachedDiagnostic(exampleReport, D.get())) { - // Search the description for '%', as that will be interpretted as a - // format character by FormatDiagnostics. - StringRef desc = exampleReport->getShortDescription(); - - SmallString<512> TmpStr; - llvm::raw_svector_ostream Out(TmpStr); - for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { - if (*I == '%') - Out << "%%"; - else - Out << *I; - } - - Out.flush(); - unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr); - - DiagnosticBuilder diagBuilder = Diag.Report( - exampleReport->getLocation(getSourceManager()).asLocation(), ErrorDiag); - for (BugReport::ranges_iterator I = Beg; I != End; ++I) - diagBuilder << *I; + // Generate the full path diagnostic, using the generation scheme + // specified by the PathDiagnosticConsumer. + if (PD.getGenerationScheme() != PathDiagnosticConsumer::None) { + if (!bugReports.empty()) + GeneratePathDiagnostic(*D.get(), PD, bugReports); } - // Emit a full diagnostic for the path if we have a PathDiagnosticConsumer. - if (!PD) - return; - + // If the path is empty, generate a single step path with the location + // of the issue. if (D->path.empty()) { - PathDiagnosticPiece *piece = new PathDiagnosticEventPiece( - exampleReport->getLocation(getSourceManager()), - exampleReport->getDescription()); + PathDiagnosticLocation L = exampleReport->getLocation(getSourceManager()); + PathDiagnosticPiece *piece = + new PathDiagnosticEventPiece(L, exampleReport->getDescription()); + BugReport::ranges_iterator Beg, End; + llvm::tie(Beg, End) = exampleReport->getRanges(); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); - D->getActivePath().push_back(piece); } - PD->HandlePathDiagnostic(D.take()); + // Get the meta data. + const BugReport::ExtraTextList &Meta = exampleReport->getExtraText(); + for (BugReport::ExtraTextList::const_iterator i = Meta.begin(), + e = Meta.end(); i != e; ++i) { + D->addMeta(*i); + } + + PD.HandlePathDiagnostic(D.take()); } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 46aa9e2..e729587 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -323,7 +323,7 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, // Walk through lvalue-to-rvalue conversions. const Expr *Ex = dyn_cast<Expr>(S); if (Ex) { - Ex = Ex->IgnoreParenLValueCasts(); + Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { const VarRegion *R = diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index e3f4c61..5345bd5 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -207,10 +207,14 @@ SourceRange CallEvent::getArgSourceRange(unsigned Index) const { return ArgE->getSourceRange(); } +void CallEvent::dump() const { + dump(llvm::errs()); +} + void CallEvent::dump(raw_ostream &Out) const { ASTContext &Ctx = getState()->getStateManager().getContext(); if (const Expr *E = getOriginExpr()) { - E->printPretty(Out, Ctx, 0, Ctx.getPrintingPolicy()); + E->printPretty(Out, 0, Ctx.getPrintingPolicy()); Out << "\n"; return; } @@ -372,47 +376,49 @@ void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const { Regions.push_back(R); } -static const CXXMethodDecl *devirtualize(const CXXMethodDecl *MD, SVal ThisVal){ - const MemRegion *R = ThisVal.getAsRegion(); - if (!R) - return 0; - - const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R->StripCasts()); - if (!TR) - return 0; - - const CXXRecordDecl *RD = TR->getValueType()->getAsCXXRecordDecl(); - if (!RD) - return 0; - - const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD); - const FunctionDecl *Definition; - if (!Result->hasBody(Definition)) - return 0; - - return cast<CXXMethodDecl>(Definition); -} - RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { + // Do we have a decl at all? const Decl *D = getDecl(); if (!D) return RuntimeDefinition(); + // If the method is non-virtual, we know we can inline it. const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) return AnyFunctionCall::getRuntimeDefinition(); - // If the method is virtual, see if we can find the actual implementation - // based on context-sensitivity. - // FIXME: Virtual method calls behave differently when an object is being - // constructed or destructed. It's not as simple as "no devirtualization" - // because a /partially/ constructed object can be referred to through a - // base pointer. We'll eventually want to use DynamicTypeInfo here. - if (const CXXMethodDecl *Devirtualized = devirtualize(MD, getCXXThisVal())) - return RuntimeDefinition(Devirtualized); + // Do we know the implicit 'this' object being called? + const MemRegion *R = getCXXThisVal().getAsRegion(); + if (!R) + return RuntimeDefinition(); - return RuntimeDefinition(); + // Do we know anything about the type of 'this'? + DynamicTypeInfo DynType = getState()->getDynamicTypeInfo(R); + if (!DynType.isValid()) + return RuntimeDefinition(); + + // Is the type a C++ class? (This is mostly a defensive check.) + QualType RegionType = DynType.getType()->getPointeeType(); + const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); + if (!RD || !RD->hasDefinition()) + return RuntimeDefinition(); + + // Find the decl for this method in that class. + const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true); + assert(Result && "At the very least the static decl should show up."); + + // Does the decl that we found have an implementation? + const FunctionDecl *Definition; + if (!Result->hasBody(Definition)) + return RuntimeDefinition(); + + // We found a definition. If we're not sure that this devirtualization is + // actually what will happen at runtime, make sure to provide the region so + // that ExprEngine can decide what to do with it. + if (DynType.canBeASubClass()) + return RuntimeDefinition(Definition, R->StripCasts()); + return RuntimeDefinition(Definition, /*DispatchRegion=*/0); } void CXXInstanceCall::getInitialStackFrameContents( @@ -421,16 +427,17 @@ void CXXInstanceCall::getInitialStackFrameContents( AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings); // Handle the binding of 'this' in the new stack frame. - // We need to make sure we have the proper layering of CXXBaseObjectRegions. SVal ThisVal = getCXXThisVal(); if (!ThisVal.isUnknown()) { ProgramStateManager &StateMgr = getState()->getStateManager(); SValBuilder &SVB = StateMgr.getSValBuilder(); - + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl()); Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx); - if (const MemRegion *ThisReg = ThisVal.getAsRegion()) { + // If we devirtualized to a different member function, we need to make sure + // we have the proper layering of CXXBaseObjectRegions. + if (MD->getCanonicalDecl() != getDecl()->getCanonicalDecl()) { ASTContext &Ctx = SVB.getContext(); const CXXRecordDecl *Class = MD->getParent(); QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class)); @@ -439,13 +446,10 @@ void CXXInstanceCall::getInitialStackFrameContents( bool Failed; ThisVal = StateMgr.getStoreManager().evalDynamicCast(ThisVal, Ty, Failed); assert(!Failed && "Calling an incorrectly devirtualized method"); - - // If we couldn't build the correct cast, just strip off all casts. - if (ThisVal.isUnknown()) - ThisVal = loc::MemRegionVal(ThisReg->StripCasts()); } - Bindings.push_back(std::make_pair(ThisLoc, ThisVal)); + if (!ThisVal.isUnknown()) + Bindings.push_back(std::make_pair(ThisLoc, ThisVal)); } } @@ -666,6 +670,9 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, if (InterfLoc.isValid() && SM.isFromMainFile(InterfLoc)) return false; + // Assume that property accessors are not overridden. + if (getMessageKind() == OCM_PropertyAccess) + return false; // We assume that if the method is public (declared outside of main file) or // has a parent which publicly declares the method, the method could be @@ -853,4 +860,3 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(), State, CallerCtx); } - diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 8ee6723..3b2e4ec 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -154,6 +154,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { } } + // Generate a CallEvent /before/ cleaning the state, so that we can get the + // correct value for 'this' (if necessary). + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); + // Step 3: BindedRetNode -> CleanedNodes // If we can find a statement and a block in the inlined function, run remove // dead bindings before returning from the call. This is important to ensure @@ -203,21 +208,21 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { &Ctx); SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); - CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<> Call = CEMgr.getCaller(calleeCtx, CEEState); + CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState); ExplodedNodeSet DstPostCall; - getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, *Call, - *this, true); + getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, + *UpdatedCall, *this, + /*WasInlined=*/true); ExplodedNodeSet Dst; - if (isa<ObjCMethodCall>(Call)) { - getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, - cast<ObjCMethodCall>(*Call), - *this, true); + if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { + getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg, + *this, + /*WasInlined=*/true); } else if (CE) { getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE, - *this, true); + *this, /*WasInlined=*/true); } else { Dst.insert(DstPostCall); } @@ -555,12 +560,20 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, RuntimeDefinition RD = Call->getRuntimeDefinition(); const Decl *D = RD.getDecl(); if (D) { - // Explore with and without inlining the call. - if (RD.mayHaveOtherDefinitions() && - getAnalysisManager().IPAMode == DynamicDispatchBifurcate) { - BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); - return; + if (RD.mayHaveOtherDefinitions()) { + // Explore with and without inlining the call. + if (getAnalysisManager().IPAMode == DynamicDispatchBifurcate) { + BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); + return; + } + + // Don't inline if we're not in any dynamic dispatch mode. + if (getAnalysisManager().IPAMode != DynamicDispatch) { + conservativeEvalCall(*Call, Bldr, Pred, State); + return; + } } + // We are not bifurcating and we do have a Decl, so just inline. if (inlineCall(*Call, D, Bldr, Pred, State)) return; @@ -575,6 +588,7 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg, const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, ExplodedNode *Pred) { assert(BifurReg); + BifurReg = BifurReg->StripCasts(); // Check if we've performed the split already - note, we only want // to split the path once per memory region. diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 0152e32..982bcbf 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -45,7 +45,7 @@ public: virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); virtual StringRef getName() const { return "HTMLDiagnostics"; @@ -63,7 +63,7 @@ public: const char *HighlightEnd = "</span>"); void ReportDiag(const PathDiagnostic& D, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); }; } // end anonymous namespace @@ -76,10 +76,10 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, FilePrefix.appendComponent("report"); } -PathDiagnosticConsumer* -ento::createHTMLDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP) { - return new HTMLDiagnostics(prefix, PP); +void ento::createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP) { + C.push_back(new HTMLDiagnostics(prefix, PP)); } //===----------------------------------------------------------------------===// @@ -88,15 +88,15 @@ ento::createHTMLDiagnosticConsumer(const std::string& prefix, void HTMLDiagnostics::FlushDiagnosticsImpl( std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *filesMade) { for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), et = Diags.end(); it != et; ++it) { - ReportDiag(**it, FilesMade); + ReportDiag(**it, filesMade); } } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *filesMade) { // Create the HTML directory if it is missing. if (!createdDir) { @@ -266,8 +266,10 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, return; } - if (FilesMade) - FilesMade->push_back(llvm::sys::path::filename(H.str())); + if (filesMade) { + filesMade->push_back(std::make_pair(StringRef(getName()), + llvm::sys::path::filename(H.str()))); + } // Emit the HTML to disk. for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) @@ -480,29 +482,11 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, R.InsertTextBefore(Loc, os.str()); // Now highlight the ranges. - for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end(); - I != E; ++I) + ArrayRef<SourceRange> Ranges = P.getRanges(); + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { HighlightRange(R, LPosInfo.first, *I); - -#if 0 - // If there is a code insertion hint, insert that code. - // FIXME: This code is disabled because it seems to mangle the HTML - // output. I'm leaving it here because it's generally the right idea, - // but needs some help from someone more familiar with the rewriter. - for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end(); - Hint != HintEnd; ++Hint) { - if (Hint->RemoveRange.isValid()) { - HighlightRange(R, LPosInfo.first, Hint->RemoveRange, - "<span class=\"CodeRemovalHint\">", "</span>"); - } - if (Hint->InsertionLoc.isValid()) { - std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true); - EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode - + "</span>"; - R.InsertTextBefore(Hint->InsertionLoc, EscapedCode); - } } -#endif } static void EmitAlphaCounter(raw_ostream &os, unsigned n) { diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 7d52aac..c849778 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -157,13 +157,13 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { return; // FIXME: Emit a warning? // Check the source ranges. - for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(), - RE = piece->ranges_end(); - RI != RE; ++RI) { - SourceLocation L = SMgr.getExpansionLoc(RI->getBegin()); + ArrayRef<SourceRange> Ranges = piece->getRanges(); + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { + SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); if (!L.isFileID() || SMgr.getFileID(L) != FID) return; // FIXME: Emit a warning? - L = SMgr.getExpansionLoc(RI->getEnd()); + L = SMgr.getExpansionLoc(I->getEnd()); if (!L.isFileID() || SMgr.getFileID(L) != FID) return; // FIXME: Emit a warning? } @@ -240,8 +240,8 @@ struct CompareDiagnostics { }; } -void -PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) { +void PathDiagnosticConsumer::FlushDiagnostics( + PathDiagnosticConsumer::FilesMade *Files) { if (flushed) return; @@ -718,7 +718,9 @@ void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { ID.AddString(str); // FIXME: Add profiling support for code hints. ID.AddInteger((unsigned) getDisplayHint()); - for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { + ArrayRef<SourceRange> Ranges = getRanges(); + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) { ID.AddInteger(I->getBegin().getRawEncoding()); ID.AddInteger(I->getEnd().getRawEncoding()); } diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 58a4bba..d5fdd9d 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -30,23 +30,21 @@ namespace { class PlistDiagnostics : public PathDiagnosticConsumer { const std::string OutputFile; const LangOptions &LangOpts; - OwningPtr<PathDiagnosticConsumer> SubPD; const bool SupportsCrossFileDiagnostics; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, - bool supportsMultipleFiles, - PathDiagnosticConsumer *subPD); + bool supportsMultipleFiles); virtual ~PlistDiagnostics() {} void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); virtual StringRef getName() const { return "PlistDiagnostics"; } - PathGenerationScheme getGenerationScheme() const; + PathGenerationScheme getGenerationScheme() const { return Extensive; } bool supportsLogicalOpControlFlow() const { return true; } bool supportsAllBlockEdges() const { return true; } virtual bool useVerboseDescription() const { return false; } @@ -58,29 +56,20 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, - bool supportsMultipleFiles, - PathDiagnosticConsumer *subPD) - : OutputFile(output), LangOpts(LO), SubPD(subPD), + bool supportsMultipleFiles) + : OutputFile(output), LangOpts(LO), SupportsCrossFileDiagnostics(supportsMultipleFiles) {} -PathDiagnosticConsumer* -ento::createPlistDiagnosticConsumer(const std::string& s, const Preprocessor &PP, - PathDiagnosticConsumer *subPD) { - return new PlistDiagnostics(s, PP.getLangOpts(), false, subPD); +void ento::createPlistDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& s, + const Preprocessor &PP) { + C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), false)); } -PathDiagnosticConsumer* -ento::createPlistMultiFileDiagnosticConsumer(const std::string &s, - const Preprocessor &PP) { - return new PlistDiagnostics(s, PP.getLangOpts(), true, 0); -} - -PathDiagnosticConsumer::PathGenerationScheme -PlistDiagnostics::getGenerationScheme() const { - if (const PathDiagnosticConsumer *PD = SubPD.get()) - return PD->getGenerationScheme(); - - return Extensive; +void ento::createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string &s, + const Preprocessor &PP) { + C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), true)); } static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, @@ -231,15 +220,16 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, EmitLocation(o, SM, LangOpts, L, FM, indent); // Output the ranges (if any). - PathDiagnosticPiece::range_iterator RI = P.ranges_begin(), - RE = P.ranges_end(); + ArrayRef<SourceRange> Ranges = P.getRanges(); - if (RI != RE) { + if (!Ranges.empty()) { Indent(o, indent) << "<key>ranges</key>\n"; Indent(o, indent) << "<array>\n"; ++indent; - for (; RI != RE; ++RI) - EmitRange(o, SM, LangOpts, *RI, FM, indent+1); + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) { + EmitRange(o, SM, LangOpts, *I, FM, indent+1); + } --indent; Indent(o, indent) << "</array>\n"; } @@ -353,7 +343,7 @@ static void ReportPiece(raw_ostream &o, void PlistDiagnostics::FlushDiagnosticsImpl( std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *filesMade) { // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. FIDMap FM; @@ -380,11 +370,11 @@ void PlistDiagnostics::FlushDiagnosticsImpl( I!=E; ++I) { const PathDiagnosticPiece *piece = I->getPtr(); AddFID(FM, Fids, SM, piece->getLocation().asLocation()); - - for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(), - RE= piece->ranges_end(); RI != RE; ++RI) { - AddFID(FM, Fids, SM, RI->getBegin()); - AddFID(FM, Fids, SM, RI->getEnd()); + ArrayRef<SourceRange> Ranges = piece->getRanges(); + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { + AddFID(FM, Fids, SM, I->getBegin()); + AddFID(FM, Fids, SM, I->getEnd()); } if (const PathDiagnosticCallPiece *call = @@ -507,19 +497,21 @@ void PlistDiagnostics::FlushDiagnosticsImpl( EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); // Output the diagnostic to the sub-diagnostic client, if any. - if (SubPD) { - std::vector<const PathDiagnostic *> SubDiags; - SubDiags.push_back(D); - SmallVector<std::string, 1> SubFilesMade; - SubPD->FlushDiagnosticsImpl(SubDiags, &SubFilesMade); - - if (!SubFilesMade.empty()) { - o << " <key>" << SubPD->getName() << "_files</key>\n"; - o << " <array>\n"; - for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i) - o << " <string>" << SubFilesMade[i] << "</string>\n"; - o << " </array>\n"; + if (!filesMade->empty()) { + StringRef lastName; + for (FilesMade::iterator I = filesMade->begin(), E = filesMade->end(); + I != E; ++I) { + StringRef newName = I->first; + if (newName != lastName) { + if (!lastName.empty()) + o << " </array>\n"; + lastName = newName; + o << " <key>" << lastName << "_files</key>\n"; + o << " <array>\n"; + } + o << " <string>" << I->second << "</string>\n"; } + o << " </array>\n"; } // Close up the entry. @@ -531,6 +523,8 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Finish. o << "</dict>\n</plist>"; - if (FilesMade) - FilesMade->push_back(OutputFile); + if (filesMade) { + StringRef Name(getName()); + filesMade->push_back(std::make_pair(Name, OutputFile)); + } } diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index dc988cc..2000338 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -745,14 +745,16 @@ template<> struct ProgramStateTrait<DynamicTypeMap> }} DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const { + Reg = Reg->StripCasts(); + // Look up the dynamic type in the GDM. const DynamicTypeInfo *GDMType = get<DynamicTypeMap>(Reg); if (GDMType) return *GDMType; // Otherwise, fall back to what we know about the region. - if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(Reg)) - return DynamicTypeInfo(TR->getValueType()); + if (const TypedRegion *TR = dyn_cast<TypedRegion>(Reg)) + return DynamicTypeInfo(TR->getLocationType(), /*CanBeSubclass=*/false); if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) { SymbolRef Sym = SR->getSymbol(); @@ -764,6 +766,7 @@ DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const { ProgramStateRef ProgramState::setDynamicTypeInfo(const MemRegion *Reg, DynamicTypeInfo NewTy) const { + Reg = Reg->StripCasts(); ProgramStateRef NewState = set<DynamicTypeMap>(Reg, NewTy); assert(NewState); return NewState; diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp index e5b8553..66bf4bb 100644 --- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp @@ -32,7 +32,7 @@ public: : OutputFile(output), Diag(diag) {} void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); virtual StringRef getName() const { return "TextPathDiagnostics"; @@ -47,15 +47,15 @@ public: } // end anonymous namespace -PathDiagnosticConsumer* -ento::createTextPathDiagnosticConsumer(const std::string& out, - const Preprocessor &PP) { - return new TextPathDiagnostics(out, PP.getDiagnostics()); +void ento::createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& out, + const Preprocessor &PP) { + C.push_back(new TextPathDiagnostics(out, PP.getDiagnostics())); } void TextPathDiagnostics::FlushDiagnosticsImpl( std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *) { for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), et = Diags.end(); it != et; ++it) { const PathDiagnostic *D = *it; diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index fcdaaea..34b5266 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -64,14 +64,55 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); // Special PathDiagnosticConsumers. //===----------------------------------------------------------------------===// -static PathDiagnosticConsumer* -createPlistHTMLDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP) { - PathDiagnosticConsumer *PD = - createHTMLDiagnosticConsumer(llvm::sys::path::parent_path(prefix), PP); - return createPlistDiagnosticConsumer(prefix, PP, PD); +static void createPlistHTMLDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string &prefix, + const Preprocessor &PP) { + createHTMLDiagnosticConsumer(C, llvm::sys::path::parent_path(prefix), PP); + createPlistDiagnosticConsumer(C, prefix, PP); } +namespace { +class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { + DiagnosticsEngine &Diag; +public: + ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {} + virtual ~ClangDiagPathDiagConsumer() {} + virtual StringRef getName() const { return "ClangDiags"; } + virtual bool useVerboseDescription() const { return false; } + virtual PathGenerationScheme getGenerationScheme() const { return None; } + + void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + FilesMade *filesMade) { + for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(), + E = Diags.end(); I != E; ++I) { + const PathDiagnostic *PD = *I; + StringRef desc = PD->getDescription(); + SmallString<512> TmpStr; + llvm::raw_svector_ostream Out(TmpStr); + for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { + if (*I == '%') + Out << "%%"; + else + Out << *I; + } + Out.flush(); + unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, + TmpStr); + SourceLocation L = PD->getLocation().asLocation(); + DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag); + + // Get the ranges from the last point in the path. + ArrayRef<SourceRange> Ranges = PD->path.back()->getRanges(); + + for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { + diagBuilder << *I; + } + } + } +}; +} // end anonymous namespace + //===----------------------------------------------------------------------===// // AnalysisConsumer declaration. //===----------------------------------------------------------------------===// @@ -105,8 +146,8 @@ public: /// working with a PCH file. SetOfDecls LocalTUDecls; - // PD is owned by AnalysisManager. - PathDiagnosticConsumer *PD; + // Set of PathDiagnosticConsumers. Owned by AnalysisManager. + PathDiagnosticConsumers PathConsumers; StoreManagerCreator CreateStoreMgr; ConstraintManagerCreator CreateConstraintMgr; @@ -126,7 +167,7 @@ public: const AnalyzerOptions& opts, ArrayRef<std::string> plugins) : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0), - Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) { + Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) { DigestAnalyzerOptions(); if (Opts.PrintStats) { llvm::EnableStatistics(); @@ -141,17 +182,19 @@ public: void DigestAnalyzerOptions() { // Create the PathDiagnosticConsumer. + PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics())); + if (!OutDir.empty()) { switch (Opts.AnalysisDiagOpt) { default: #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ - case PD_##NAME: PD = CREATEFN(OutDir, PP); break; + case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break; #include "clang/Frontend/Analyses.def" } } else if (Opts.AnalysisDiagOpt == PD_TEXT) { // Create the text client even without a specified output file since // it just uses diagnostic notes. - PD = createTextPathDiagnosticConsumer("", PP); + createTextPathDiagnosticConsumer(PathConsumers, "", PP); } // Create the analyzer component creators. @@ -205,9 +248,12 @@ public: Ctx = &Context; checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins, PP.getDiagnostics())); - Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), - PP.getLangOpts(), PD, - CreateStoreMgr, CreateConstraintMgr, + Mgr.reset(new AnalysisManager(*Ctx, + PP.getDiagnostics(), + PP.getLangOpts(), + PathConsumers, + CreateStoreMgr, + CreateConstraintMgr, checkerMgr.get(), Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, |