summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2012-08-19 10:33:04 +0000
committerdim <dim@FreeBSD.org>2012-08-19 10:33:04 +0000
commitcc73504950eb7b5dff2dded9bedd67bc36d64641 (patch)
tree5b9c2fa9d79942fbdce3d618e37e27c18263af9a /lib
parent554bcb69c2d785a011a30e7db87a36a87fe7db10 (diff)
downloadFreeBSD-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')
-rw-r--r--lib/AST/APValue.cpp5
-rw-r--r--lib/AST/ASTContext.cpp68
-rw-r--r--lib/AST/ASTDiagnostic.cpp2
-rw-r--r--lib/AST/CommentCommandTraits.cpp10
-rw-r--r--lib/AST/DeclCXX.cpp13
-rw-r--r--lib/AST/DeclPrinter.cpp56
-rw-r--r--lib/AST/DeclTemplate.cpp3
-rw-r--r--lib/AST/DumpXML.cpp5
-rw-r--r--lib/AST/NestedNameSpecifier.cpp9
-rw-r--r--lib/AST/RawCommentList.cpp21
-rw-r--r--lib/AST/Stmt.cpp23
-rw-r--r--lib/AST/StmtPrinter.cpp32
-rw-r--r--lib/AST/TemplateBase.cpp6
-rw-r--r--lib/Basic/Diagnostic.cpp6
-rw-r--r--lib/Basic/Targets.cpp3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp69
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp41
-rw-r--r--lib/CodeGen/CGExpr.cpp80
-rw-r--r--lib/CodeGen/CGExprCXX.cpp9
-rw-r--r--lib/CodeGen/CGStmt.cpp24
-rw-r--r--lib/CodeGen/CGValue.h2
-rw-r--r--lib/Driver/Tools.cpp3
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/CacheTokens.cpp2
-rw-r--r--lib/Lex/PTHLexer.cpp6
-rw-r--r--lib/Parse/ParseDecl.cpp73
-rw-r--r--lib/Parse/ParseStmt.cpp181
-rw-r--r--lib/Rewrite/RewriteModernObjC.cpp9
-rw-r--r--lib/Rewrite/RewriteObjC.cpp10
-rw-r--r--lib/Sema/AttributeList.cpp2
-rw-r--r--lib/Sema/SemaCast.cpp20
-rw-r--r--lib/Sema/SemaChecking.cpp420
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1
-rw-r--r--lib/Sema/SemaDecl.cpp72
-rw-r--r--lib/Sema/SemaDeclAttr.cpp163
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp3
-rw-r--r--lib/Sema/SemaExprMember.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp2
-rw-r--r--lib/Sema/SemaStmt.cpp329
-rw-r--r--lib/Sema/SemaTemplate.cpp7
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp3
-rw-r--r--lib/Sema/SemaType.cpp46
-rw-r--r--lib/Sema/TreeTransform.h19
-rw-r--r--lib/Serialization/ASTReader.cpp1
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp87
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp151
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp45
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp189
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp86
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp48
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp74
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,
OpenPOWER on IntegriCloud