summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2011-02-26 22:09:03 +0000
committerdim <dim@FreeBSD.org>2011-02-26 22:09:03 +0000
commita0fb00f9837bd0d2e5948f16f6a6b82a7a628f51 (patch)
treeabae0246ec9156cc1a7cbb947b2b0dfe95fa3189 /lib
parent39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (diff)
downloadFreeBSD-src-a0fb00f9837bd0d2e5948f16f6a6b82a7a628f51.zip
FreeBSD-src-a0fb00f9837bd0d2e5948f16f6a6b82a7a628f51.tar.gz
Vendor import of clang trunk r126547:
http://llvm.org/svn/llvm-project/cfe/trunk@126547
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp106
-rw-r--r--lib/AST/ASTImporter.cpp48
-rw-r--r--lib/AST/Decl.cpp73
-rw-r--r--lib/AST/DeclBase.cpp16
-rw-r--r--lib/AST/DeclCXX.cpp32
-rw-r--r--lib/AST/DeclPrinter.cpp6
-rw-r--r--lib/AST/Expr.cpp13
-rw-r--r--lib/AST/ExprCXX.cpp42
-rw-r--r--lib/AST/ExprConstant.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp10
-rw-r--r--lib/AST/NestedNameSpecifier.cpp182
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp93
-rw-r--r--lib/AST/Stmt.cpp4
-rw-r--r--lib/AST/StmtDumper.cpp4
-rw-r--r--lib/AST/TemplateBase.cpp18
-rw-r--r--lib/Analysis/AnalysisContext.cpp28
-rw-r--r--lib/Analysis/CFG.cpp53
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp76
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Basic/DiagnosticIDs.cpp11
-rw-r--r--lib/Basic/SourceManager.cpp17
-rw-r--r--lib/Basic/Targets.cpp1
-rw-r--r--lib/CodeGen/CGBlocks.cpp36
-rw-r--r--lib/CodeGen/CGBlocks.h1
-rw-r--r--lib/CodeGen/CGClass.cpp11
-rw-r--r--lib/CodeGen/CGCleanup.cpp2
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp465
-rw-r--r--lib/CodeGen/CGDebugInfo.h12
-rw-r--r--lib/CodeGen/CGDecl.cpp386
-rw-r--r--lib/CodeGen/CGException.cpp16
-rw-r--r--lib/CodeGen/CGExpr.cpp82
-rw-r--r--lib/CodeGen/CGObjC.cpp25
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp15
-rw-r--r--lib/CodeGen/CGObjCMac.cpp11
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp26
-rw-r--r--lib/CodeGen/CodeGenFunction.h50
-rw-r--r--lib/CodeGen/CodeGenModule.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.h11
-rw-r--r--lib/CodeGen/TargetInfo.cpp11
-rw-r--r--lib/Driver/ToolChain.cpp3
-rw-r--r--lib/Driver/ToolChains.cpp14
-rw-r--r--lib/Driver/Tools.cpp10
-rw-r--r--lib/Frontend/ASTUnit.cpp3
-rw-r--r--lib/Frontend/CompilerInvocation.cpp52
-rw-r--r--lib/Frontend/DocumentXML.cpp5
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp107
-rw-r--r--lib/Frontend/InitPreprocessor.cpp37
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp14
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp8
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp6
-rw-r--r--lib/Headers/CMakeLists.txt5
-rw-r--r--lib/Lex/PPDirectives.cpp9
-rw-r--r--lib/Lex/Pragma.cpp68
-rw-r--r--lib/Lex/TokenLexer.cpp5
-rw-r--r--lib/Parse/ParseDecl.cpp49
-rw-r--r--lib/Parse/ParseExprCXX.cpp55
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/Parser.cpp8
-rw-r--r--lib/Rewrite/RewriteObjC.cpp27
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp78
-rw-r--r--lib/Sema/DeclSpec.cpp236
-rw-r--r--lib/Sema/Sema.cpp29
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp257
-rw-r--r--lib/Sema/SemaChecking.cpp74
-rw-r--r--lib/Sema/SemaDecl.cpp75
-rw-r--r--lib/Sema/SemaDeclAttr.cpp48
-rw-r--r--lib/Sema/SemaDeclCXX.cpp54
-rw-r--r--lib/Sema/SemaDeclObjC.cpp70
-rw-r--r--lib/Sema/SemaExpr.cpp406
-rw-r--r--lib/Sema/SemaExprCXX.cpp52
-rw-r--r--lib/Sema/SemaInit.cpp304
-rw-r--r--lib/Sema/SemaLookup.cpp7
-rw-r--r--lib/Sema/SemaOverload.cpp77
-rw-r--r--lib/Sema/SemaStmt.cpp104
-rw-r--r--lib/Sema/SemaTemplate.cpp36
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp14
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp11
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp158
-rw-r--r--lib/Sema/SemaType.cpp187
-rw-r--r--lib/Sema/TreeTransform.h323
-rw-r--r--lib/Sema/TypeLocBuilder.h13
-rw-r--r--lib/Serialization/ASTReader.cpp128
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp32
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp20
-rw-r--r--lib/Serialization/ASTWriter.cpp71
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp15
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp116
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt14
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp261
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td32
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp56
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprEngine.cpp105
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp148
-rw-r--r--lib/StaticAnalyzer/Checkers/InternalChecks.h3
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp123
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp (renamed from lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp)63
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp148
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp50
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp58
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp70
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp397
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp5
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp6
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp18
121 files changed, 4851 insertions, 2638 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 945dfb8..9c24550 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -205,7 +205,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0), PrintingPolicy(LOpts),
LastSDM(0, 0),
- UniqueBlockByRefTypeID(0), UniqueBlockParmTypeID(0) {
+ UniqueBlockByRefTypeID(0) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
ObjCSelRedefinitionType = QualType();
@@ -874,7 +874,7 @@ ASTContext::getTypeInfo(const Type *T) const {
case Type::Auto: {
const AutoType *A = cast<AutoType>(T);
assert(A->isDeduced() && "Cannot request the size of a dependent type");
- return getTypeInfo(cast<AutoType>(T)->getDeducedType().getTypePtr());
+ return getTypeInfo(A->getDeducedType().getTypePtr());
}
case Type::Paren:
@@ -2683,12 +2683,22 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
return QualType(dt, 0);
}
-/// getAutoType - Unlike many "get<Type>" functions, we don't unique
-/// AutoType AST's.
+/// getAutoType - We only unique auto types after they've been deduced.
QualType ASTContext::getAutoType(QualType DeducedType) const {
- AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType);
- Types.push_back(at);
- return QualType(at, 0);
+ void *InsertPos = 0;
+ if (!DeducedType.isNull()) {
+ // Look in the folding set for an existing type.
+ llvm::FoldingSetNodeID ID;
+ AutoType::Profile(ID, DeducedType);
+ if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(AT, 0);
+ }
+
+ AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType);
+ Types.push_back(AT);
+ if (InsertPos)
+ AutoTypes.InsertNode(AT, InsertPos);
+ return QualType(AT, 0);
}
/// getTagDeclType - Return the unique reference to the type for the
@@ -2971,7 +2981,15 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
case NestedNameSpecifier::Namespace:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
- return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
+ return NestedNameSpecifier::Create(*this, 0,
+ NNS->getAsNamespace()->getOriginalNamespace());
+
+ case NestedNameSpecifier::NamespaceAlias:
+ // A namespace is canonical; build a nested-name-specifier with
+ // this namespace and no prefix.
+ return NestedNameSpecifier::Create(*this, 0,
+ NNS->getAsNamespaceAlias()->getNamespace()
+ ->getOriginalNamespace());
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
@@ -3609,78 +3627,6 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
return getPointerType(getTagDeclType(T));
}
-
-QualType ASTContext::getBlockParmType(
- bool BlockHasCopyDispose,
- llvm::SmallVectorImpl<const Expr *> &Layout) const {
-
- // FIXME: Move up
- llvm::SmallString<36> Name;
- llvm::raw_svector_ostream(Name) << "__block_literal_"
- << ++UniqueBlockParmTypeID;
- RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
- T->startDefinition();
- QualType FieldTypes[] = {
- getPointerType(VoidPtrTy),
- IntTy,
- IntTy,
- getPointerType(VoidPtrTy),
- (BlockHasCopyDispose ?
- getPointerType(getBlockDescriptorExtendedType()) :
- getPointerType(getBlockDescriptorType()))
- };
-
- const char *FieldNames[] = {
- "__isa",
- "__flags",
- "__reserved",
- "__FuncPtr",
- "__descriptor"
- };
-
- for (size_t i = 0; i < 5; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false);
- Field->setAccess(AS_public);
- T->addDecl(Field);
- }
-
- for (unsigned i = 0; i < Layout.size(); ++i) {
- const Expr *E = Layout[i];
-
- QualType FieldType = E->getType();
- IdentifierInfo *FieldName = 0;
- if (isa<CXXThisExpr>(E)) {
- FieldName = &Idents.get("this");
- } else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E)) {
- const ValueDecl *D = BDRE->getDecl();
- FieldName = D->getIdentifier();
- if (BDRE->isByRef())
- FieldType = BuildByRefType(D->getName(), FieldType);
- } else {
- // Padding.
- assert(isa<ConstantArrayType>(FieldType) &&
- isa<DeclRefExpr>(E) &&
- !cast<DeclRefExpr>(E)->getDecl()->getDeclName() &&
- "doesn't match characteristics of padding decl");
- }
-
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- FieldName, FieldType, /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false);
- Field->setAccess(AS_public);
- T->addDecl(Field);
- }
-
- T->completeDefinition();
-
- return getPointerType(getTagDeclType(T));
-}
-
void ASTContext::setObjCFastEnumerationStateType(QualType T) {
const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid ObjCFAstEnumerationStateType");
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 65c0a3b..21f10fb 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2097,11 +2097,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D->isScoped(), D->isScopedUsingClassTag(),
D->isFixed());
// Import the qualifier, if any.
- if (D->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
- SourceRange NNSRange = Importer.Import(D->getQualifierRange());
- D2->setQualifierInfo(NNS, NNSRange);
- }
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, D2);
@@ -2225,12 +2221,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()));
}
- // Import the qualifier, if any.
- if (D->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
- SourceRange NNSRange = Importer.Import(D->getQualifierRange());
- D2->setQualifierInfo(NNS, NNSRange);
- }
+
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(D2);
}
@@ -2408,11 +2400,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
// Import the qualifier, if any.
- if (D->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
- SourceRange NNSRange = Importer.Import(D->getQualifierRange());
- ToFunction->setQualifierInfo(NNS, NNSRange);
- }
+ ToFunction->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
ToFunction->setVirtualAsWritten(D->isVirtualAsWritten());
@@ -2666,12 +2654,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
Name.getAsIdentifierInfo(), T, TInfo,
D->getStorageClass(),
D->getStorageClassAsWritten());
- // Import the qualifier, if any.
- if (D->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
- SourceRange NNSRange = Importer.Import(D->getQualifierRange());
- ToVar->setQualifierInfo(NNS, NNSRange);
- }
+ ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToVar);
@@ -3591,14 +3574,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(DTemplated->getTagKeywordLoc()));
D2Templated->setAccess(DTemplated->getAccess());
-
-
- // Import the qualifier, if any.
- if (DTemplated->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(DTemplated->getQualifier());
- SourceRange NNSRange = Importer.Import(DTemplated->getQualifierRange());
- D2Templated->setQualifierInfo(NNS, NNSRange);
- }
+ D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
D2Templated->setLexicalDeclContext(LexicalDC);
// Create the class template declaration itself.
@@ -3703,12 +3679,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
ClassTemplate->AddSpecialization(D2, InsertPos);
// Import the qualifier, if any.
- if (D->getQualifier()) {
- NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
- SourceRange NNSRange = Importer.Import(D->getQualifierRange());
- D2->setQualifierInfo(NNS, NNSRange);
- }
-
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
// Add the specialization to this context.
D2->setLexicalDeclContext(LexicalDC);
@@ -4067,6 +4038,11 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
return 0;
}
+NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
+ // FIXME: Implement!
+ return NestedNameSpecifierLoc();
+}
+
TemplateName ASTImporter::Import(TemplateName From) {
switch (From.getKind()) {
case TemplateName::Template:
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 56db8c7..73fe117 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -266,8 +266,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
return LinkageInfo::internal();
}
- if (D->isInAnonymousNamespace())
- return LinkageInfo::uniqueExternal();
+ if (D->isInAnonymousNamespace()) {
+ const VarDecl *Var = dyn_cast<VarDecl>(D);
+ const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
+ if ((!Var || !Var->isExternC()) && (!Func || !Func->isExternC()))
+ return LinkageInfo::uniqueExternal();
+ }
// Set up the defaults.
@@ -704,7 +708,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// external linkage.
if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- if (Function->isInAnonymousNamespace())
+ if (Function->isInAnonymousNamespace() && !Function->isExternC())
return LinkageInfo::uniqueExternal();
LinkageInfo LV;
@@ -725,7 +729,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D))
if (Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->isInAnonymousNamespace())
+ if (Var->isInAnonymousNamespace() && !Var->isExternC())
return LinkageInfo::uniqueExternal();
LinkageInfo LV;
@@ -837,8 +841,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
// UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
// We want to keep it, unless it nominates same namespace.
if (getKind() == Decl::UsingDirective) {
- return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() ==
- cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace();
+ return cast<UsingDirectiveDecl>(this)->getNominatedNamespace()
+ ->getOriginalNamespace() ==
+ cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace()
+ ->getOriginalNamespace();
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
@@ -864,9 +870,13 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
return cast<UsingShadowDecl>(this)->getTargetDecl() ==
cast<UsingShadowDecl>(OldD)->getTargetDecl();
- if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD))
- return cast<UsingDecl>(this)->getTargetNestedNameDecl() ==
- cast<UsingDecl>(OldD)->getTargetNestedNameDecl();
+ if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD)) {
+ ASTContext &Context = getASTContext();
+ return Context.getCanonicalNestedNameSpecifier(
+ cast<UsingDecl>(this)->getQualifier()) ==
+ Context.getCanonicalNestedNameSpecifier(
+ cast<UsingDecl>(OldD)->getQualifier());
+ }
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
@@ -927,9 +937,8 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
return SourceLocation();
}
-void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange) {
- if (Qualifier) {
+void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
+ if (QualifierLoc) {
// Make sure the extended decl info is allocated.
if (!hasExtInfo()) {
// Save (non-extended) type source info pointer.
@@ -940,12 +949,10 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
getExtInfo()->TInfo = savedTInfo;
}
// Set qualifier info.
- getExtInfo()->NNS = Qualifier;
- getExtInfo()->NNSRange = QualifierRange;
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
- assert(QualifierRange.isInvalid());
if (hasExtInfo()) {
// Save type source info pointer.
TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
@@ -967,7 +974,7 @@ QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context,
TemplateParameterList **TPLists) {
assert((NumTPLists == 0 || TPLists != 0) &&
"Empty array of template parameters with positive size!");
- assert((NumTPLists == 0 || NNS) &&
+ assert((NumTPLists == 0 || QualifierLoc) &&
"Nonempty array of template parameters with no qualifier!");
// Free previous template parameters (if any).
@@ -1037,8 +1044,11 @@ bool VarDecl::isExternC() const {
getStorageClass() != SC_Static) ||
(getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
- for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
- DC = DC->getParent()) {
+ const DeclContext *DC = getDeclContext();
+ if (DC->isFunctionOrMethod())
+ return false;
+
+ for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
return getStorageClass() != SC_Static;
@@ -1046,8 +1056,6 @@ bool VarDecl::isExternC() const {
break;
}
- if (DC->isFunctionOrMethod())
- return false;
}
return false;
@@ -1363,8 +1371,11 @@ bool FunctionDecl::isExternC() const {
if (!Context.getLangOptions().CPlusPlus)
return getStorageClass() != SC_Static && !getAttr<OverloadableAttr>();
- for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
- DC = DC->getParent()) {
+ const DeclContext *DC = getDeclContext();
+ if (DC->isRecord())
+ return false;
+
+ for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
return getStorageClass() != SC_Static &&
@@ -1372,9 +1383,6 @@ bool FunctionDecl::isExternC() const {
break;
}
-
- if (DC->isRecord())
- break;
}
return isMain();
@@ -2018,19 +2026,16 @@ TagDecl* TagDecl::getDefinition() const {
return 0;
}
-void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange) {
- if (Qualifier) {
+void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
+ if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
- getExtInfo()->NNS = Qualifier;
- getExtInfo()->NNSRange = QualifierRange;
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
- assert(QualifierRange.isInvalid());
if (hasExtInfo()) {
getASTContext().Deallocate(getExtInfo());
TypedefDeclOrQualifier = (TypedefDecl*) 0;
@@ -2211,8 +2216,10 @@ NamespaceDecl *NamespaceDecl::getNextNamespace() {
}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T) {
- return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
+ SourceLocation loc,
+ IdentifierInfo *name,
+ QualType type) {
+ return new (C) ImplicitParamDecl(DC, loc, name, type);
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index be379d5..81df00d 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -465,6 +465,22 @@ void Decl::CheckAccessDeclContext() const {
#endif
}
+DeclContext *Decl::getNonClosureContext() {
+ DeclContext *DC = getDeclContext();
+
+ // This is basically "while (DC->isClosure()) DC = DC->getParent();"
+ // except that it's significantly more efficient to cast to a known
+ // decl type and call getDeclContext() than to call getParent().
+ do {
+ if (isa<BlockDecl>(DC)) {
+ DC = cast<BlockDecl>(DC)->getDeclContext();
+ continue;
+ }
+ } while (false);
+
+ assert(!DC->isClosure());
+ return DC;
+}
//===----------------------------------------------------------------------===//
// DeclContext Implementation
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index fba73f5..46768c1 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1267,15 +1267,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation NamespaceLoc,
- SourceRange QualifierRange,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc,
NamedDecl *Used,
DeclContext *CommonAncestor) {
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used))
Used = NS->getOriginalNamespace();
- return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
- Qualifier, IdentLoc, Used, CommonAncestor);
+ return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
+ IdentLoc, Used, CommonAncestor);
}
NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
@@ -1289,14 +1288,13 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- SourceRange QualifierRange,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc,
NamedDecl *Namespace) {
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
Namespace = NS->getOriginalNamespace();
- return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias, QualifierRange,
- Qualifier, IdentLoc, Namespace);
+ return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
+ QualifierLoc, IdentLoc, Namespace);
}
UsingDecl *UsingShadowDecl::getUsingDecl() const {
@@ -1337,35 +1335,31 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
S->UsingOrNextShadow = this;
}
-UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceRange NNR, SourceLocation UL,
- NestedNameSpecifier* TargetNNS,
+UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, NNR, UL, TargetNNS, NameInfo, IsTypeNameArg);
+ return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg);
}
UnresolvedUsingValueDecl *
UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
- SourceRange TargetNNR,
- NestedNameSpecifier *TargetNNS,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo) {
return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
- TargetNNR, TargetNNS, NameInfo);
+ QualifierLoc, NameInfo);
}
UnresolvedUsingTypenameDecl *
UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
SourceLocation TypenameLoc,
- SourceRange TargetNNR,
- NestedNameSpecifier *TargetNNS,
+ NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc,
DeclarationName TargetName) {
return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc,
- TargetNNR, TargetNNS,
- TargetNameLoc,
+ QualifierLoc, TargetNameLoc,
TargetName.getAsIdentifierInfo());
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 77b4257..c6ae128 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -918,20 +918,20 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
- D->getTargetNestedNameDecl()->print(Out, Policy);
+ D->getQualifier()->print(Out, Policy);
Out << D;
}
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
- D->getTargetNestedNameSpecifier()->print(Out, Policy);
+ D->getQualifier()->print(Out, Policy);
Out << D->getDeclName();
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
- D->getTargetNestedNameSpecifier()->print(Out, Policy);
+ D->getQualifier()->print(Out, Policy);
Out << D->getDeclName();
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 391b26a..1c1061b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -836,6 +836,19 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
+SourceRange CallExpr::getSourceRange() const {
+ if (isa<CXXOperatorCallExpr>(this))
+ return cast<CXXOperatorCallExpr>(this)->getSourceRange();
+
+ SourceLocation begin = getCallee()->getLocStart();
+ if (begin.isInvalid() && getNumArgs() > 0)
+ begin = getArg(0)->getLocStart();
+ SourceLocation end = getRParenLoc();
+ if (end.isInvalid() && getNumArgs() > 0)
+ end = getArg(getNumArgs() - 1)->getLocEnd();
+ return SourceRange(begin, end);
+}
+
OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 28ff9fb..4f4a6b4 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -128,10 +128,10 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
}
CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
- Expr *Base, bool isArrow, SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
- TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc,
- SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType)
+ Expr *Base, bool isArrow, SourceLocation OperatorLoc,
+ NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType,
+ SourceLocation ColonColonLoc, SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
FunctionProtoType::ExtProtoInfo())),
@@ -142,15 +142,16 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
/*isValueDependent=*/Base->isValueDependent(),
// ContainsUnexpandedParameterPack
(Base->containsUnexpandedParameterPack() ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()) ||
(ScopeType &&
ScopeType->getType()->containsUnexpandedParameterPack()) ||
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()
->containsUnexpandedParameterPack()))),
Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
- OperatorLoc(OperatorLoc), Qualifier(Qualifier),
- QualifierRange(QualifierRange),
+ OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc),
DestroyedType(DestroyedType) { }
@@ -282,15 +283,16 @@ CXXRecordDecl *OverloadExpr::getNamingClass() const {
// DependentScopeDeclRefExpr
DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args)
: Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary,
true, true,
(NameInfo.containsUnexpandedParameterPack() ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()))),
- NameInfo(NameInfo), QualifierRange(QualifierRange), Qualifier(Qualifier),
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()))),
+ QualifierLoc(QualifierLoc), NameInfo(NameInfo),
HasExplicitTemplateArgs(Args != 0)
{
if (Args) {
@@ -306,16 +308,14 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
DependentScopeDeclRefExpr *
DependentScopeDeclRefExpr::Create(ASTContext &C,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
size += ExplicitTemplateArgumentList::sizeFor(*Args);
void *Mem = C.Allocate(size);
- return new (Mem) DependentScopeDeclRefExpr(C.DependentTy,
- Qualifier, QualifierRange,
+ return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc,
NameInfo, Args);
}
@@ -328,13 +328,16 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size);
DependentScopeDeclRefExpr *E
- = new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(),
+ = new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(),
DeclarationNameInfo(), 0);
E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
return E;
}
SourceRange CXXConstructExpr::getSourceRange() const {
+ if (isa<CXXTemporaryObjectExpr>(this))
+ return cast<CXXTemporaryObjectExpr>(this)->getSourceRange();
+
if (ParenRange.isValid())
return SourceRange(Loc, ParenRange.getEnd());
@@ -397,13 +400,6 @@ CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() {
return ThisArg->getType()->getAsCXXRecordDecl();
}
-SourceRange CXXMemberCallExpr::getSourceRange() const {
- SourceLocation LocStart = getCallee()->getLocStart();
- if (LocStart.isInvalid() && getNumArgs() > 0)
- LocStart = getArg(0)->getLocStart();
- return SourceRange(LocStart, getRParenLoc());
-}
-
//===----------------------------------------------------------------------===//
// Named casts
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 656bb99..3a5eb66 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2926,7 +2926,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
Exp->getOpcode() == BO_Rem) {
// Evaluate gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
- if (LHSResult.Val != 2 && RHSResult.Val != 2) {
+ if (LHSResult.Val == 0 && RHSResult.Val == 0) {
llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx);
if (REval == 0)
return ICEDiag(1, E->getLocStart());
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index d66c374..939ca7a 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -606,6 +606,9 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
case NestedNameSpecifier::Namespace:
mangleName(Qualifier->getAsNamespace());
break;
+ case NestedNameSpecifier::NamespaceAlias:
+ mangleName(Qualifier->getAsNamespaceAlias()->getNamespace());
+ break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *QTy = Qualifier->getAsType();
@@ -1647,8 +1650,11 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
- assert(!D.isNull() && "can't mangle undeduced auto type");
- mangleType(D);
+ // <builtin-type> ::= Da # dependent auto
+ if (D.isNull())
+ Out << "Da";
+ else
+ mangleType(D);
}
void CXXNameMangler::mangleIntegerLiteral(QualType T,
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 650321d..6f1ec05 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -14,8 +14,10 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -46,7 +48,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Identifier);
+ Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
}
@@ -60,19 +62,34 @@ NestedNameSpecifier::Create(const ASTContext &Context,
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Namespace);
+ Mockup.Prefix.setInt(StoredNamespaceOrAlias);
Mockup.Specifier = NS;
return FindOrInsert(Context, Mockup);
}
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ NamespaceAliasDecl *Alias) {
+ assert(Alias && "Namespace alias cannot be NULL");
+ assert((!Prefix ||
+ (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+ "Broken nested name specifier");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(StoredNamespaceOrAlias);
+ Mockup.Specifier = Alias;
+ return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
bool Template, const Type *T) {
assert(T && "Type cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+ Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
Mockup.Specifier = const_cast<Type*>(T);
return FindOrInsert(Context, Mockup);
}
@@ -82,7 +99,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(0);
- Mockup.Prefix.setInt(Identifier);
+ Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
}
@@ -94,6 +111,47 @@ NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
return Context.GlobalNestedNameSpecifier;
}
+NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
+ if (Specifier == 0)
+ return Global;
+
+ switch (Prefix.getInt()) {
+ case StoredIdentifier:
+ return Identifier;
+
+ case StoredNamespaceOrAlias:
+ return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
+ : NamespaceAlias;
+
+ case StoredTypeSpec:
+ return TypeSpec;
+
+ case StoredTypeSpecWithTemplate:
+ return TypeSpecWithTemplate;
+ }
+
+ return Global;
+}
+
+/// \brief Retrieve the namespace stored in this nested name
+/// specifier.
+NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
+ if (Prefix.getInt() == StoredNamespaceOrAlias)
+ return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
+
+ return 0;
+}
+
+/// \brief Retrieve the namespace alias stored in this nested name
+/// specifier.
+NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
+ if (Prefix.getInt() == StoredNamespaceOrAlias)
+ return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
+
+ return 0;
+}
+
+
/// \brief Whether this nested name specifier refers to a dependent
/// type or not.
bool NestedNameSpecifier::isDependent() const {
@@ -103,6 +161,7 @@ bool NestedNameSpecifier::isDependent() const {
return true;
case Namespace:
+ case NamespaceAlias:
case Global:
return false;
@@ -121,6 +180,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
case Namespace:
+ case NamespaceAlias:
case Global:
return false;
@@ -147,7 +207,11 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
break;
case Namespace:
- OS << getAsNamespace()->getIdentifier()->getName();
+ OS << getAsNamespace()->getName();
+ break;
+
+ case NamespaceAlias:
+ OS << getAsNamespaceAlias()->getName();
break;
case Global:
@@ -199,3 +263,111 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
void NestedNameSpecifier::dump(const LangOptions &LO) {
print(llvm::errs(), PrintingPolicy(LO));
}
+
+unsigned
+NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
+ assert(Qualifier && "Expected a non-NULL qualifier");
+
+ // Location of the trailing '::'.
+ unsigned Length = sizeof(unsigned);
+
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // Nothing more to add.
+ break;
+
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ // The location of the identifier or namespace name.
+ Length += sizeof(unsigned);
+ break;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec:
+ // The "void*" that points at the TypeLoc data.
+ // Note: the 'template' keyword is part of the TypeLoc.
+ Length += sizeof(void *);
+ break;
+ }
+
+ return Length;
+}
+
+unsigned
+NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) {
+ unsigned Length = 0;
+ for (; Qualifier; Qualifier = Qualifier->getPrefix())
+ Length += getLocalDataLength(Qualifier);
+ return Length;
+}
+
+namespace {
+ /// \brief Load a (possibly unaligned) source location from a given address
+ /// and offset.
+ SourceLocation LoadSourceLocation(void *Data, unsigned Offset) {
+ unsigned Raw;
+ memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned));
+ return SourceLocation::getFromRawEncoding(Raw);
+ }
+
+ /// \brief Load a (possibly unaligned) pointer from a given address and
+ /// offset.
+ void *LoadPointer(void *Data, unsigned Offset) {
+ void *Result;
+ memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*));
+ return Result;
+ }
+}
+
+SourceRange NestedNameSpecifierLoc::getSourceRange() const {
+ if (!Qualifier)
+ return SourceRange();
+
+ NestedNameSpecifierLoc First = *this;
+ while (NestedNameSpecifierLoc Prefix = First.getPrefix())
+ First = Prefix;
+
+ return SourceRange(First.getLocalSourceRange().getBegin(),
+ getLocalSourceRange().getEnd());
+}
+
+SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
+ if (!Qualifier)
+ return SourceRange();
+
+ unsigned Offset = getDataLength(Qualifier->getPrefix());
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ return LoadSourceLocation(Data, Offset);
+
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ return SourceRange(LoadSourceLocation(Data, Offset),
+ LoadSourceLocation(Data, Offset + sizeof(unsigned)));
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ // The "void*" that points at the TypeLoc data.
+ // Note: the 'template' keyword is part of the TypeLoc.
+ void *TypeData = LoadPointer(Data, Offset);
+ TypeLoc TL(Qualifier->getAsType(), TypeData);
+ return SourceRange(TL.getBeginLoc(),
+ LoadSourceLocation(Data, Offset + sizeof(void*)));
+ }
+ }
+
+ return SourceRange();
+}
+
+TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
+ assert((Qualifier->getKind() == NestedNameSpecifier::TypeSpec ||
+ Qualifier->getKind() == NestedNameSpecifier::TypeSpecWithTemplate) &&
+ "Nested-name-specifier location is not a type");
+
+ // The "void*" that points at the TypeLoc data.
+ unsigned Offset = getDataLength(Qualifier->getPrefix());
+ void *TypeData = LoadPointer(Data, Offset);
+ return TypeLoc(Qualifier->getAsType(), TypeData);
+}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index cf14eba..4ed031f 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -698,6 +698,25 @@ protected:
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ CharUnits getSize() const {
+ assert(Size % Context.getCharWidth() == 0);
+ return Context.toCharUnitsFromBits(Size);
+ }
+ uint64_t getSizeInBits() const { return Size; }
+
+ void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); }
+ void setSize(uint64_t NewSize) { Size = NewSize; }
+
+ CharUnits getDataSize() const {
+ assert(DataSize % Context.getCharWidth() == 0);
+ return Context.toCharUnitsFromBits(DataSize);
+ }
+ uint64_t getDataSizeInBits() const { return DataSize; }
+
+ void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
+ void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
+
+
RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
public:
@@ -796,8 +815,8 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
// Update the size.
- Size += GetVirtualPointersSize(RD);
- DataSize = Size;
+ setSize(getSizeInBits() + GetVirtualPointersSize(RD));
+ setDataSize(getSizeInBits());
CharUnits UnpackedBaseAlign =
Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
@@ -1090,7 +1109,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
if (Base->Class->isEmpty() &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
- Size = std::max(Size, RecordSizeInBits);
+ setSize(std::max(getSizeInBits(), RecordSizeInBits));
return CharUnits::Zero();
}
@@ -1106,7 +1125,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// Round up the current record size to the base's alignment boundary.
uint64_t Offset =
- llvm::RoundUpToAlignment(DataSize, Context.toBits(BaseAlign));
+ llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(BaseAlign));
// Try to place the base.
while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
@@ -1115,11 +1134,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
if (!Base->Class->isEmpty()) {
// Update the data size.
- DataSize = Offset + Context.toBits(Layout.getNonVirtualSize());
+ setDataSize(Offset + Context.toBits(Layout.getNonVirtualSize()));
- Size = std::max(Size, DataSize);
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
} else
- Size = std::max(Size, Offset + Context.toBits(Layout.getSize()));
+ setSize(std::max(getSizeInBits(),
+ Offset + Context.toBits(Layout.getSize())));
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
@@ -1167,7 +1187,8 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- NonVirtualSize = Context.toCharUnitsFromBits(Size);
+ // FIXME: Size isn't always an exact multiple of the char width. Round up?
+ NonVirtualSize = Context.toCharUnitsFromBits(getSizeInBits());
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1211,8 +1232,8 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
- Size = Context.toBits(SL.getDataSize());
- DataSize = Size;
+ setSize(SL.getDataSize());
+ setDataSize(getSizeInBits());
}
InitializeLayout(D);
@@ -1270,20 +1291,20 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
- uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
if (IsUnion) {
- DataSize = std::max(DataSize, FieldSize);
+ setDataSize(std::max(getDataSizeInBits(), FieldSize));
FieldOffset = 0;
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
// for T', with length n bits.
- FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign);
+ FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), TypeAlign);
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
- UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
// Place this field at the current location.
@@ -1293,7 +1314,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
TypeAlign, FieldPacked, D);
// Update the size.
- Size = std::max(Size, DataSize);
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
@@ -1301,7 +1322,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
@@ -1355,16 +1376,16 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
- DataSize = std::max(DataSize, FieldSize);
+ setDataSize(std::max(getDataSizeInBits(), FieldSize));
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
- UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
// Update the size.
- Size = std::max(Size, DataSize);
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign),
@@ -1377,14 +1398,14 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
return;
}
- uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
// Reset the unfilled bits.
UnfilledBitsInLastByte = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
CharUnits FieldOffset =
- IsUnion ? CharUnits::Zero() : Context.toCharUnitsFromBits(DataSize);
+ IsUnion ? CharUnits::Zero() : getDataSize();
CharUnits FieldSize;
CharUnits FieldAlign;
@@ -1464,12 +1485,12 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
// Reserve space for this field.
uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
- Size = std::max(Size, FieldSizeInBits);
+ setSize(std::max(getSizeInBits(), FieldSizeInBits));
else
- Size = Context.toBits(FieldOffset) + FieldSizeInBits;
+ setSize(Context.toBits(FieldOffset) + FieldSizeInBits);
// Update the data size.
- DataSize = Size;
+ setDataSize(getSizeInBits());
// Remember max struct/class alignment.
UpdateAlignment(FieldAlign, UnpackedFieldAlign);
@@ -1477,29 +1498,30 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// In C++, records cannot be of size 0.
- if (Context.getLangOptions().CPlusPlus && Size == 0) {
+ if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
// Compatibility with gcc requires a class (pod or non-pod)
// which is not empty but of size 0; such as having fields of
// array of zero-length, remains of Size 0
if (RD->isEmpty())
- Size = 8;
+ setSize(8);
}
else
- Size = 8;
+ setSize(8);
}
// Finally, round the size of the record up to the alignment of the
// record itself.
- uint64_t UnpaddedSize = Size - UnfilledBitsInLastByte;
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
uint64_t UnpackedSize =
- llvm::RoundUpToAlignment(Size, Context.toBits(UnpackedAlignment));
- Size = llvm::RoundUpToAlignment(Size, Context.toBits(Alignment));
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.toBits(UnpackedAlignment));
+ setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
unsigned CharBitNum = Context.Target.getCharWidth();
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
// Warn if padding was introduced to the struct/class/union.
- if (Size > UnpaddedSize) {
- unsigned PadSize = Size - UnpaddedSize;
+ if (getSizeInBits() > UnpaddedSize) {
+ unsigned PadSize = getSizeInBits() - UnpaddedSize;
bool InBits = true;
if (PadSize % CharBitNum == 0) {
PadSize = PadSize / CharBitNum;
@@ -1513,7 +1535,8 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Warn if we packed it unnecessarily. If the alignment is 1 byte don't
// bother since there won't be alignment issues.
- if (Packed && UnpackedAlignment > CharUnits::One() && Size == UnpackedSize)
+ if (Packed && UnpackedAlignment > CharUnits::One() &&
+ getSizeInBits() == UnpackedSize)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 7e73f02..8a80275 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -218,6 +218,10 @@ unsigned AsmStmt::getNumPlusOperands() const {
Expr *AsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
+void AsmStmt::setInputExpr(unsigned i, Expr *E) {
+ Exprs[i + NumOutputs] = E;
+}
+
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 846bd4c..5c7dbb3 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -279,8 +279,8 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// print using decl (e.g. "using std::string;")
const char *tn = UD->isTypeName() ? "typename " : "";
OS << '"' << UD->getDeclKindName() << tn;
- UD->getTargetNestedNameDecl()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOptions()));
+ UD->getQualifier()->print(OS,
+ PrintingPolicy(UD->getASTContext().getLangOptions()));
OS << ";\"";
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << LD->getNameAsString();
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 5ab5f46..1764f4a 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -24,8 +24,6 @@
#include "llvm/ADT/FoldingSet.h"
#include <algorithm>
#include <cctype>
-#include <iomanip>
-#include <sstream>
using namespace clang;
@@ -42,17 +40,11 @@ static void printIntegral(const TemplateArgument &TemplArg,
if (T->isBooleanType()) {
Out << (Val->getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
- char Ch = Val->getSExtValue();
- if (std::isprint(Ch)) {
- Out << "'";
- if (Ch == '\'' || Ch == '\\')
- Out << '\\';
- Out << Ch << "'";
- } else {
- std::ostringstream Str;
- Str << std::setw(2) << std::setfill('0') << std::hex << (int)Ch;
- Out << "'\\x" << Str.str() << "'";
- }
+ const unsigned char Ch = Val->getZExtValue();
+ const std::string Str(1, Ch);
+ Out << ((Ch == '\'') ? "'\\" : "'");
+ Out.write_escaped(Str, /*UseHexEscapes=*/ true);
+ Out << "'";
} else {
Out << Val->toString(10);
}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 5233d3b..62097ef 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -19,8 +19,10 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/ErrorHandling.h"
@@ -86,6 +88,30 @@ CFG *AnalysisContext::getUnoptimizedCFG() {
return completeCFG;
}
+CFGStmtMap *AnalysisContext::getCFGStmtMap() {
+ if (cfgStmtMap)
+ return cfgStmtMap;
+
+ if (CFG *c = getCFG()) {
+ cfgStmtMap = CFGStmtMap::Build(c, &getParentMap());
+ return cfgStmtMap;
+ }
+
+ return 0;
+}
+
+CFGReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
+ if (CFA)
+ return CFA;
+
+ if (CFG *c = getCFG()) {
+ CFA = new CFGReachabilityAnalysis(*c);
+ return CFA;
+ }
+
+ return 0;
+}
+
void AnalysisContext::dumpCFG() {
getCFG()->dump(getASTContext().getLangOptions());
}
@@ -346,10 +372,12 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
AnalysisContext::~AnalysisContext() {
delete cfg;
delete completeCFG;
+ delete cfgStmtMap;
delete liveness;
delete relaxedLiveness;
delete PM;
delete PCA;
+ delete CFA;
delete ReferencedBlockVars;
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index a0ec5fe..cc6e9c5 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/CharUnits.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
@@ -413,9 +414,16 @@ private:
Expr::EvalResult Result;
if (!S->isTypeDependent() && !S->isValueDependent() &&
- S->Evaluate(Result, *Context) && Result.Val.isInt())
- return Result.Val.getInt().getBoolValue();
-
+ S->Evaluate(Result, *Context)) {
+ if (Result.Val.isInt())
+ return Result.Val.getInt().getBoolValue();
+ if (Result.Val.isLValue()) {
+ Expr *e = Result.Val.getLValueBase();
+ const CharUnits &c = Result.Val.getLValueOffset();
+ if (!e && c.isZero())
+ return false;
+ }
+ }
return TryResult();
}
};
@@ -928,11 +936,13 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
/// VisitChildren - Visit the children of a Stmt.
CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) {
- CFGBlock *B = Block;
- for (Stmt::child_range I = Terminator->children(); I; ++I) {
- if (*I) B = Visit(*I);
- }
- return B;
+ CFGBlock *lastBlock = Block;
+ for (Stmt::child_range I = Terminator->children(); I; ++I)
+ if (Stmt *child = *I)
+ if (CFGBlock *b = Visit(child))
+ lastBlock = b;
+
+ return lastBlock;
}
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
@@ -1207,6 +1217,8 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
return 0;
Block = NULL;
}
+ else
+ LHSBlock = ConfluenceBlock;
// Create the block for the RHS expression.
Succ = ConfluenceBlock;
@@ -1219,23 +1231,23 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
- if (LHSBlock)
- addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
+ addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
Block->setTerminator(C);
Expr *condExpr = C->getCond();
- CFGBlock *result = 0;
-
- // Run the condition expression if it's not trivially expressed in
- // terms of the opaque value (or if there is no opaque value).
- if (condExpr != opaqueValue) result = addStmt(condExpr);
-
- // Before that, run the common subexpression if there was one.
- // At least one of this or the above will be run.
- if (opaqueValue) result = addStmt(BCO->getCommon());
+ if (opaqueValue) {
+ // Run the condition expression if it's not trivially expressed in
+ // terms of the opaque value (or if there is no opaque value).
+ if (condExpr != opaqueValue)
+ addStmt(condExpr);
- return result;
+ // Before that, run the common subexpression if there was one.
+ // At least one of this or the above will be run.
+ return addStmt(BCO->getCommon());
+ }
+
+ return addStmt(condExpr);
}
CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
@@ -1819,6 +1831,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
if (badCFG)
return 0;
LoopSuccessor = Block;
+ Block = 0;
} else
LoopSuccessor = Succ;
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
new file mode 100644
index 0000000..7786584
--- /dev/null
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -0,0 +1,76 @@
+//==- CFGReachabilityAnalysis.cpp - Basic reachability analysis --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a flow-sensitive, (mostly) path-insensitive reachability
+// analysis based on Clang's CFGs. Clients can query if a given basic block
+// is reachable within the CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/CFG.h"
+
+using namespace clang;
+
+CFGReachabilityAnalysis::CFGReachabilityAnalysis(const CFG &cfg)
+ : analyzed(cfg.getNumBlockIDs(), false) {}
+
+bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
+ const CFGBlock *Dst) {
+
+ const unsigned DstBlockID = Dst->getBlockID();
+
+ // If we haven't analyzed the destination node, run the analysis now
+ if (!analyzed[DstBlockID]) {
+ mapReachability(Dst);
+ analyzed[DstBlockID] = true;
+ }
+
+ // Return the cached result
+ return reachable[DstBlockID][Src->getBlockID()];
+}
+
+// Maps reachability to a common node by walking the predecessors of the
+// destination node.
+void CFGReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
+ llvm::SmallVector<const CFGBlock *, 11> worklist;
+ llvm::BitVector visited(analyzed.size());
+
+ ReachableSet &DstReachability = reachable[Dst->getBlockID()];
+ DstReachability.resize(analyzed.size(), false);
+
+ // Start searching from the destination node, since we commonly will perform
+ // multiple queries relating to a destination node.
+ worklist.push_back(Dst);
+ bool firstRun = true;
+
+ while (!worklist.empty()) {
+ const CFGBlock *block = worklist.back();
+ worklist.pop_back();
+
+ if (visited[block->getBlockID()])
+ continue;
+ visited[block->getBlockID()] = true;
+
+ // Update reachability information for this node -> Dst
+ if (!firstRun) {
+ // Don't insert Dst -> Dst unless it was a predecessor of itself
+ DstReachability[block->getBlockID()] = true;
+ }
+ else
+ firstRun = false;
+
+ // Add the predecessors to the worklist.
+ for (CFGBlock::const_pred_iterator i = block->pred_begin(),
+ e = block->pred_end(); i != e; ++i) {
+ worklist.push_back(*i);
+ }
+ }
+}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 0912f3c..84b211f 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_USED_LIBS clangBasic clangAST clangIndex)
add_clang_library(clangAnalysis
AnalysisContext.cpp
CFG.cpp
+ CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
CocoaConventions.cpp
FormatString.cpp
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 8725e7f..553e4c9 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -288,14 +288,15 @@ const char *DiagnosticIDs::getDescription(unsigned DiagID) const {
/// the DiagnosticClient.
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
- const Diagnostic &Diag) const {
+ const Diagnostic &Diag,
+ diag::Mapping *mapping) const {
// Handle custom diagnostics, which cannot be mapped.
if (DiagID >= diag::DIAG_UPPER_LIMIT)
return CustomDiagInfo->getLevel(DiagID);
unsigned DiagClass = getBuiltinDiagClass(DiagID);
assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
- return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
+ return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag, mapping);
}
/// \brief Based on the way the client configured the Diagnostic
@@ -307,7 +308,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
SourceLocation Loc,
- const Diagnostic &Diag) const {
+ const Diagnostic &Diag,
+ diag::Mapping *mapping) const {
// Specific non-error diagnostics may be mapped to various levels from ignored
// to error. Errors can only be mapped to fatal.
DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
@@ -323,6 +325,9 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
MappingInfo = GetDefaultDiagMapping(DiagID);
Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
}
+
+ if (mapping)
+ *mapping = (diag::Mapping) (MappingInfo & 7);
switch (MappingInfo & 7) {
default: assert(0 && "Unknown mapping!");
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 044c88d..e2783ba 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -823,6 +823,12 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
+unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
+ if (isInvalid(Loc, Invalid)) return 0;
+ return getPresumedLoc(Loc).getColumn();
+}
+
static LLVM_ATTRIBUTE_NOINLINE void
ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
@@ -985,17 +991,22 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
return LineNo;
}
+unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
+ if (isInvalid(Loc, Invalid)) return 0;
+ std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
+ return getLineNumber(LocInfo.first, LocInfo.second);
+}
unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
-unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
+unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
- std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
- return getLineNumber(LocInfo.first, LocInfo.second);
+ return getPresumedLoc(Loc).getLine();
}
/// getFileCharacteristic - return the file characteristic of the specified
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a8198e4..55321f24 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -152,6 +152,7 @@ public:
DarwinTargetInfo(const std::string& triple) :
OSTargetInfo<Target>(triple) {
this->TLSSupported = llvm::Triple(triple).getDarwinMajorNumber() > 10;
+ this->MCountName = "\01mcount";
}
virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index a35648d..9587de2 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -895,12 +895,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
QualType selfTy = getContext().VoidPtrTy;
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- // FIXME: this leaks, and we only need it very temporarily.
- ImplicitParamDecl *selfDecl =
- ImplicitParamDecl::Create(getContext(),
- const_cast<BlockDecl*>(blockDecl),
- SourceLocation(), II, selfTy);
- args.push_back(std::make_pair(selfDecl, selfTy));
+ ImplicitParamDecl selfDecl(const_cast<BlockDecl*>(blockDecl),
+ SourceLocation(), II, selfTy);
+ args.push_back(std::make_pair(&selfDecl, selfTy));
// Now add the rest of the parameters.
for (BlockDecl::param_const_iterator i = blockDecl->param_begin(),
@@ -928,12 +925,11 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
blockInfo.getBlockExpr()->getBody()->getLocEnd());
CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl
- // Okay. Undo some of what StartFunction did. We really don't need
- // an alloca for the block address; in theory we could remove it,
- // but that might do unpleasant things to debug info.
- llvm::AllocaInst *blockAddrAlloca
- = cast<llvm::AllocaInst>(LocalDeclMap[selfDecl]);
- llvm::Value *blockAddr = Builder.CreateLoad(blockAddrAlloca);
+ // Okay. Undo some of what StartFunction did.
+
+ // Pull the 'self' reference out of the local decl map.
+ llvm::Value *blockAddr = LocalDeclMap[&selfDecl];
+ LocalDeclMap.erase(&selfDecl);
BlockPointer = Builder.CreateBitCast(blockAddr,
blockInfo.StructureType->getPointerTo(),
"block");
@@ -1010,7 +1006,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
continue;
}
- DI->EmitDeclareOfBlockDeclRefVariable(variable, blockAddrAlloca,
+ DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointer,
Builder, blockInfo);
}
}
@@ -1376,10 +1372,9 @@ llvm::Constant *CodeGenModule::BuildbyrefCopyHelper(const llvm::Type *T,
BlockFieldFlags flags,
unsigned align,
const VarDecl *var) {
- // All alignments below that of pointer alignment collapse down to just
- // pointer alignment, as we always have at least that much alignment to begin
- // with.
- align /= unsigned(getTarget().getPointerAlign(0) / 8);
+ // All alignments below pointer alignment are bumped up, as we
+ // always have at least that much alignment to begin with.
+ if (align < PointerAlignInBytes) align = PointerAlignInBytes;
// As an optimization, we only generate a single function of each kind we
// might need. We need a different one for each alignment and for each
@@ -1396,10 +1391,9 @@ llvm::Constant *CodeGenModule::BuildbyrefDestroyHelper(const llvm::Type *T,
BlockFieldFlags flags,
unsigned align,
const VarDecl *var) {
- // All alignments below that of pointer alignment collpase down to just
- // pointer alignment, as we always have at least that much alignment to begin
- // with.
- align /= unsigned(getTarget().getPointerAlign(0) / 8);
+ // All alignments below pointer alignment are bumped up, as we
+ // always have at least that much alignment to begin with.
+ if (align < PointerAlignInBytes) align = PointerAlignInBytes;
// As an optimization, we only generate a single function of each kind we
// might need. We need a different one for each alignment and for each
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index bee729d..0bc8bca 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -177,7 +177,6 @@ public:
const BlockExpr *Block;
CharUnits BlockSize;
CharUnits BlockAlign;
- llvm::SmallVector<const Expr*, 8> BlockLayout;
const Capture &getCapture(const VarDecl *var) const {
llvm::DenseMap<const VarDecl*, Capture>::const_iterator
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 8e88beb..cd28bbe 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Frontend/CodeGenOptions.h"
using namespace clang;
using namespace CodeGen;
@@ -1140,6 +1141,16 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI && CGM.getCodeGenOpts().LimitDebugInfo) {
+ // If debug info for this class has been emitted then this is the right time
+ // to do so.
+ const CXXRecordDecl *Parent = D->getParent();
+ DI->getOrCreateRecordType(CGM.getContext().getTypeDeclType(Parent),
+ Parent->getLocation());
+ }
+
if (D->isTrivial()) {
if (ArgBeg == ArgEnd) {
// Trivial default constructor, no codegen required.
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 374ede8..1d7901a 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -876,7 +876,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
///
/// As a side-effect, this method clears the insertion point.
void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
- assert(Dest.getScopeDepth().encloses(EHStack.getInnermostNormalCleanup())
+ assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
&& "stale jump destination");
if (!HaveInsertPoint())
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 469b460..dfd9f56 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -156,14 +156,14 @@ CGDebugInfo::getClassName(RecordDecl *RD) {
llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
if (!Loc.isValid())
// If Location is not valid then use main input file.
- return DBuilder.CreateFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid() || llvm::StringRef(PLoc.getFilename()).empty())
// If the location is not valid then use main input file.
- return DBuilder.CreateFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
// Cache the results.
const char *fname = PLoc.getFilename();
@@ -176,7 +176,7 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
return llvm::DIFile(cast<llvm::MDNode>(it->second));
}
- llvm::DIFile F = DBuilder.CreateFile(PLoc.getFilename(), getCurrentDirname());
+ llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname());
DIFileCache[fname] = F;
return F;
@@ -185,7 +185,7 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
/// getOrCreateMainFile - Get the file info for main compile unit.
llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
- return DBuilder.CreateFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
}
/// getLineNumber - Get line number for the location. If location is invalid
@@ -264,7 +264,7 @@ void CGDebugInfo::CreateCompileUnit() {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- DBuilder.CreateCompileUnit(
+ DBuilder.createCompileUnit(
LangTag, Filename, getCurrentDirname(),
Producer,
LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
@@ -282,7 +282,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- return DBuilder.CreateStructType(TheCU, "objc_class",
+ return DBuilder.createStructType(TheCU, "objc_class",
getOrCreateMainFile(), 0, 0, 0,
llvm::DIDescriptor::FlagFwdDecl,
llvm::DIArray());
@@ -293,28 +293,28 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
// } *id;
llvm::DIType OCTy =
- DBuilder.CreateStructType(TheCU, "objc_class",
+ DBuilder.createStructType(TheCU, "objc_class",
getOrCreateMainFile(), 0, 0, 0,
llvm::DIDescriptor::FlagFwdDecl,
llvm::DIArray());
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
- llvm::DIType ISATy = DBuilder.CreatePointerType(OCTy, Size);
+ llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size);
llvm::SmallVector<llvm::Value *, 16> EltTys;
llvm::DIType FieldTy =
- DBuilder.CreateMemberType("isa", getOrCreateMainFile(),
+ DBuilder.createMemberType("isa", getOrCreateMainFile(),
0,Size, 0, 0, 0, ISATy);
EltTys.push_back(FieldTy);
llvm::DIArray Elements =
- DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
- return DBuilder.CreateStructType(TheCU, "objc_object",
+ return DBuilder.createStructType(TheCU, "objc_object",
getOrCreateMainFile(),
0, 0, 0, 0, Elements);
}
case BuiltinType::ObjCSel: {
- return DBuilder.CreateStructType(TheCU, "objc_selector",
+ return DBuilder.createStructType(TheCU, "objc_selector",
getOrCreateMainFile(), 0, 0, 0,
llvm::DIDescriptor::FlagFwdDecl,
llvm::DIArray());
@@ -350,7 +350,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
uint64_t Size = CGM.getContext().getTypeSize(BT);
uint64_t Align = CGM.getContext().getTypeAlign(BT);
llvm::DIType DbgTy =
- DBuilder.CreateBasicType(BTName, Size, Align, Encoding);
+ DBuilder.createBasicType(BTName, Size, Align, Encoding);
return DbgTy;
}
@@ -363,7 +363,7 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIType DbgTy =
- DBuilder.CreateBasicType("complex", Size, Align, Encoding);
+ DBuilder.createBasicType("complex", Size, Align, Encoding);
return DbgTy;
}
@@ -399,7 +399,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// No need to fill in the Name, Line, Size, Alignment, Offset in case of
// CVR derived types.
- llvm::DIType DbgTy = DBuilder.CreateQualifiedType(Tag, FromTy);
+ llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy);
return DbgTy;
}
@@ -430,19 +430,19 @@ llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
llvm::DIDescriptor FDContext =
- getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()));
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
if (RD->isStruct())
- return DBuilder.CreateStructType(FDContext, RD->getName(), DefUnit,
+ return DBuilder.createStructType(FDContext, RD->getName(), DefUnit,
Line, 0, 0, llvm::DIType::FlagFwdDecl,
llvm::DIArray());
else if (RD->isUnion())
- return DBuilder.CreateUnionType(FDContext, RD->getName(), DefUnit,
+ return DBuilder.createUnionType(FDContext, RD->getName(), DefUnit,
Line, 0, 0, llvm::DIType::FlagFwdDecl,
llvm::DIArray());
else {
assert(RD->isClass() && "Unknown RecordType!");
- return DBuilder.CreateClassType(FDContext, RD->getName(), DefUnit,
+ return DBuilder.createClassType(FDContext, RD->getName(), DefUnit,
Line, 0, 0, 0, llvm::DIType::FlagFwdDecl,
llvm::DIType(), llvm::DIArray());
}
@@ -457,7 +457,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
llvm::DIFile Unit) {
if (Tag == llvm::dwarf::DW_TAG_reference_type)
- return DBuilder.CreateReferenceType(CreatePointeeType(PointeeTy, Unit));
+ return DBuilder.createReferenceType(CreatePointeeType(PointeeTy, Unit));
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
@@ -467,7 +467,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return
- DBuilder.CreatePointerType(CreatePointeeType(PointeeTy, Unit), Size, Align);
+ DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), Size, Align);
}
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
@@ -488,20 +488,20 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
- Elements = DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
EltTys.clear();
unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
unsigned LineNo = getLineNumber(CurLoc);
- EltTy = DBuilder.CreateStructType(Unit, "__block_descriptor",
+ EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
Unit, LineNo, FieldOffset, 0,
Flags, Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
- DescTy = DBuilder.CreatePointerType(EltTy, Size);
+ DescTy = DBuilder.createPointerType(EltTy, Size);
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
@@ -516,20 +516,20 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldTy = DescTy;
FieldSize = CGM.getContext().getTypeSize(Ty);
FieldAlign = CGM.getContext().getTypeAlign(Ty);
- FieldTy = DBuilder.CreateMemberType("__descriptor", Unit,
+ FieldTy = DBuilder.createMemberType("__descriptor", Unit,
LineNo, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- Elements = DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
- EltTy = DBuilder.CreateStructType(Unit, "__block_literal_generic",
+ EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
Unit, LineNo, FieldOffset, 0,
Flags, Elements);
BlockLiteralGenericSet = true;
- BlockLiteralGeneric = DBuilder.CreatePointerType(EltTy, Size);
+ BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
return BlockLiteralGeneric;
}
@@ -543,7 +543,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
- llvm::DIType DbgTy = DBuilder.CreateTypedef(Src, Ty->getDecl()->getName(),
+ llvm::DIType DbgTy = DBuilder.createTypedef(Src, Ty->getDecl()->getName(),
Unit, Line);
return DbgTy;
}
@@ -558,66 +558,76 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
// Set up remainder of arguments if there is a prototype.
// FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'!
if (isa<FunctionNoProtoType>(Ty))
- EltTys.push_back(DBuilder.CreateUnspecifiedParameter());
+ EltTys.push_back(DBuilder.createUnspecifiedParameter());
else if (const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(Ty)) {
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
EltTys.push_back(getOrCreateType(FTP->getArgType(i), Unit));
}
llvm::DIArray EltTypeArray =
- DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
- llvm::DIType DbgTy = DBuilder.CreateSubroutineType(Unit, EltTypeArray);
+ llvm::DIType DbgTy = DBuilder.createSubroutineType(Unit, EltTypeArray);
return DbgTy;
}
+llvm::DIType CGDebugInfo::createFieldType(llvm::StringRef name,
+ QualType type,
+ Expr *bitWidth,
+ SourceLocation loc,
+ AccessSpecifier AS,
+ uint64_t offsetInBits,
+ llvm::DIFile tunit) {
+ llvm::DIType debugType = getOrCreateType(type, tunit);
+
+ // Get the location for the field.
+ llvm::DIFile file = getOrCreateFile(loc);
+ unsigned line = getLineNumber(loc);
+
+ uint64_t sizeInBits = 0;
+ unsigned alignInBits = 0;
+ if (!type->isIncompleteArrayType()) {
+ llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
+
+ if (bitWidth)
+ sizeInBits = bitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ }
+
+ unsigned flags = 0;
+ if (AS == clang::AS_private)
+ flags |= llvm::DIDescriptor::FlagPrivate;
+ else if (AS == clang::AS_protected)
+ flags |= llvm::DIDescriptor::FlagProtected;
+
+ return DBuilder.createMemberType(name, file, line, sizeInBits, alignInBits,
+ offsetInBits, flags, debugType);
+}
+
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
-CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit,
- llvm::SmallVectorImpl<llvm::Value *> &EltTys) {
- unsigned FieldNo = 0;
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end();
- I != E; ++I, ++FieldNo) {
- FieldDecl *Field = *I;
- llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- llvm::StringRef FieldName = Field->getName();
-
- // Ignore unnamed fields. Do not ignore unnamed records.
- if (FieldName.empty() && !isa<RecordType>(Field->getType()))
+CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
+ llvm::SmallVectorImpl<llvm::Value *> &elements) {
+ unsigned fieldNo = 0;
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
+ for (RecordDecl::field_iterator I = record->field_begin(),
+ E = record->field_end();
+ I != E; ++I, ++fieldNo) {
+ FieldDecl *field = *I;
+
+ llvm::StringRef name = field->getName();
+ QualType type = field->getType();
+
+ // Ignore unnamed fields unless they're anonymous structs/unions.
+ if (name.empty() && !type->isRecordType())
continue;
- // Get the location for the field.
- llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation());
- unsigned FieldLine = getLineNumber(Field->getLocation());
- QualType FType = Field->getType();
- uint64_t FieldSize = 0;
- unsigned FieldAlign = 0;
- if (!FType->isIncompleteArrayType()) {
-
- // Bit size, align and offset of the type.
- FieldSize = CGM.getContext().getTypeSize(FType);
- Expr *BitWidth = Field->getBitWidth();
- if (BitWidth)
- FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- }
+ llvm::DIType fieldType
+ = createFieldType(name, type, field->getBitWidth(),
+ field->getLocation(), field->getAccess(),
+ layout.getFieldOffset(fieldNo), tunit);
- uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
-
- unsigned Flags = 0;
- AccessSpecifier Access = I->getAccess();
- if (Access == clang::AS_private)
- Flags |= llvm::DIDescriptor::FlagPrivate;
- else if (Access == clang::AS_protected)
- Flags |= llvm::DIDescriptor::FlagProtected;
-
- FieldTy = DBuilder.CreateMemberType(FieldName, FieldDefUnit,
- FieldLine, FieldSize, FieldAlign,
- FieldOffset, Flags, FieldTy);
- EltTys.push_back(FieldTy);
+ elements.push_back(fieldType);
}
}
@@ -649,7 +659,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
QualType ThisPtr =
Context.getPointerType(Context.getTagDeclType(Method->getParent()));
llvm::DIType ThisPtrType =
- DBuilder.CreateArtificialType(getOrCreateType(ThisPtr, Unit));
+ DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit));
TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
Elts.push_back(ThisPtrType);
@@ -660,9 +670,9 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
Elts.push_back(Args.getElement(i));
llvm::DIArray EltTypeArray =
- DBuilder.GetOrCreateArray(Elts.data(), Elts.size());
+ DBuilder.getOrCreateArray(Elts.data(), Elts.size());
- return DBuilder.CreateSubroutineType(Unit, EltTypeArray);
+ return DBuilder.createSubroutineType(Unit, EltTypeArray);
}
/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
@@ -736,7 +746,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
Flags |= llvm::DIDescriptor::FlagPrototyped;
llvm::DISubprogram SP =
- DBuilder.CreateMethod(RecordTy , MethodName, MethodLinkageName,
+ DBuilder.createMethod(RecordTy , MethodName, MethodLinkageName,
MethodDefUnit, MethodLine,
MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/ false,
@@ -780,7 +790,7 @@ CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
BE = RD->friend_end(); BI != BE; ++BI) {
if (TypeSourceInfo *TInfo = (*BI)->getFriendType())
- EltTys.push_back(DBuilder.CreateFriend(RecordTy,
+ EltTys.push_back(DBuilder.createFriend(RecordTy,
getOrCreateType(TInfo->getType(),
Unit)));
}
@@ -818,7 +828,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
BFlags |= llvm::DIDescriptor::FlagProtected;
llvm::DIType DTy =
- DBuilder.CreateInheritance(RecordTy,
+ DBuilder.createInheritance(RecordTy,
getOrCreateType(BI->getType(), Unit),
BaseOffset, BFlags);
EltTys.push_back(DTy);
@@ -834,12 +844,12 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
/* Function type */
llvm::Value *STy = getOrCreateType(Context.IntTy, Unit);
- llvm::DIArray SElements = DBuilder.GetOrCreateArray(&STy, 1);
- llvm::DIType SubTy = DBuilder.CreateSubroutineType(Unit, SElements);
+ llvm::DIArray SElements = DBuilder.getOrCreateArray(&STy, 1);
+ llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
- llvm::DIType vtbl_ptr_type = DBuilder.CreatePointerType(SubTy, Size, 0,
+ llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0,
"__vtbl_ptr_type");
- VTablePtrType = DBuilder.CreatePointerType(vtbl_ptr_type, Size);
+ VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
return VTablePtrType;
}
@@ -872,7 +882,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
- = DBuilder.CreateMemberType(getVTableName(RD), Unit,
+ = DBuilder.createMemberType(getVTableName(RD), Unit,
0, Size, 0, 0, 0,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
@@ -882,7 +892,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
- DBuilder.RetainType(T);
+ DBuilder.retainType(T);
return T;
}
@@ -902,13 +912,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DIDescriptor FDContext =
- getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()));
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!RD->getDefinition()) {
llvm::DIType FwdDecl =
- DBuilder.CreateStructType(FDContext, RD->getName(),
+ DBuilder.createStructType(FDContext, RD->getName(),
DefUnit, Line, 0, 0,
llvm::DIDescriptor::FlagFwdDecl,
llvm::DIArray());
@@ -916,7 +926,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
return FwdDecl;
}
- llvm::DIType FwdDecl = DBuilder.CreateTemporaryType(DefUnit);
+ llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
llvm::MDNode *MN = FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
@@ -952,7 +962,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
// Do not use DIGlobalVariable for enums.
if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
- DBuilder.CreateStaticVariable(FwdDecl, VName, VName, VUnit,
+ DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
getLineNumber(V->getLocation()),
VTy, true, CI);
}
@@ -973,13 +983,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
if (TA.getKind() == TemplateArgument::Type) {
llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
llvm::DITemplateTypeParameter TTP =
- DBuilder.CreateTemplateTypeParameter(TheCU, TTy.getName(), TTy);
+ DBuilder.createTemplateTypeParameter(TheCU, TTy.getName(), TTy);
TemplateParams.push_back(TTP);
} else if (TA.getKind() == TemplateArgument::Integral) {
llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
// FIXME: Get parameter name, instead of parameter type name.
llvm::DITemplateValueParameter TVP =
- DBuilder.CreateTemplateValueParameter(TheCU, TTy.getName(), TTy,
+ DBuilder.createTemplateValueParameter(TheCU, TTy.getName(), TTy,
TA.getAsIntegral()->getZExtValue());
TemplateParams.push_back(TVP);
}
@@ -994,19 +1004,19 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RegionMap.erase(RI);
llvm::DIDescriptor RDContext =
- getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()));
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
llvm::StringRef RDName = RD->getName();
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIArray Elements =
- DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
llvm::MDNode *RealDecl = NULL;
if (RD->isStruct())
- RealDecl = DBuilder.CreateStructType(RDContext, RDName, DefUnit, Line,
+ RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, Elements);
else if (RD->isUnion())
- RealDecl = DBuilder.CreateUnionType(RDContext, RDName, DefUnit, Line,
+ RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, Elements);
else {
assert(RD->isClass() && "Unknown RecordType!");
@@ -1030,8 +1040,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
else if (CXXDecl->isDynamicClass())
ContainingType = FwdDecl;
llvm::DIArray TParamsArray =
- DBuilder.GetOrCreateArray(TemplateParams.data(), TemplateParams.size());
- RealDecl = DBuilder.CreateClassType(RDContext, RDName, DefUnit, Line,
+ DBuilder.getOrCreateArray(TemplateParams.data(), TemplateParams.size());
+ RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, 0, llvm::DIType(),
Elements, ContainingType,
TParamsArray);
@@ -1067,7 +1077,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// debug type.
if (ID->isForwardDecl()) {
llvm::DIType FwdDecl =
- DBuilder.CreateStructType(Unit, ID->getName(),
+ DBuilder.createStructType(Unit, ID->getName(),
DefUnit, Line, 0, 0, 0,
llvm::DIArray(), RuntimeLang);
return FwdDecl;
@@ -1079,7 +1089,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// its members. Finally, we create a descriptor for the complete type (which
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DIType FwdDecl = DBuilder.CreateTemporaryType(DefUnit);
+ llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
llvm::MDNode *MN = FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
@@ -1101,7 +1111,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
return llvm::DIType();
llvm::DIType InhTag =
- DBuilder.CreateInheritance(FwdDecl, SClassTy, 0, 0);
+ DBuilder.createInheritance(FwdDecl, SClassTy, 0, 0);
EltTys.push_back(InhTag);
}
@@ -1146,14 +1156,14 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
- FieldTy = DBuilder.CreateMemberType(FieldName, FieldDefUnit,
+ FieldTy = DBuilder.createMemberType(FieldName, FieldDefUnit,
FieldLine, FieldSize, FieldAlign,
FieldOffset, Flags, FieldTy);
EltTys.push_back(FieldTy);
}
llvm::DIArray Elements =
- DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
RegionStack.pop_back();
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
@@ -1166,7 +1176,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIType RealDecl =
- DBuilder.CreateStructType(Unit, ID->getName(), DefUnit,
+ DBuilder.createStructType(Unit, ID->getName(), DefUnit,
Line, Size, Align, 0,
Elements, RuntimeLang);
@@ -1194,14 +1204,14 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty,
if (NumElems > 0)
--NumElems;
- llvm::Value *Subscript = DBuilder.GetOrCreateSubrange(0, NumElems);
- llvm::DIArray SubscriptArray = DBuilder.GetOrCreateArray(&Subscript, 1);
+ llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, NumElems);
+ llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(&Subscript, 1);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return
- DBuilder.CreateVectorType(Size, Align, ElementTy, SubscriptArray);
+ DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
}
llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
@@ -1238,16 +1248,16 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
if (CAT->getSize().getZExtValue())
Upper = CAT->getSize().getZExtValue() - 1;
// FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.GetOrCreateSubrange(0, Upper));
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Upper));
EltTy = Ty->getElementType();
}
}
llvm::DIArray SubscriptArray =
- DBuilder.GetOrCreateArray(Subscripts.data(), Subscripts.size());
+ DBuilder.getOrCreateArray(Subscripts.data(), Subscripts.size());
llvm::DIType DbgTy =
- DBuilder.CreateArrayType(Size, Align, getOrCreateType(EltTy, Unit),
+ DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
SubscriptArray);
return DbgTy;
}
@@ -1283,21 +1293,21 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
// FIXME: This should probably be a function type instead.
ElementTypes[0] =
- DBuilder.CreateMemberType("ptr", U, 0,
+ DBuilder.createMemberType("ptr", U, 0,
Info.first, Info.second, FieldOffset, 0,
PointerDiffDITy);
FieldOffset += Info.first;
ElementTypes[1] =
- DBuilder.CreateMemberType("ptr", U, 0,
+ DBuilder.createMemberType("ptr", U, 0,
Info.first, Info.second, FieldOffset, 0,
PointerDiffDITy);
llvm::DIArray Elements =
- DBuilder.GetOrCreateArray(&ElementTypes[0],
+ DBuilder.getOrCreateArray(&ElementTypes[0],
llvm::array_lengthof(ElementTypes));
- return DBuilder.CreateStructType(U, llvm::StringRef("test"),
+ return DBuilder.createStructType(U, llvm::StringRef("test"),
U, 0, FieldOffset,
0, 0, Elements);
}
@@ -1312,13 +1322,13 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
Enum != EnumEnd; ++Enum) {
Enumerators.push_back(
- DBuilder.CreateEnumerator(Enum->getName(),
+ DBuilder.createEnumerator(Enum->getName(),
Enum->getInitVal().getZExtValue()));
}
// Return a CompositeType for the enum itself.
llvm::DIArray EltArray =
- DBuilder.GetOrCreateArray(Enumerators.data(), Enumerators.size());
+ DBuilder.getOrCreateArray(Enumerators.data(), Enumerators.size());
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
@@ -1329,9 +1339,9 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
}
llvm::DIDescriptor EnumContext =
- getContextDescriptor(dyn_cast<Decl>(ED->getDeclContext()));
+ getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIType DbgTy =
- DBuilder.CreateEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
+ DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
Size, Align, EltArray);
return DbgTy;
}
@@ -1485,7 +1495,7 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
- llvm::DIType Ty = DBuilder.CreateMemberType(Name, Unit, 0,
+ llvm::DIType Ty = DBuilder.createMemberType(Name, Unit, 0,
FieldSize, FieldAlign,
*Offset, 0, FieldTy);
*Offset += FieldSize;
@@ -1548,7 +1558,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
llvm::DISubprogram SP =
- DBuilder.CreateFunction(FDContext, Name, LinkageName, Unit,
+ DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
LineNo, getOrCreateType(FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/,
Flags, CGM.getLangOptions().Optimize, Fn);
@@ -1640,7 +1650,7 @@ void CGDebugInfo::UpdateLineDirectiveRegion(CGBuilderTy &Builder) {
/// region - "llvm.dbg.region.start.".
void CGDebugInfo::EmitRegionStart(CGBuilderTy &Builder) {
llvm::DIDescriptor D =
- DBuilder.CreateLexicalBlock(RegionStack.empty() ?
+ DBuilder.createLexicalBlock(RegionStack.empty() ?
llvm::DIDescriptor() :
llvm::DIDescriptor(RegionStack.back()),
getOrCreateFile(CurLoc),
@@ -1725,18 +1735,18 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
FieldAlign = Align.getQuantity()*8;
*XOffset = FieldOffset;
- FieldTy = DBuilder.CreateMemberType(VD->getName(), Unit,
+ FieldTy = DBuilder.createMemberType(VD->getName(), Unit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
llvm::DIArray Elements =
- DBuilder.GetOrCreateArray(EltTys.data(), EltTys.size());
+ DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
- return DBuilder.CreateStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
+ return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
Elements);
}
@@ -1762,13 +1772,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// If Storage is an aggregate returned as 'sret' then let debugger know
// about this.
if (Arg->hasStructRetAttr())
- Ty = DBuilder.CreateReferenceType(Ty);
+ Ty = DBuilder.createReferenceType(Ty);
else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) {
// If an aggregate variable has non trivial destructor or non trivial copy
// constructor than it is pass indirectly. Let debug info know about this
// by using reference of the aggregate type as a argument type.
if (!Record->hasTrivialCopyConstructor() || !Record->hasTrivialDestructor())
- Ty = DBuilder.CreateReferenceType(Ty);
+ Ty = DBuilder.createReferenceType(Ty);
}
}
@@ -1799,27 +1809,27 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.CreateComplexVariable(Tag,
+ DBuilder.createComplexVariable(Tag,
llvm::DIDescriptor(RegionStack.back()),
VD->getName(), Unit, Line, Ty,
addr.data(), addr.size());
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DBuilder.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
}
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.CreateLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
Name, Unit, Line, Ty,
CGM.getLangOptions().Optimize, Flags);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DBuilder.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
@@ -1827,33 +1837,34 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// If VD is an anonymous union then Storage represents value for
// all union fields.
- if (const RecordType *RT = dyn_cast<RecordType>(VD->getType()))
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(RT->getDecl()))
- if (RD->isUnion()) {
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end();
- I != E; ++I) {
- FieldDecl *Field = *I;
- llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- llvm::StringRef FieldName = Field->getName();
+ if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ if (RD->isUnion()) {
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
+ I != E; ++I) {
+ FieldDecl *Field = *I;
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+ llvm::StringRef FieldName = Field->getName();
- // Ignore unnamed fields. Do not ignore unnamed records.
- if (FieldName.empty() && !isa<RecordType>(Field->getType()))
- continue;
+ // Ignore unnamed fields. Do not ignore unnamed records.
+ if (FieldName.empty() && !isa<RecordType>(Field->getType()))
+ continue;
- // Use VarDecl's Tag, Scope and Line number.
- llvm::DIVariable D =
- DBuilder.CreateLocalVariable(Tag, llvm::DIDescriptor(Scope),
- FieldName, Unit, Line, FieldTy,
- CGM.getLangOptions().Optimize, Flags);
+ // Use VarDecl's Tag, Scope and Line number.
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ FieldName, Unit, Line, FieldTy,
+ CGM.getLangOptions().Optimize, Flags);
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- }
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
+ }
+ }
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1887,7 +1898,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::SmallVector<llvm::Value *, 9> addr;
const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
- addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (isByRef) {
@@ -1905,12 +1915,12 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
+ DBuilder.createComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
VD->getName(), Unit, Line, Ty,
addr.data(), addr.size());
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DBuilder.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
llvm::MDNode *Scope = RegionStack.back();
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
@@ -1936,7 +1946,146 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
}
+namespace {
+ struct BlockLayoutChunk {
+ uint64_t OffsetInBits;
+ const BlockDecl::Capture *Capture;
+ };
+ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
+ return l.OffsetInBits < r.OffsetInBits;
+ }
+}
+
+void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
+ llvm::Value *addr,
+ CGBuilderTy &Builder) {
+ ASTContext &C = CGM.getContext();
+ const BlockDecl *blockDecl = block.getBlockDecl();
+
+ // Collect some general information about the block's location.
+ SourceLocation loc = blockDecl->getCaretLocation();
+ llvm::DIFile tunit = getOrCreateFile(loc);
+ unsigned line = getLineNumber(loc);
+ unsigned column = getColumnNumber(loc);
+
+ // Build the debug-info type for the block literal.
+ llvm::DIDescriptor enclosingContext =
+ getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
+
+ const llvm::StructLayout *blockLayout =
+ CGM.getTargetData().getStructLayout(block.StructureType);
+
+ llvm::SmallVector<llvm::Value*, 16> fields;
+ fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(0),
+ tunit));
+ fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(1),
+ tunit));
+ fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(2),
+ tunit));
+ fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(3),
+ tunit));
+ fields.push_back(createFieldType("__descriptor",
+ C.getPointerType(block.NeedsCopyDispose ?
+ C.getBlockDescriptorExtendedType() :
+ C.getBlockDescriptorType()),
+ 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(4),
+ tunit));
+
+ // We want to sort the captures by offset, not because DWARF
+ // requires this, but because we're paranoid about debuggers.
+ llvm::SmallVector<BlockLayoutChunk, 8> chunks;
+
+ // 'this' capture.
+ if (blockDecl->capturesCXXThis()) {
+ BlockLayoutChunk chunk;
+ chunk.OffsetInBits =
+ blockLayout->getElementOffsetInBits(block.CXXThisIndex);
+ chunk.Capture = 0;
+ chunks.push_back(chunk);
+ }
+
+ // Variable captures.
+ for (BlockDecl::capture_const_iterator
+ i = blockDecl->capture_begin(), e = blockDecl->capture_end();
+ i != e; ++i) {
+ const BlockDecl::Capture &capture = *i;
+ const VarDecl *variable = capture.getVariable();
+ const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
+ // Ignore constant captures.
+ if (captureInfo.isConstant())
+ continue;
+
+ BlockLayoutChunk chunk;
+ chunk.OffsetInBits =
+ blockLayout->getElementOffsetInBits(captureInfo.getIndex());
+ chunk.Capture = &capture;
+ chunks.push_back(chunk);
+ }
+
+ // Sort by offset.
+ llvm::array_pod_sort(chunks.begin(), chunks.end());
+
+ for (llvm::SmallVectorImpl<BlockLayoutChunk>::iterator
+ i = chunks.begin(), e = chunks.end(); i != e; ++i) {
+ uint64_t offsetInBits = i->OffsetInBits;
+ const BlockDecl::Capture *capture = i->Capture;
+
+ // If we have a null capture, this must be the C++ 'this' capture.
+ if (!capture) {
+ const CXXMethodDecl *method =
+ cast<CXXMethodDecl>(blockDecl->getNonClosureContext());
+ QualType type = method->getThisType(C);
+
+ fields.push_back(createFieldType("this", type, 0, loc, AS_public,
+ offsetInBits, tunit));
+ continue;
+ }
+
+ const VarDecl *variable = capture->getVariable();
+ QualType type = (capture->isByRef() ? C.VoidPtrTy : variable->getType());
+ llvm::StringRef name = variable->getName();
+ fields.push_back(createFieldType(name, type, 0, loc, AS_public,
+ offsetInBits, tunit));
+ }
+
+ llvm::SmallString<36> typeName;
+ llvm::raw_svector_ostream(typeName)
+ << "__block_literal_" << CGM.getUniqueBlockCount();
+
+ llvm::DIArray fieldsArray =
+ DBuilder.getOrCreateArray(fields.data(), fields.size());
+
+ llvm::DIType type =
+ DBuilder.createStructType(tunit, typeName.str(), tunit, line,
+ CGM.getContext().toBits(block.BlockSize),
+ CGM.getContext().toBits(block.BlockAlign),
+ 0, fieldsArray);
+ type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
+
+ // Get overall information about the block.
+ unsigned flags = llvm::DIDescriptor::FlagArtificial;
+ llvm::MDNode *scope = RegionStack.back();
+ llvm::StringRef name = ".block_descriptor";
+
+ // Create the descriptor for the parameter.
+ llvm::DIVariable debugVar =
+ DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
+ llvm::DIDescriptor(scope),
+ name, tunit, line, type,
+ CGM.getLangOptions().Optimize, flags);
+
+ // Insert an llvm.dbg.value into the current block.
+ llvm::Instruction *declare =
+ DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar,
+ Builder.GetInsertBlock());
+ declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+}
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
@@ -1967,7 +2116,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
LinkageName = llvm::StringRef();
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
- DBuilder.CreateStaticVariable(DContext, DeclName, LinkageName,
+ DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
Unit, LineNo, getOrCreateType(T, Unit),
Var->hasInternalLinkage(), Var);
}
@@ -1994,7 +2143,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ArrayType::Normal, 0);
}
- DBuilder.CreateGlobalVariable(Name, Unit, LineNo,
+ DBuilder.createGlobalVariable(Name, Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(), Var);
}
@@ -2013,7 +2162,7 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
// Do not use DIGlobalVariable for enums.
if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
- DBuilder.CreateStaticVariable(Unit, Name, Name, Unit,
+ DBuilder.createStaticVariable(Unit, Name, Name, Unit,
getLineNumber(VD->getLocation()),
Ty, true, Init);
}
@@ -2032,7 +2181,7 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
llvm::DIDescriptor Context =
getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
llvm::DINameSpace NS =
- DBuilder.CreateNameSpace(Context, NSDecl->getName(), FileD, LineNo);
+ DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
return NS;
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 6a9ab9c..a390788 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -123,7 +123,10 @@ class CGDebugInfo {
llvm::SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy);
-
+ llvm::DIType createFieldType(llvm::StringRef name, QualType type,
+ Expr *bitWidth, SourceLocation loc,
+ AccessSpecifier AS, uint64_t offsetInBits,
+ llvm::DIFile tunit);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
llvm::SmallVectorImpl<llvm::Value *> &E);
@@ -180,6 +183,13 @@ public:
void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
CGBuilderTy &Builder);
+ /// EmitDeclareOfBlockLiteralArgVariable - Emit call to
+ /// llvm.dbg.declare for the block-literal argument to a block
+ /// invocation function.
+ void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
+ llvm::Value *addr,
+ CGBuilderTy &Builder);
+
/// EmitGlobalVariable - Emit information about a global variable.
void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index a87dfae..f4db01d 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -474,14 +474,19 @@ namespace {
struct CallCleanupFunction : EHScopeStack::Cleanup {
llvm::Constant *CleanupFn;
const CGFunctionInfo &FnInfo;
- llvm::Value *Addr;
const VarDecl &Var;
CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info,
- llvm::Value *Addr, const VarDecl *Var)
- : CleanupFn(CleanupFn), FnInfo(*Info), Addr(Addr), Var(*Var) {}
+ const VarDecl *Var)
+ : CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
+ SourceLocation());
+ // Compute the address of the local variable, in case it's a byref
+ // or something.
+ llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getAddress();
+
// In some cases, the type of the function argument will be different from
// the type of the pointer. An example of this is
// void f(void* arg);
@@ -543,7 +548,7 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
/// canEmitInitWithFewStoresAfterMemset returned true for, emit the scalar
/// stores that would be required.
static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
- CGBuilderTy &Builder) {
+ bool isVolatile, CGBuilderTy &Builder) {
// Zero doesn't require any stores.
if (isa<llvm::ConstantAggregateZero>(Init) ||
isa<llvm::ConstantPointerNull>(Init) ||
@@ -554,7 +559,7 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
isa<llvm::ConstantExpr>(Init)) {
if (!Init->isNullValue())
- Builder.CreateStore(Init, Loc);
+ Builder.CreateStore(Init, Loc, isVolatile);
return;
}
@@ -567,7 +572,7 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
// Otherwise, get a pointer to the element and emit it.
emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- Builder);
+ isVolatile, Builder);
}
}
@@ -597,37 +602,55 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a
/// variable declaration with auto, register, or no storage class specifier.
/// These turn into simple stack objects, or GlobalValues depending on target.
-void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
- SpecialInitFn *SpecialInit) {
+void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
+ AutoVarEmission emission = EmitAutoVarAlloca(D);
+ EmitAutoVarInit(emission);
+ EmitAutoVarCleanups(emission);
+}
+
+/// EmitAutoVarAlloca - Emit the alloca and debug information for a
+/// local variable. Does not emit initalization or destruction.
+CodeGenFunction::AutoVarEmission
+CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType Ty = D.getType();
- unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
+
+ AutoVarEmission emission(D);
+
bool isByRef = D.hasAttr<BlocksAttr>();
- bool needsDispose = false;
- CharUnits Align = CharUnits::Zero();
- bool IsSimpleConstantInitializer = false;
+ emission.IsByRef = isByRef;
+
+ CharUnits alignment = getContext().getDeclAlign(&D);
+ emission.Alignment = alignment;
- bool NRVO = false;
- llvm::Value *NRVOFlag = 0;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- NRVO = getContext().getLangOptions().ElideConstructors &&
- D.isNRVOVariable();
- // If this value is an array or struct, is POD, and if the initializer is
- // a staticly determinable constant, try to optimize it (unless the NRVO
- // is already optimizing this).
- if (!NRVO && D.getInit() && !isByRef &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
- Ty->isPODType() &&
+ bool NRVO = getContext().getLangOptions().ElideConstructors &&
+ D.isNRVOVariable();
+
+ // If this value is a POD array or struct with a statically
+ // determinable constant initializer, there are optimizations we
+ // can do.
+ // TODO: we can potentially constant-evaluate non-POD structs and
+ // arrays as long as the initialization is trivial (e.g. if they
+ // have a non-trivial destructor, but not a non-trivial constructor).
+ if (D.getInit() &&
+ (Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() &&
D.getInit()->isConstantInitializer(getContext(), false)) {
- // If this variable is marked 'const', emit the value as a global.
- if (CGM.getCodeGenOpts().MergeAllConstants &&
- Ty.isConstant(getContext())) {
- EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
- return;
+
+ // If the variable's a const type, and it's neither an NRVO
+ // candidate nor a __block variable, emit it as a global instead.
+ if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
+ !NRVO && !isByRef) {
+ EmitStaticVarDecl(D, llvm::GlobalValue::PrivateLinkage);
+
+ emission.Address = 0; // signal this condition to later callbacks
+ assert(emission.wasEmittedAsGlobal());
+ return emission;
}
-
- IsSimpleConstantInitializer = true;
+
+ // Otherwise, tell the initialization code that we're in this case.
+ emission.IsConstantAggregate = true;
}
// A normal fixed sized variable becomes an alloca in the entry block,
@@ -646,12 +669,13 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
// to this variable. Set it to zero to indicate that NRVO was not
// applied.
llvm::Value *Zero = Builder.getFalse();
- NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
+ llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
EnsureInsertPoint();
Builder.CreateStore(Zero, NRVOFlag);
// Record the NRVO flag for this variable.
NRVOFlags[&D] = NRVOFlag;
+ emission.NRVOFlag = NRVOFlag;
}
}
} else {
@@ -661,11 +685,11 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString());
- Align = getContext().getDeclAlign(&D);
+ CharUnits allocaAlignment = alignment;
if (isByRef)
- Align = std::max(Align,
+ allocaAlignment = std::max(allocaAlignment,
getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
- Alloc->setAlignment(Align.getQuantity());
+ Alloc->setAlignment(allocaAlignment.getQuantity());
DeclPtr = Alloc;
}
} else {
@@ -707,7 +731,7 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
// Allocate memory for the array.
llvm::AllocaInst *VLA =
Builder.CreateAlloca(llvm::Type::getInt8Ty(getLLVMContext()), VLASize, "vla");
- VLA->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ VLA->setAlignment(alignment.getQuantity());
DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
}
@@ -715,6 +739,7 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
+ emission.Address = DeclPtr;
// Emit debug info for local var declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
@@ -727,53 +752,92 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
}
+ return emission;
+}
+
+/// Determines whether the given __block variable is potentially
+/// captured by the given expression.
+static bool isCapturedBy(const VarDecl &var, const Expr *e) {
+ // Skip the most common kinds of expressions that make
+ // hierarchy-walking expensive.
+ e = e->IgnoreParenCasts();
+
+ if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) {
+ const BlockDecl *block = be->getBlockDecl();
+ for (BlockDecl::capture_const_iterator i = block->capture_begin(),
+ e = block->capture_end(); i != e; ++i) {
+ if (i->getVariable() == &var)
+ return true;
+ }
+
+ // No need to walk into the subexpressions.
+ return false;
+ }
+
+ for (Stmt::const_child_range children = e->children(); children; ++children)
+ if (isCapturedBy(var, cast<Expr>(*children)))
+ return true;
+
+ return false;
+}
+
+void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
+ assert(emission.Variable && "emission was not valid!");
+
+ // If this was emitted as a global constant, we're done.
+ if (emission.wasEmittedAsGlobal()) return;
+
+ const VarDecl &D = *emission.Variable;
+ QualType type = D.getType();
+
// If this local has an initializer, emit it now.
const Expr *Init = D.getInit();
// If we are at an unreachable point, we don't need to emit the initializer
// unless it contains a label.
if (!HaveInsertPoint()) {
- if (!ContainsLabel(Init))
- Init = 0;
- else
- EnsureInsertPoint();
+ if (!Init || !ContainsLabel(Init)) return;
+ EnsureInsertPoint();
}
- if (isByRef) {
- EnsureInsertPoint();
+ CharUnits alignment = emission.Alignment;
+
+ if (emission.IsByRef) {
llvm::Value *V;
BlockFieldFlags fieldFlags;
bool fieldNeedsCopyDispose = false;
- needsDispose = true;
-
- if (Ty->isBlockPointerType()) {
+ if (type->isBlockPointerType()) {
fieldFlags |= BLOCK_FIELD_IS_BLOCK;
fieldNeedsCopyDispose = true;
- } else if (getContext().isObjCNSObjectType(Ty) ||
- Ty->isObjCObjectPointerType()) {
+ } else if (getContext().isObjCNSObjectType(type) ||
+ type->isObjCObjectPointerType()) {
fieldFlags |= BLOCK_FIELD_IS_OBJECT;
fieldNeedsCopyDispose = true;
} else if (getLangOptions().CPlusPlus) {
if (getContext().getBlockVarCopyInits(&D))
fieldNeedsCopyDispose = true;
- else if (const CXXRecordDecl *record = D.getType()->getAsCXXRecordDecl())
+ else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
fieldNeedsCopyDispose = !record->hasTrivialDestructor();
}
+ llvm::Value *addr = emission.Address;
+
// FIXME: Someone double check this.
- if (Ty.isObjCGCWeak())
+ if (type.isObjCGCWeak())
fieldFlags |= BLOCK_FIELD_IS_WEAK;
+ // Initialize the 'isa', which is just 0 or 1.
int isa = 0;
if (fieldFlags & BLOCK_FIELD_IS_WEAK)
isa = 1;
V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
- Builder.CreateStore(V, Builder.CreateStructGEP(DeclPtr, 0, "byref.isa"));
+ Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa"));
- Builder.CreateStore(DeclPtr, Builder.CreateStructGEP(DeclPtr, 1,
- "byref.forwarding"));
+ // Store the address of the variable into its own forwarding pointer.
+ Builder.CreateStore(addr,
+ Builder.CreateStructGEP(addr, 1, "byref.forwarding"));
// Blocks ABI:
// c) the flags field is set to either 0 if no helper functions are
@@ -781,150 +845,157 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
BlockFlags flags;
if (fieldNeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- Builder.CreateStructGEP(DeclPtr, 2, "byref.flags"));
+ Builder.CreateStructGEP(addr, 2, "byref.flags"));
const llvm::Type *V1;
- V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
+ V1 = cast<llvm::PointerType>(addr->getType())->getElementType();
V = llvm::ConstantInt::get(IntTy, CGM.GetTargetTypeStoreSize(V1).getQuantity());
- Builder.CreateStore(V, Builder.CreateStructGEP(DeclPtr, 3, "byref.size"));
+ Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size"));
if (fieldNeedsCopyDispose) {
- llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
- Builder.CreateStore(CGM.BuildbyrefCopyHelper(DeclPtr->getType(),
- fieldFlags,
- Align.getQuantity(), &D),
+ llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4);
+ Builder.CreateStore(CGM.BuildbyrefCopyHelper(addr->getType(), fieldFlags,
+ alignment.getQuantity(), &D),
copy_helper);
- llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
- Builder.CreateStore(CGM.BuildbyrefDestroyHelper(DeclPtr->getType(),
+ llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
+ Builder.CreateStore(CGM.BuildbyrefDestroyHelper(addr->getType(),
fieldFlags,
- Align.getQuantity(), &D),
+ alignment.getQuantity(),
+ &D),
destroy_helper);
}
}
- if (SpecialInit) {
- SpecialInit(*this, D, DeclPtr);
- } else if (Init) {
- llvm::Value *Loc = DeclPtr;
-
- bool isVolatile = getContext().getCanonicalType(Ty).isVolatileQualified();
+ if (!Init) return;
+
+ // Check whether this is a byref variable that's potentially
+ // captured and moved by its own initializer. If so, we'll need to
+ // emit the initializer first, then copy into the variable.
+ bool capturedByInit = emission.IsByRef && isCapturedBy(D, Init);
+
+ llvm::Value *Loc =
+ capturedByInit ? emission.Address : emission.getObjectAddress(*this);
+
+ bool isVolatile = type.isVolatileQualified();
- // If the initializer was a simple constant initializer, we can optimize it
- // in various ways.
- if (IsSimpleConstantInitializer) {
- llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), Ty,this);
- assert(Init != 0 && "Wasn't a simple constant init?");
-
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(IntPtrTy,
- getContext().getTypeSizeInChars(Ty).getQuantity());
-
- const llvm::Type *BP = Int8PtrTy;
- if (Loc->getType() != BP)
- Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+ // If this is a simple aggregate initialization, we can optimize it
+ // in various ways.
+ if (emission.IsConstantAggregate) {
+ assert(!capturedByInit && "constant init contains a capturing block?");
+
+ llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), type, this);
+ assert(Init != 0 && "Wasn't a simple constant init?");
- // If the initializer is all or mostly zeros, codegen with memset then do
- // a few stores afterward.
- if (shouldUseMemSetPlusStoresToInitialize(Init,
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(IntPtrTy,
+ getContext().getTypeSizeInChars(type).getQuantity());
+
+ const llvm::Type *BP = Int8PtrTy;
+ if (Loc->getType() != BP)
+ Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+
+ // If the initializer is all or mostly zeros, codegen with memset then do
+ // a few stores afterward.
+ if (shouldUseMemSetPlusStoresToInitialize(Init,
CGM.getTargetData().getTypeAllocSize(Init->getType()))) {
- Builder.CreateMemSet(Loc, Builder.getInt8(0), SizeVal,
- Align.getQuantity(), false);
- if (!Init->isNullValue()) {
- Loc = Builder.CreateBitCast(Loc, Init->getType()->getPointerTo());
- emitStoresForInitAfterMemset(Init, Loc, Builder);
- }
-
- } else {
- // Otherwise, create a temporary global with the initializer then
- // memcpy from the global to the alloca.
- std::string Name = GetStaticDeclName(*this, D, ".");
- llvm::GlobalVariable *GV =
+ Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
+ alignment.getQuantity(), isVolatile);
+ if (!Init->isNullValue()) {
+ Loc = Builder.CreateBitCast(Loc, Init->getType()->getPointerTo());
+ emitStoresForInitAfterMemset(Init, Loc, isVolatile, Builder);
+ }
+ } else {
+ // Otherwise, create a temporary global with the initializer then
+ // memcpy from the global to the alloca.
+ std::string Name = GetStaticDeclName(*this, D, ".");
+ llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
llvm::GlobalValue::InternalLinkage,
Init, Name, 0, false, 0);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(alignment.getQuantity());
- llvm::Value *SrcPtr = GV;
- if (SrcPtr->getType() != BP)
- SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+ llvm::Value *SrcPtr = GV;
+ if (SrcPtr->getType() != BP)
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
- Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, Align.getQuantity(), false);
- }
- } else if (Ty->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(Init, &D);
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
- EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Alignment, Ty);
- } else if (!hasAggregateLLVMType(Init->getType())) {
- llvm::Value *V = EmitScalarExpr(Init);
- if (isByRef) {
- // When RHS has side-effect, must go through "forwarding' field
- // to get to the address of the __block variable descriptor.
- if (Init->HasSideEffects(getContext()))
- Loc = BuildBlockByrefAddress(DeclPtr, &D);
- else
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
- }
- EmitStoreOfScalar(V, Loc, isVolatile, Alignment, Ty);
- } else if (Init->getType()->isAnyComplexType()) {
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
- EmitComplexExprIntoAddr(Init, Loc, isVolatile);
- } else {
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
- EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false));
+ Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(),
+ isVolatile);
}
+ } else if (type->isReferenceType()) {
+ RValue RV = EmitReferenceBindingToExpr(Init, &D);
+ if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
+ EmitStoreOfScalar(RV.getScalarVal(), Loc, false, alignment.getQuantity(),
+ type);
+ } else if (!hasAggregateLLVMType(type)) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
+ EmitStoreOfScalar(V, Loc, isVolatile, alignment.getQuantity(), type);
+ } else if (type->isAnyComplexType()) {
+ ComplexPairTy complex = EmitComplexExpr(Init);
+ if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
+ StoreComplexToAddr(complex, Loc, isVolatile);
+ } else {
+ // TODO: how can we delay here if D is captured by its initializer?
+ EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false));
}
+}
- // Handle CXX destruction of variables.
- QualType DtorTy(Ty);
- while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
- DtorTy = getContext().getBaseElementType(Array);
- if (const RecordType *RT = DtorTy->getAs<RecordType>())
- if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
+ assert(emission.Variable && "emission was not valid!");
+
+ // If this was emitted as a global constant, we're done.
+ if (emission.wasEmittedAsGlobal()) return;
+
+ const VarDecl &D = *emission.Variable;
+
+ // Handle C++ destruction of variables.
+ if (getLangOptions().CPlusPlus) {
+ QualType type = D.getType();
+ QualType baseType = getContext().getBaseElementType(type);
+ if (const RecordType *RT = baseType->getAs<RecordType>()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (!ClassDecl->hasTrivialDestructor()) {
// Note: We suppress the destructor call when the corresponding NRVO
// flag has been set.
- llvm::Value *Loc = DeclPtr;
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
+
+ // Note that for __block variables, we want to destroy the
+ // original stack object, not the possible forwarded object.
+ llvm::Value *Loc = emission.getObjectAddress(*this);
const CXXDestructorDecl *D = ClassDecl->getDestructor();
assert(D && "EmitLocalBlockVarDecl - destructor is nul");
- if (const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(Ty)) {
+ if (type != baseType) {
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(type);
+ assert(Array && "types changed without array?");
EHStack.pushCleanup<CallArrayDtor>(NormalAndEHCleanup,
D, Array, Loc);
} else {
EHStack.pushCleanup<CallVarDtor>(NormalAndEHCleanup,
- D, NRVOFlag, Loc);
+ D, emission.NRVOFlag, Loc);
}
}
+ }
}
- // Handle the cleanup attribute
+ // Handle the cleanup attribute.
if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
const FunctionDecl *FD = CA->getFunctionDecl();
- llvm::Constant* F = CGM.GetAddrOfFunction(FD);
+ llvm::Constant *F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
- EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup,
- F, &Info, DeclPtr, &D);
+ EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, F, &Info, &D);
}
- // If this is a block variable, clean it up.
- if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly)
- EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, DeclPtr);
+ // If this is a block variable, call _Block_object_destroy
+ // (on the unforwarded address).
+ if (emission.IsByRef &&
+ CGM.getLangOptions().getGCMode() != LangOptions::GCOnly)
+ EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address);
}
/// Emit an alloca (or GlobalValue depending on target)
@@ -933,6 +1004,24 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
// FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
"Invalid argument to EmitParmDecl");
+
+ Arg->setName(D.getName());
+
+ // Use better IR generation for certain implicit parameters.
+ if (isa<ImplicitParamDecl>(D)) {
+ // The only implicit argument a block has is its literal.
+ if (BlockInfo) {
+ LocalDeclMap[&D] = Arg;
+
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D.getLocation());
+ DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
+ }
+
+ return;
+ }
+ }
+
QualType Ty = D.getType();
llvm::Value *DeclPtr;
@@ -949,7 +1038,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
getContext().getDeclAlign(&D).getQuantity(), Ty,
CGM.getTBAAInfo(Ty));
}
- Arg->setName(D.getName());
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 6181965..4bce081 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -1086,14 +1086,14 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
// 3. Enter __cxa_end_catch cleanup
// 4. Enter dtor cleanup
//
- // We do this by initializing the exception variable with a
- // "special initializer", InitCatchParam. Delegation sequence:
+ // We do this by using a slightly abnormal initialization process.
+ // Delegation sequence:
// - ExitCXXTryStmt opens a RunCleanupsScope
- // - EmitLocalBlockVarDecl creates the variable and debug info
+ // - EmitAutoVarAlloca creates the variable and debug info
// - InitCatchParam initializes the variable from the exception
- // - CallBeginCatch calls __cxa_begin_catch
- // - CallBeginCatch enters the __cxa_end_catch cleanup
- // - EmitLocalBlockVarDecl enters the variable destructor cleanup
+ // - CallBeginCatch calls __cxa_begin_catch
+ // - CallBeginCatch enters the __cxa_end_catch cleanup
+ // - EmitAutoVarCleanups enters the variable destructor cleanup
// - EmitCXXTryStmt emits the code for the catch body
// - EmitCXXTryStmt close the RunCleanupsScope
@@ -1105,7 +1105,9 @@ static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {
}
// Emit the local.
- CGF.EmitAutoVarDecl(*CatchParam, &InitCatchParam);
+ CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
+ InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF));
+ CGF.EmitAutoVarCleanups(var);
}
namespace {
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 1b7e7a0..2abaadf 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -260,6 +260,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
}
}
+ if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
+ if (opaque->getType()->isRecordType())
+ return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+
// Nothing changed.
break;
}
@@ -1606,39 +1610,67 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
}
}
-LValue CodeGenFunction::EmitLValueForField(llvm::Value *BaseValue,
- const FieldDecl *Field,
- unsigned CVRQualifiers) {
- if (Field->isBitField())
- return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
+LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
+ const FieldDecl *field,
+ unsigned cvr) {
+ if (field->isBitField())
+ return EmitLValueForBitfield(baseAddr, field, cvr);
- const CGRecordLayout &RL =
- CGM.getTypes().getCGRecordLayout(Field->getParent());
- unsigned idx = RL.getLLVMFieldNo(Field);
- llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
+ const RecordDecl *rec = field->getParent();
+ QualType type = field->getType();
+
+ bool mayAlias = rec->hasAttr<MayAliasAttr>();
- // Match union field type.
- if (Field->getParent()->isUnion()) {
- const llvm::Type *FieldTy =
- CGM.getTypes().ConvertTypeForMem(Field->getType());
- const llvm::PointerType *BaseTy =
- cast<llvm::PointerType>(BaseValue->getType());
- unsigned AS = BaseTy->getAddressSpace();
- V = Builder.CreateBitCast(V,
- llvm::PointerType::get(FieldTy, AS),
- "tmp");
+ llvm::Value *addr;
+ if (rec->isUnion()) {
+ // For unions, we just cast to the appropriate type.
+ assert(!type->isReferenceType() && "union has reference member");
+
+ const llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(type);
+ unsigned AS =
+ cast<llvm::PointerType>(baseAddr->getType())->getAddressSpace();
+ addr = Builder.CreateBitCast(baseAddr, llvmType->getPointerTo(AS),
+ field->getName());
+ } else {
+ // For structs, we GEP to the field that the record layout suggests.
+ unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
+ addr = Builder.CreateStructGEP(baseAddr, idx, field->getName());
+
+ // If this is a reference field, load the reference right now.
+ if (const ReferenceType *refType = type->getAs<ReferenceType>()) {
+ llvm::LoadInst *load = Builder.CreateLoad(addr, "ref");
+ if (cvr & Qualifiers::Volatile) load->setVolatile(true);
+
+ if (CGM.shouldUseTBAA()) {
+ llvm::MDNode *tbaa;
+ if (mayAlias)
+ tbaa = CGM.getTBAAInfo(getContext().CharTy);
+ else
+ tbaa = CGM.getTBAAInfo(type);
+ CGM.DecorateInstruction(load, tbaa);
+ }
+
+ addr = load;
+ mayAlias = false;
+ type = refType->getPointeeType();
+ cvr = 0; // qualifiers don't recursively apply to referencee
+ }
}
- if (Field->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
- unsigned Alignment = getContext().getDeclAlign(Field).getQuantity();
- LValue LV = MakeAddrLValue(V, Field->getType(), Alignment);
- LV.getQuals().addCVRQualifiers(CVRQualifiers);
+ unsigned alignment = getContext().getDeclAlign(field).getQuantity();
+ LValue LV = MakeAddrLValue(addr, type, alignment);
+ LV.getQuals().addCVRQualifiers(cvr);
// __weak attribute on a field is ignored.
if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
LV.getQuals().removeObjCGCAttr();
-
+
+ // Fields of may_alias structs act like 'char' for TBAA purposes.
+ // FIXME: this should get propagated down through anonymous structs
+ // and unions.
+ if (mayAlias && LV.getTBAAInfo())
+ LV.setTBAAInfo(CGM.getTBAAInfo(getContext().CharTy));
+
return LV;
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 08c458b..5d34907 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -663,6 +663,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
return;
}
+ // The local variable comes into scope immediately.
+ AutoVarEmission variable = AutoVarEmission::invalid();
+ if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
+ variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
+
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(S.getSourceRange().getBegin());
@@ -799,22 +804,23 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Initialize the element variable.
RunCleanupsScope elementVariableScope(*this);
- bool elementIsDecl;
+ bool elementIsVariable;
LValue elementLValue;
QualType elementType;
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) {
- EmitStmt(SD);
- const VarDecl* D = cast<VarDecl>(SD->getSingleDecl());
+ // Initialize the variable, in case it's a __block variable or something.
+ EmitAutoVarInit(variable);
+ const VarDecl* D = cast<VarDecl>(SD->getSingleDecl());
DeclRefExpr tempDRE(const_cast<VarDecl*>(D), D->getType(),
VK_LValue, SourceLocation());
elementLValue = EmitLValue(&tempDRE);
elementType = D->getType();
- elementIsDecl = true;
+ elementIsVariable = true;
} else {
elementLValue = LValue(); // suppress warning
elementType = cast<Expr>(S.getElement())->getType();
- elementIsDecl = false;
+ elementIsVariable = false;
}
const llvm::Type *convertedElementType = ConvertType(elementType);
@@ -837,11 +843,16 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Make sure we have an l-value. Yes, this gets evaluated every
// time through the loop.
- if (!elementIsDecl)
+ if (!elementIsVariable)
elementLValue = EmitLValue(cast<Expr>(S.getElement()));
EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue, elementType);
+ // If we do have an element variable, this assignment is the end of
+ // its initialization.
+ if (elementIsVariable)
+ EmitAutoVarCleanups(variable);
+
// Perform the loop body, setting up break and continue labels.
BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
{
@@ -891,7 +902,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// No more elements.
EmitBlock(EmptyBB);
- if (!elementIsDecl) {
+ if (!elementIsVariable) {
// If the element was not a declaration, set it to be null.
llvm::Value *null = llvm::Constant::getNullValue(convertedElementType);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index d481e77..5f19dc6 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -949,7 +949,12 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(MakeConstantString(Name, ".class_name"));
Elements.push_back(Zero);
Elements.push_back(llvm::ConstantInt::get(LongTy, info));
- Elements.push_back(InstanceSize);
+ if (isMeta) {
+ llvm::TargetData td(&TheModule);
+ Elements.push_back(llvm::ConstantInt::get(LongTy,
+ td.getTypeSizeInBits(ClassTy)/8));
+ } else
+ Elements.push_back(InstanceSize);
Elements.push_back(IVars);
Elements.push_back(Methods);
Elements.push_back(NULLPtr);
@@ -1831,9 +1836,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
std::vector<const llvm::Type*> Params;
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- Params.push_back(IntTy);
+ Params.push_back(SizeTy);
Params.push_back(BoolTy);
- // void objc_getProperty (id, SEL, int, bool)
+ // void objc_getProperty (id, SEL, ptrdiff_t, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(IdTy, Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
@@ -1844,11 +1849,11 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() {
std::vector<const llvm::Type*> Params;
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- Params.push_back(IntTy);
+ Params.push_back(SizeTy);
Params.push_back(IdTy);
Params.push_back(BoolTy);
Params.push_back(BoolTy);
- // void objc_setProperty (id, SEL, int, id, bool, bool)
+ // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 7c679b9..8dbd85f 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -46,6 +46,15 @@ using namespace CodeGen;
// don't belong in CGObjCRuntime either so we will live with it for
// now.
+static void EmitNullReturnInitialization(CodeGenFunction &CGF,
+ ReturnValueSlot &returnSlot,
+ QualType resultType) {
+ // Force the return slot to exist.
+ if (!returnSlot.getValue())
+ returnSlot = ReturnValueSlot(CGF.CreateMemTemp(resultType), false);
+ CGF.EmitNullInitialization(returnSlot.getValue(), resultType);
+}
+
static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *OID,
const ObjCImplementationDecl *ID,
@@ -1639,6 +1648,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
+ EmitNullReturnInitialization(CGF, Return, ResultType);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -5629,6 +5639,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
+ EmitNullReturnInitialization(CGF, Return, ResultType);
if (IsSuper) {
Fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
Name += "objc_msgSendSuper2_stret_fixup";
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 4b19aef..ceae66f 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -207,8 +207,9 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
uint64_t ContainingTypeSizeInBits,
unsigned ContainingTypeAlign) {
const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType());
- uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty);
- uint64_t TypeSizeInBits = TypeSizeInBytes * 8;
+ CharUnits TypeSizeInBytes =
+ CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
+ uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
bool IsSigned = FD->getType()->isSignedIntegerType();
@@ -249,7 +250,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
// Adjust initial access size to fit within record.
- while (AccessWidth > 8 &&
+ while (AccessWidth > Types.getTarget().getCharWidth() &&
AccessStart + AccessWidth > ContainingTypeSizeInBits) {
AccessWidth >>= 1;
AccessStart = FieldOffset - (FieldOffset % AccessWidth);
@@ -262,7 +263,8 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
if (AccessStart + AccessWidth > ContainingTypeSizeInBits) {
// If so, reduce access size to the next smaller power-of-two and retry.
AccessWidth >>= 1;
- assert(AccessWidth >= 8 && "Cannot access under byte size!");
+ assert(AccessWidth >= Types.getTarget().getCharWidth()
+ && "Cannot access under byte size!");
continue;
}
@@ -329,7 +331,7 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
if (fieldSize == 0)
return;
- uint64_t nextFieldOffsetInBits = NextFieldOffset.getQuantity() * 8;
+ uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
unsigned numBytesToAppend;
if (fieldOffset < nextFieldOffsetInBits) {
@@ -378,8 +380,10 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
CheckZeroInitializable(D->getType());
- assert(fieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
- CharUnits fieldOffsetInBytes = CharUnits::fromQuantity(fieldOffset / 8);
+ assert(fieldOffset % Types.getTarget().getCharWidth() == 0
+ && "field offset is not on a byte boundary!");
+ CharUnits fieldOffsetInBytes
+ = Types.getContext().toCharUnitsFromBits(fieldOffset);
const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
CharUnits typeAlignment = getTypeAlignment(Ty);
@@ -396,7 +400,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
if (const MaxFieldAlignmentAttr *MFAA =
RD->getAttr<MaxFieldAlignmentAttr>()) {
- if (MFAA->getAlignment() != typeAlignment.getQuantity() * 8)
+ if (MFAA->getAlignment() != Types.getContext().toBits(typeAlignment))
return false;
}
}
@@ -728,7 +732,8 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
assert(RecordSize % 8 == 0 && "Invalid record size!");
- CharUnits RecordSizeInBytes = CharUnits::fromQuantity(RecordSize / 8);
+ CharUnits RecordSizeInBytes =
+ Types.getContext().toCharUnitsFromBits(RecordSize);
assert(NextFieldOffset <= RecordSizeInBytes && "Size mismatch!");
CharUnits AlignedNextFieldOffset =
@@ -920,7 +925,8 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
// Verify that every component access is within the structure.
uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
- uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8;
+ uint64_t AccessBitOffset = FieldOffset +
+ getContext().toBits(CharUnits::fromQuantity(AI.FieldByteOffset));
assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
"Invalid bit-field access (out of range)!");
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 67ef414..be646fb 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1555,7 +1555,55 @@ public:
/// EmitAutoVarDecl - Emit an auto variable declaration.
///
/// This function can be called with a null (unreachable) insert point.
- void EmitAutoVarDecl(const VarDecl &D, SpecialInitFn *SpecialInit = 0);
+ void EmitAutoVarDecl(const VarDecl &D);
+
+ class AutoVarEmission {
+ friend class CodeGenFunction;
+
+ const VarDecl *Variable;
+
+ /// The alignment of the variable.
+ CharUnits Alignment;
+
+ /// The address of the alloca. Null if the variable was emitted
+ /// as a global constant.
+ llvm::Value *Address;
+
+ llvm::Value *NRVOFlag;
+
+ /// True if the variable is a __block variable.
+ bool IsByRef;
+
+ /// True if the variable is of aggregate type and has a constant
+ /// initializer.
+ bool IsConstantAggregate;
+
+ struct Invalid {};
+ AutoVarEmission(Invalid) : Variable(0) {}
+
+ AutoVarEmission(const VarDecl &variable)
+ : Variable(&variable), Address(0), NRVOFlag(0),
+ IsByRef(false), IsConstantAggregate(false) {}
+
+ bool wasEmittedAsGlobal() const { return Address == 0; }
+
+ public:
+ static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
+
+ /// Returns the address of the object within this declaration.
+ /// Note that this does not chase the forwarding pointer for
+ /// __block decls.
+ llvm::Value *getObjectAddress(CodeGenFunction &CGF) const {
+ if (!IsByRef) return Address;
+
+ return CGF.Builder.CreateStructGEP(Address,
+ CGF.getByRefValueLLVMField(Variable),
+ Variable->getNameAsString());
+ }
+ };
+ AutoVarEmission EmitAutoVarAlloca(const VarDecl &var);
+ void EmitAutoVarInit(const AutoVarEmission &emission);
+ void EmitAutoVarCleanups(const AutoVarEmission &emission);
void EmitStaticVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 9e5d7cf..a8453c3 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -97,6 +97,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
PointerWidthInBits = C.Target.getPointerWidth(0);
+ PointerAlignInBytes =
+ C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity();
IntTy = llvm::IntegerType::get(LLVMContext, C.Target.getIntWidth());
IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits);
Int8PtrTy = Int8Ty->getPointerTo(0);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index b6bd37c..73e6ece 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -120,8 +120,11 @@ namespace CodeGen {
const llvm::PointerType *Int8PtrPtrTy;
};
- /// The width of an address-zero pointer.
+ /// The width of a pointer into the generic address space.
unsigned char PointerWidthInBits;
+
+ /// The alignment of a pointer into the generic address space.
+ unsigned char PointerAlignInBytes;
};
/// CodeGenModule - This class organizes the cross-function state that is used
@@ -292,6 +295,8 @@ public:
const TargetCodeGenInfo &getTargetCodeGenInfo();
bool isTargetDarwin() const;
+ bool shouldUseTBAA() const { return TBAA != 0; }
+
llvm::MDNode *getTBAAInfo(QualType QTy);
static void DecorateInstruction(llvm::Instruction *Inst,
@@ -386,8 +391,8 @@ public:
unsigned Align,
const VarDecl *variable);
- /// getGlobalUniqueCount - Fetches the global unique block count.
- int getGlobalUniqueCount() { return ++Block.GlobalUniqueCount; }
+ /// getUniqueBlockCount - Fetches the global unique block count.
+ int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
/// getBlockDescriptorType - Fetches the type of a generic block
/// descriptor.
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index d74b3f3..2ffc840 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -2105,8 +2105,15 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const {
RT->getDecl()->hasFlexibleArrayMember())
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- // FIXME: mingw64-gcc emits 128-bit struct as i128
- if (Size <= 128 &&
+ // FIXME: mingw-w64-gcc emits 128-bit struct as i128
+ if (Size == 128 &&
+ getContext().Target.getTriple().getOS() == llvm::Triple::MinGW32)
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
+ Size));
+
+ // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
+ // not 1, 2, 4, or 8 bytes, must be passed by reference."
+ if (Size <= 64 &&
(Size & (Size - 1)) == 0)
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index e4051a1..e305683 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -198,7 +198,8 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
switch (Type) {
case ToolChain::CST_Libcxx:
- CmdArgs.push_back("-cxx-system-include");
+ CmdArgs.push_back("-nostdinc++");
+ CmdArgs.push_back("-cxx-isystem");
CmdArgs.push_back("/usr/include/c++/v1");
break;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 13b8b46..1c396bd 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -42,7 +42,7 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
// Compute the initial Darwin version based on the host.
bool HadExtra;
std::string OSName = Triple.getOSName();
- if (!Driver::GetReleaseVersion(&OSName[6],
+ if (!Driver::GetReleaseVersion(&OSName.c_str()[6],
DarwinVersion[0], DarwinVersion[1],
DarwinVersion[2], HadExtra))
getDriver().Diag(clang::diag::err_drv_invalid_darwin_version) << OSName;
@@ -1271,6 +1271,7 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
/// Linux toolchain (very bare-bones at the moment).
enum LinuxDistro {
+ ArchLinux,
DebianLenny,
DebianSqueeze,
Exherbo,
@@ -1367,6 +1368,9 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists)
return Exherbo;
+ if (!llvm::sys::fs::exists("/etc/arch-release", Exists) && Exists)
+ return ArchLinux;
+
return UnknownDistro;
}
@@ -1436,8 +1440,9 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
GccTriple = "i586-suse-linux";
}
- const char* GccVersions[] = {"4.5.1", "4.5", "4.4.5", "4.4.4", "4.4.3", "4.4",
- "4.3.4", "4.3.3", "4.3.2"};
+ const char* GccVersions[] = {"4.5.2", "4.5.1", "4.5", "4.4.5", "4.4.4",
+ "4.4.3", "4.4", "4.3.4", "4.3.3", "4.3.2",
+ "4.3"};
std::string Base = "";
for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
std::string Suffix = GccTriple + "/" + GccVersions[i];
@@ -1498,6 +1503,9 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
Distro == UbuntuKarmic)
ExtraOpts.push_back("--build-id");
+ if (Distro == ArchLinux)
+ Lib = "lib";
+
Paths.push_back(Base + Suffix);
if (HasMultilib(Arch, Distro)) {
if (IsOpenSuse(Distro) && Is32Bits)
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 6717349..9f4a0bc 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1546,10 +1546,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
- // -fobjc-exceptions is default.
- if (!Args.hasFlag(options::OPT_fobjc_exceptions,
- options::OPT_fno_objc_exceptions))
- CmdArgs.push_back("-fno-objc-exceptions");
+ // -fno-objc-exceptions is default.
+ if (IsRewriter || Args.hasFlag(options::OPT_fobjc_exceptions,
+ options::OPT_fno_objc_exceptions))
+ CmdArgs.push_back("-fobjc-exceptions");
}
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
@@ -3085,7 +3085,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-pthread");
+ CmdArgs.push_back("-lpthread");
if (!Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lgcc");
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 4a5a51d..a7942e6 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -389,7 +389,8 @@ public:
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
llvm::StringRef OriginalFileName,
- std::string &SuggestedPredefines) {
+ std::string &SuggestedPredefines,
+ FileManager &FileMgr) {
Predefines = Buffers[0].Data;
for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
Predefines += Buffers[I].Data;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 103d251..b9d15ad 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -78,6 +78,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
std::vector<std::string> &Res) {
for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
Res.push_back(getAnalysisName(Opts.AnalysisList[i]));
+ if (Opts.ShowCheckerHelp)
+ Res.push_back("-analyzer-checker-help");
if (Opts.AnalysisStoreOpt != BasicStoreModel) {
Res.push_back("-analyzer-store");
Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
@@ -114,8 +116,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-viz-egraph-ubigraph");
if (Opts.EnableExperimentalChecks)
Res.push_back("-analyzer-experimental-checks");
- if (Opts.EnableExperimentalInternalChecks)
- Res.push_back("-analyzer-experimental-internal-checks");
if (Opts.BufferOverflows)
Res.push_back("-analyzer-check-buffer-overflows");
@@ -473,11 +473,6 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back(Opts.Sysroot);
}
- for (unsigned i = 0, e = Opts.CXXSystemIncludes.size(); i != e; ++i) {
- Res.push_back("-cxx-system-include");
- Res.push_back(Opts.CXXSystemIncludes[i]);
- }
-
/// User specified include entries.
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
@@ -490,6 +485,8 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back("-iquote");
} else if (E.Group == frontend::System) {
Res.push_back("-isystem");
+ } else if (E.Group == frontend::CXXSystem) {
+ Res.push_back("-cxx-isystem");
} else {
assert(E.Group == frontend::Angled && "Invalid group!");
Res.push_back(E.IsFramework ? "-F" : "-I");
@@ -588,10 +585,12 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-faltivec");
if (Opts.Exceptions)
Res.push_back("-fexceptions");
+ if (Opts.ObjCExceptions)
+ Res.push_back("-fobjc-exceptions");
+ if (Opts.CXXExceptions)
+ Res.push_back("-fcxx-exceptions");
if (Opts.SjLjExceptions)
Res.push_back("-fsjlj-exceptions");
- if (!Opts.ObjCExceptions)
- Res.push_back("-fno-objc-exceptions");
if (!Opts.RTTI)
Res.push_back("-fno-rtti");
if (Opts.MSBitfields)
@@ -862,6 +861,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalysisDiagOpt = Value;
}
+ Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
@@ -876,8 +876,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors);
Opts.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers);
Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
- Opts.EnableExperimentalInternalChecks =
- Args.hasArg(OPT_analyzer_experimental_internal_checks);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
@@ -892,8 +890,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
const Arg *A = *it;
A->claim();
bool enable = (A->getOption().getID() == OPT_analyzer_checker);
- Opts.CheckersControlList.push_back(std::make_pair(A->getValue(Args),
- enable));
+ // We can have a list of comma separated checker names, e.g:
+ // '-analyzer-checker=cocoa,unix'
+ llvm::StringRef checkerList = A->getValue(Args);
+ llvm::SmallVector<llvm::StringRef, 4> checkers;
+ checkerList.split(checkers, ",");
+ for (unsigned i = 0, e = checkers.size(); i != e; ++i)
+ Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
}
}
@@ -1236,7 +1239,6 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
using namespace cc1options;
- Opts.CXXSystemIncludes = Args.getAllArgValues(OPT_cxx_system_include);
Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
@@ -1272,10 +1274,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, true);
- for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot),
- ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::System, true, false,
- (*it)->getOption().matches(OPT_iwithsysroot));
+ for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem, OPT_isystem,
+ OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args),
+ ((*it)->getOption().matches(OPT_cxx_isystem) ?
+ frontend::CXXSystem : frontend::System),
+ true, false, (*it)->getOption().matches(OPT_iwithsysroot));
// FIXME: Need options for the various environment variables!
}
@@ -1457,7 +1461,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_threadsafe_statics))
Opts.ThreadsafeStatics = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
- Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions);
+ Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions);
+ Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions);
+ Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
+
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
@@ -1486,8 +1493,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
- Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
- Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
@@ -1658,8 +1663,11 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags);
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
- if (DashX != IK_AST && DashX != IK_LLVM_IR)
+ if (DashX != IK_AST && DashX != IK_LLVM_IR) {
ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
+ if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
+ Res.getLangOpts().ObjCExceptions = 1;
+ }
// FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of
// PCH file and find the original header name. Remove the need to do that in
// ParsePreprocessorArgs and remove the FileManager
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index b24ece5..a09db0b 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -14,6 +14,7 @@
#include "clang/Frontend/DocumentXML.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
@@ -218,6 +219,10 @@ void DocumentXML::addPtrAttribute(const char* pAttributeName,
addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
break;
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias());
+ break;
+ }
case NestedNameSpecifier::TypeSpec: {
addPtrAttribute(pAttributeName, pNNS->getAsType());
break;
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 4855b62..2e3162c 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -42,7 +42,9 @@ namespace {
/// a HeaderSearch object. InitHeaderSearch stores several search path lists
/// internally, which can be sent to a HeaderSearch object in one swoop.
class InitHeaderSearch {
- std::vector<DirectoryLookup> IncludeGroup[4];
+ std::vector<std::pair<IncludeDirGroup, DirectoryLookup> > IncludePath;
+ typedef std::vector<std::pair<IncludeDirGroup,
+ DirectoryLookup> >::const_iterator path_iterator;
HeaderSearch& Headers;
bool Verbose;
std::string IncludeSysroot;
@@ -94,7 +96,7 @@ public:
/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
- void Realize();
+ void Realize(const LangOptions &Lang);
};
}
@@ -131,8 +133,8 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
// If the directory exists, add it.
if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) {
- IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
- isFramework));
+ IncludePath.push_back(std::make_pair(Group, DirectoryLookup(DE, Type,
+ isUserSupplied, isFramework)));
return;
}
@@ -142,7 +144,8 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
if (const FileEntry *FE = FM.getFile(MappedPathStr)) {
if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
// It is a headermap, add it to the search path.
- IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
+ IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type,
+ isUserSupplied)));
return;
}
}
@@ -179,29 +182,29 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef Dir64,
const llvm::Triple &triple) {
// Add the base dir
- AddPath(Base, System, true, false, false);
+ AddPath(Base, CXXSystem, true, false, false);
// Add the multilib dirs
llvm::Triple::ArchType arch = triple.getArch();
bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
if (is64bit)
- AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, true, false, false);
else
- AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, true, false, false);
// Add the backward dir
- AddPath(Base + "/backward", System, true, false, false);
+ AddPath(Base + "/backward", CXXSystem, true, false, false);
}
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef Arch,
llvm::StringRef Version) {
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
- System, true, false, false);
+ CXXSystem, true, false, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
- System, true, false, false);
+ CXXSystem, true, false, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
- System, true, false, false);
+ CXXSystem, true, false, false);
}
// FIXME: This probably should goto to some platform utils place.
@@ -567,13 +570,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
break;
case llvm::Triple::MinGW32:
// mingw-w64-20110207
- AddPath("c:/MinGW/include/c++/4.5.3", System, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", System, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.3/backward", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.3", CXXSystem, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", CXXSystem, true,
+ false, false);
+ AddPath("c:/MinGW/include/c++/4.5.3/backward", CXXSystem, true, false,
+ false);
// mingw-w64-20101129
- AddPath("c:/MinGW/include/c++/4.5.2", System, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", System, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.2/backward", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.2", CXXSystem, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", CXXSystem, true,
+ false, false);
+ AddPath("c:/MinGW/include/c++/4.5.2/backward", CXXSystem, true, false,
+ false);
// Try gcc 4.5.0
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
// Try gcc 4.4.0
@@ -613,7 +620,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
}
break;
case llvm::Triple::DragonFly:
- AddPath("/usr/include/c++/4.1", System, true, false, false);
+ AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
break;
case llvm::Triple::Linux:
//===------------------------------------------------------------------===//
@@ -809,13 +816,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) {
- if (!HSOpts.CXXSystemIncludes.empty()) {
- for (unsigned i = 0, e = HSOpts.CXXSystemIncludes.size(); i != e; ++i)
- AddPath(HSOpts.CXXSystemIncludes[i], System, true, false, false);
- } else
- AddDefaultCPlusPlusIncludePaths(triple);
- }
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes)
+ AddDefaultCPlusPlusIncludePaths(triple);
AddDefaultCIncludePaths(triple, HSOpts);
@@ -829,11 +831,11 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
/// RemoveDuplicates - If there are duplicate directory entries in the specified
/// search list, remove the later (dead) ones.
static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
- bool Verbose) {
+ unsigned First, bool Verbose) {
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
- for (unsigned i = 0; i != SearchList.size(); ++i) {
+ for (unsigned i = First; i != SearchList.size(); ++i) {
unsigned DirToRemove = i;
const DirectoryLookup &CurEntry = SearchList[i];
@@ -908,32 +910,49 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
}
-void InitHeaderSearch::Realize() {
+void InitHeaderSearch::Realize(const LangOptions &Lang) {
// Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
std::vector<DirectoryLookup> SearchList;
- SearchList = IncludeGroup[Angled];
- SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
- IncludeGroup[System].end());
- SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
- IncludeGroup[After].end());
- RemoveDuplicates(SearchList, Verbose);
- RemoveDuplicates(IncludeGroup[Quoted], Verbose);
+ SearchList.reserve(IncludePath.size());
+
+ /* Quoted arguments go first. */
+ for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
+ it != ie; ++it) {
+ if (it->first == Quoted)
+ SearchList.push_back(it->second);
+ }
+ /* Deduplicate and remember index */
+ RemoveDuplicates(SearchList, 0, Verbose);
+ unsigned quoted = SearchList.size();
+
+ for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
+ it != ie; ++it) {
+ if (it->first == Angled)
+ SearchList.push_back(it->second);
+ }
- // Prepend QUOTED list on the search list.
- SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
- IncludeGroup[Quoted].end());
+ for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
+ it != ie; ++it) {
+ if (it->first == System || (Lang.CPlusPlus && it->first == CXXSystem))
+ SearchList.push_back(it->second);
+ }
+
+ for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
+ it != ie; ++it) {
+ if (it->first == After)
+ SearchList.push_back(it->second);
+ }
+ RemoveDuplicates(SearchList, quoted, Verbose);
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
- Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
- DontSearchCurDir);
+ Headers.SetSearchPaths(SearchList, quoted, DontSearchCurDir);
// If verbose, print the list of directories that will be searched.
if (Verbose) {
llvm::errs() << "#include \"...\" search starts here:\n";
- unsigned QuotedIdx = IncludeGroup[Quoted].size();
for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
- if (i == QuotedIdx)
+ if (i == quoted)
llvm::errs() << "#include <...> search starts here:\n";
const char *Name = SearchList[i].getName();
const char *Suffix;
@@ -978,5 +997,5 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
if (HSOpts.UseStandardIncludes)
Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts);
- Init.Realize();
+ Init.Realize(Lang);
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index d0111a5..91b5280 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -48,12 +48,13 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
}
}
-std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
+std::string clang::NormalizeDashIncludePath(llvm::StringRef File,
+ FileManager &FileMgr) {
// Implicit include paths should be resolved relative to the current
// working directory first, and then use the regular header search
// mechanism. The proper way to handle this is to have the
// predefines buffer located at the current working directory, but
- // it has not file entry. For now, workaround this by using an
+ // it has no file entry. For now, workaround this by using an
// absolute path if we find the file here, and otherwise letting
// header search handle it.
llvm::SmallString<128> Path(File);
@@ -61,21 +62,25 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
bool exists;
if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
Path = File;
+ else if (exists)
+ FileMgr.getFile(File);
return Lexer::Stringify(Path.str());
}
/// AddImplicitInclude - Add an implicit #include of the specified file to the
/// predefines buffer.
-static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) {
+static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File,
+ FileManager &FileMgr) {
Builder.append("#include \"" +
- llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
+ llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
}
static void AddImplicitIncludeMacros(MacroBuilder &Builder,
- llvm::StringRef File) {
+ llvm::StringRef File,
+ FileManager &FileMgr) {
Builder.append("#__include_macros \"" +
- llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
+ llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
// Marker token to stop the __include_macros fetch loop.
Builder.append("##"); // ##?
}
@@ -94,7 +99,7 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
return;
}
- AddImplicitInclude(Builder, OriginalFile);
+ AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
}
/// PickFP - This is used to pick a value based on the FP semantics of the
@@ -169,15 +174,10 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
llvm::StringRef ValSuffix, bool isSigned,
- MacroBuilder& Builder) {
- long long MaxVal;
- if (isSigned) {
- assert(TypeWidth != 1);
- MaxVal = ~0ULL >> (65-TypeWidth);
- } else
- MaxVal = ~0ULL >> (64-TypeWidth);
-
- Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix);
+ MacroBuilder &Builder) {
+ llvm::APInt MaxVal = isSigned ? llvm::APInt::getSignedMaxValue(TypeWidth)
+ : llvm::APInt::getMaxValue(TypeWidth);
+ Builder.defineMacro(MacroName, MaxVal.toString(10, isSigned) + ValSuffix);
}
/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
@@ -590,7 +590,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// If -imacros are specified, include them now. These are processed before
// any -include directives.
for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
- AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]);
+ AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i],
+ PP.getFileManager());
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
@@ -598,7 +599,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
if (Path == InitOpts.ImplicitPTHInclude)
AddImplicitIncludePTH(Builder, PP, Path);
else
- AddImplicitInclude(Builder, Path);
+ AddImplicitInclude(Builder, Path, PP.getFileManager());
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 04c6a68..0849153 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -905,9 +905,21 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
std::string OptionName;
if (DiagOpts->ShowOptionNames) {
+ // Was this a warning mapped to an error using -Werror or pragma?
+ if (Level == Diagnostic::Error &&
+ DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID())) {
+ diag::Mapping mapping = diag::MAP_IGNORE;
+ Info.getDiags()->getDiagnosticLevel(Info.getID(), Info.getLocation(),
+ &mapping);
+ if (mapping == diag::MAP_WARNING)
+ OptionName += "-Werror";
+ }
+
if (const char *
Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) {
- OptionName = "-W";
+ if (!OptionName.empty())
+ OptionName += ',';
+ OptionName += "-W";
OptionName += Opt;
} else if (Info.getID() == diag::fatal_too_many_errors) {
OptionName = "-ferror-limit=";
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
index 51b351f..fff417e 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -369,7 +369,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
if (I->first.isInvalid() || !SourceMgr)
OS << "\n (frontend)";
else
- OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first);
+ OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first);
OS << ": " << I->second;
}
@@ -391,7 +391,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
if (D.Location.isInvalid() || !SourceMgr)
OS << "\n (frontend)";
else
- OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location);
+ OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location);
OS << ": " << D.Text;
}
@@ -413,12 +413,12 @@ static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
Directive& D = **I;
- unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location);
+ unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location);
for (unsigned i = 0; i < D.Count; ++i) {
DiagList::iterator II, IE;
for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
if (LineNo1 != LineNo2)
continue;
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 4bb85e7..65fad6d 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -108,6 +108,12 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
return 0;
}
+ // Honor -analyzer-checker-help.
+ if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
+ ento::printCheckerHelp(llvm::outs());
+ return 0;
+ }
+
// Honor -version.
//
// FIXME: Use a better -version message?
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index eef541e..1e9eacc 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -28,8 +28,8 @@ if(MSVC_IDE OR XCODE)
endif()
# Generate arm_neon.h
-set(LLVM_TARGET_DEFINITIONS ${CLANG_SOURCE_DIR}/include/clang/Basic/arm_neon.td)
-tablegen(arm_neon.h.inc -gen-arm-neon)
+clang_tablegen(arm_neon.h.inc -gen-arm-neon
+ SOURCE ${CLANG_SOURCE_DIR}/include/clang/Basic/arm_neon.td)
set(out_files)
foreach( f ${files} )
@@ -67,6 +67,7 @@ if (other_output_dir)
endif ()
add_custom_target(clang-headers ALL DEPENDS ${out_files})
+set_target_properties(clang-headers PROPERTIES FOLDER "Misc")
install(FILES ${files} ${output_dir}/arm_neon.h
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 0f0d25b..3e871ae 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -86,6 +86,7 @@ void Preprocessor::DiscardUntilEndOfDirective() {
Token Tmp;
do {
LexUnexpandedToken(Tmp);
+ assert(Tmp.isNot(tok::eof) && "EOF seen while discarding directive tokens");
} while (Tmp.isNot(tok::eom));
}
@@ -167,10 +168,12 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
if (Tmp.isNot(tok::eom)) {
// Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
- // because it is more trouble than it is worth to insert /**/ and check that
- // there is no /**/ in the range also.
+ // or if this is a macro-style preprocessing directive, because it is more
+ // trouble than it is worth to insert /**/ and check that there is no /**/
+ // in the range also.
FixItHint Hint;
- if (Features.GNUMode || Features.C99 || Features.CPlusPlus)
+ if ((Features.GNUMode || Features.C99 || Features.CPlusPlus) &&
+ !CurTokenLexer)
Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//");
Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint;
DiscardUntilEndOfDirective();
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index f0475bc..80d3bb1 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -110,7 +110,8 @@ void Preprocessor::HandlePragmaDirective(unsigned Introducer) {
PragmaHandlers->HandlePragma(*this, PragmaIntroducerKind(Introducer), Tok);
// If the pragma handler didn't read the rest of the line, consume it now.
- if (CurPPLexer && CurPPLexer->ParsingPreprocessorDirective)
+ if ((CurTokenLexer && CurTokenLexer->isParsingPreprocessorDirective())
+ || (CurPPLexer && CurPPLexer->ParsingPreprocessorDirective))
DiscardUntilEndOfDirective();
}
@@ -174,7 +175,22 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
}
}
- Handle_Pragma(PIK__Pragma, StrVal, PragmaLoc, RParenLoc);
+ // Plop the string (including the newline and trailing null) into a buffer
+ // where we can lex it.
+ Token TmpTok;
+ TmpTok.startToken();
+ CreateString(&StrVal[0], StrVal.size(), TmpTok);
+ SourceLocation TokLoc = TmpTok.getLocation();
+
+ // Make and enter a lexer object so that we lex and expand the tokens just
+ // like any others.
+ Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc,
+ StrVal.size(), *this);
+
+ EnterSourceFileWithLexer(TL, 0);
+
+ // With everything set up, lex this as a #pragma directive.
+ HandlePragmaDirective(PIK__Pragma);
// Finally, return whatever came after the pragma directive.
return Lex(Tok);
@@ -193,16 +209,16 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
return;
}
- // Get the tokens enclosed within the __pragma().
+ // Get the tokens enclosed within the __pragma(), as well as the final ')'.
llvm::SmallVector<Token, 32> PragmaToks;
int NumParens = 0;
Lex(Tok);
while (Tok.isNot(tok::eof)) {
+ PragmaToks.push_back(Tok);
if (Tok.is(tok::l_paren))
NumParens++;
else if (Tok.is(tok::r_paren) && NumParens-- == 0)
break;
- PragmaToks.push_back(Tok);
Lex(Tok);
}
@@ -211,45 +227,23 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
return;
}
- // Build the pragma string.
- std::string StrVal = " ";
- for (llvm::SmallVector<Token, 32>::iterator I =
- PragmaToks.begin(), E = PragmaToks.end(); I != E; ++I) {
- StrVal += getSpelling(*I);
- }
-
- SourceLocation RParenLoc = Tok.getLocation();
-
- Handle_Pragma(PIK___pragma, StrVal, PragmaLoc, RParenLoc);
+ PragmaToks.front().setFlag(Token::LeadingSpace);
- // Finally, return whatever came after the pragma directive.
- return Lex(Tok);
-}
+ // Replace the ')' with an EOM to mark the end of the pragma.
+ PragmaToks.back().setKind(tok::eom);
-void Preprocessor::Handle_Pragma(unsigned Introducer,
- const std::string &StrVal,
- SourceLocation PragmaLoc,
- SourceLocation RParenLoc) {
+ Token *TokArray = new Token[PragmaToks.size()];
+ std::copy(PragmaToks.begin(), PragmaToks.end(), TokArray);
- // Plop the string (including the newline and trailing null) into a buffer
- // where we can lex it.
- Token TmpTok;
- TmpTok.startToken();
- CreateString(&StrVal[0], StrVal.size(), TmpTok);
- SourceLocation TokLoc = TmpTok.getLocation();
-
- // Make and enter a lexer object so that we lex and expand the tokens just
- // like any others.
- Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc,
- StrVal.size(), *this);
-
- EnterSourceFileWithLexer(TL, 0);
+ // Push the tokens onto the stack.
+ EnterTokenStream(TokArray, PragmaToks.size(), true, true);
// With everything set up, lex this as a #pragma directive.
- HandlePragmaDirective(Introducer);
-}
-
+ HandlePragmaDirective(PIK___pragma);
+ // Finally, return whatever came after the pragma directive.
+ return Lex(Tok);
+}
/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'.
///
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index ea39b47..caa44bf 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -543,6 +543,11 @@ unsigned TokenLexer::isNextTokenLParen() const {
return Tokens[CurToken].is(tok::l_paren);
}
+/// isParsingPreprocessorDirective - Return true if we are in the middle of a
+/// preprocessor directive.
+bool TokenLexer::isParsingPreprocessorDirective() const {
+ return Tokens[NumTokens-1].is(tok::eom) && !isAtEnd();
+}
/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
/// together to form a comment that comments out everything in the current
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5a7fc7e..077edd7 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -667,6 +667,8 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
}
+ Actions.FinalizeDeclaration(ThisDecl);
+
return ThisDecl;
}
@@ -954,8 +956,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
CXXScopeSpec SS;
- SS.setScopeRep((NestedNameSpecifier*) Tok.getAnnotationValue());
- SS.setRange(Tok.getAnnotationRange());
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(),
+ SS);
// We are looking for a qualified typename.
Token Next = NextToken();
@@ -1244,9 +1247,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DiagID, getLang());
break;
case tok::kw_auto:
- if (getLang().CPlusPlus0x)
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
- DiagID);
+ if (getLang().CPlusPlus0x || getLang().ObjC2) {
+ if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
+ DiagID, getLang());
+ if (!isInvalid)
+ Diag(Tok, diag::auto_storage_class)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ }
+ else
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
+ DiagID);
+ }
else
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
DiagID, getLang());
@@ -1459,6 +1471,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
else
Diag(Tok, DiagID) << PrevSpec;
}
+
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
}
@@ -1973,6 +1986,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
}
+ bool AllowFixedUnderlyingType = getLang().CPlusPlus0x || getLang().Microsoft;
bool IsScopedEnum = false;
bool IsScopedUsingClassTag = false;
@@ -1984,7 +1998,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
// Must have either 'enum name' or 'enum {...}'.
- if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
+ (AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {
Diag(Tok, diag::err_expected_ident_lbrace);
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -2011,7 +2026,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TypeResult BaseType;
// Parse the fixed underlying type.
- if (getLang().CPlusPlus0x && Tok.is(tok::colon)) {
+ if (AllowFixedUnderlyingType && Tok.is(tok::colon)) {
bool PossibleBitfield = false;
if (getCurScope()->getFlags() & Scope::ClassScope) {
// If we're in class scope, this can either be an enum declaration with
@@ -2043,7 +2058,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Consume the ':'.
ConsumeToken();
- if (isCXXDeclarationSpecifier() != TPResult::True()) {
+ if ((getLang().CPlusPlus &&
+ isCXXDeclarationSpecifier() != TPResult::True()) ||
+ (!getLang().CPlusPlus && !isDeclarationSpecifier(true))) {
// We'll parse this as a bitfield later.
PossibleBitfield = true;
TPA.Revert();
@@ -2060,6 +2077,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!PossibleBitfield) {
SourceRange Range;
BaseType = ParseTypeName(&Range);
+
+ if (!getLang().CPlusPlus0x)
+ Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
+ << Range;
}
}
@@ -2090,6 +2111,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
+ if (!Name && TUK != Sema::TUK_Definition) {
+ Diag(Tok, diag::err_enumerator_unnamed_no_def);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
bool Owned = false;
bool IsDependent = false;
SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
@@ -2734,6 +2763,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (Kind == tok::star)
// Remember that we parsed a pointer type, and remember the type-quals.
D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
+ DS.getConstSpecLoc(),
+ DS.getVolatileSpecLoc(),
+ DS.getRestrictSpecLoc(),
DS.takeAttributes()),
SourceLocation());
else
@@ -3730,4 +3762,3 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
}
return false;
}
-
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index e73578f..d8db711 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -65,8 +65,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
- SS.setScopeRep(static_cast<NestedNameSpecifier*>(Tok.getAnnotationValue()));
- SS.setRange(Tok.getAnnotationRange());
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(),
+ SS);
ConsumeToken();
return false;
}
@@ -80,10 +81,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
// '::' - Global scope qualifier.
- SourceLocation CCLoc = ConsumeToken();
- SS.setBeginLoc(CCLoc);
- SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), CCLoc));
- SS.setEndLoc(CCLoc);
+ if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS))
+ return true;
+
HasScopeSpecifier = true;
}
@@ -208,20 +208,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
- if (!HasScopeSpecifier) {
- SS.setBeginLoc(TypeToken.getLocation());
+ if (!HasScopeSpecifier)
HasScopeSpecifier = true;
- }
if (ParsedType T = getTypeAnnotation(TypeToken)) {
- CXXScopeTy *Scope =
- Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, T,
- TypeToken.getAnnotationRange(),
- CCLoc);
- SS.setScopeRep(Scope);
- } else
- SS.setScopeRep(0);
- SS.setEndLoc(CCLoc);
+ if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS))
+ SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc));
+
+ continue;
+ } else {
+ SourceLocation Start = SS.getBeginLoc().isValid()? SS.getBeginLoc()
+ : CCLoc;
+ SS.SetInvalid(SourceRange(Start, CCLoc));
+ }
+
continue;
}
@@ -245,7 +245,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// If we get foo:bar, this is almost certainly a typo for foo::bar. Recover
// and emit a fixit hint for it.
if (Next.is(tok::colon) && !ColonIsSacred) {
- if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, ObjectType,
+ if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II,
+ Tok.getLocation(),
+ Next.getLocation(), ObjectType,
EnteringContext) &&
// If the token after the colon isn't an identifier, it's still an
// error, but they probably meant something else strange so don't
@@ -274,16 +276,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
"NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
- if (!HasScopeSpecifier) {
- SS.setBeginLoc(IdLoc);
- HasScopeSpecifier = true;
- }
-
- if (!SS.isInvalid())
- SS.setScopeRep(
- Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, IdLoc, CCLoc, II,
- ObjectType, EnteringContext));
- SS.setEndLoc(CCLoc);
+ HasScopeSpecifier = true;
+ if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
+ ObjectType, EnteringContext, SS))
+ SS.SetInvalid(SourceRange(IdLoc, CCLoc));
+
continue;
}
@@ -836,6 +833,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// FIXME: Build a reference to this declaration? Convert it to bool?
// (This is currently handled by Sema).
+
+ Actions.FinalizeDeclaration(DeclOut);
return false;
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 8387c88..59ced8b 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -829,7 +829,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateId->RAngleLoc = RAngleLoc;
ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
- Args[Arg] = TemplateArgs[Arg];
+ Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a50763a..07e592c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -296,6 +296,10 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
case tok::wide_string_literal:
ConsumeStringToken();
break;
+
+ case tok::at:
+ return false;
+
case tok::semi:
if (StopAtSemi)
return false;
@@ -1159,7 +1163,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
else
PP.EnterToken(Tok);
Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
Tok.setAnnotationRange(SS.getRange());
// In case the tokens were cached, have Preprocessor replace them
@@ -1196,7 +1200,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
else
PP.EnterToken(Tok);
Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
Tok.setAnnotationRange(SS.getRange());
// In case the tokens were cached, have Preprocessor replace them with the
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 875a0c7..0263f65 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -298,6 +298,7 @@ namespace {
Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SourceLocation OrigEnd);
+ bool IsDeclStmtInForeachHeader(DeclStmt *DS);
CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
Expr **args, unsigned nargs,
SourceLocation StartLoc=SourceLocation(),
@@ -1348,13 +1349,13 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
MsgExpr = ObjCMessageExpr::Create(*Context,
Ty.getNonReferenceType(),
Expr::getValueKindForType(Ty),
- /*FIXME?*/SourceLocation(),
+ PropOrGetterRefExpr->getLocStart(),
SuperLocation,
/*IsInstanceSuper=*/true,
SuperTy,
Sel, SelectorLoc, OMD,
0, 0,
- /*FIXME:*/SourceLocation());
+ PropOrGetterRefExpr->getLocEnd());
else {
assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null");
if (Expr *Exp = dyn_cast<Expr>(Receiver))
@@ -1364,14 +1365,15 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
MsgExpr = ObjCMessageExpr::Create(*Context,
Ty.getNonReferenceType(),
Expr::getValueKindForType(Ty),
- /*FIXME:*/SourceLocation(),
+ PropOrGetterRefExpr->getLocStart(),
cast<Expr>(Receiver),
Sel, SelectorLoc, OMD,
0, 0,
- /*FIXME:*/SourceLocation());
+ PropOrGetterRefExpr->getLocEnd());
}
- Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
+ Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr, MsgExpr->getLocStart(),
+ MsgExpr->getLocEnd());
if (!PropParentMap)
PropParentMap = new ParentMap(CurrentBody);
@@ -2986,9 +2988,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Make all implicit casts explicit...ICE comes in handy:-)
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
// Reuse the ICE type, it is exactly what the doctor ordered.
- QualType type = ICE->getType()->isObjCQualifiedIdType()
- ? Context->getObjCIdType()
- : ICE->getType();
+ QualType type = ICE->getType();
+ if (needToScanForQualifiers(type))
+ type = Context->getObjCIdType();
// Make sure we convert "type (^)(...)" to "type (*)(...)".
(void)convertBlockPointerToFunctionPointer(type);
userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK_BitCast,
@@ -5459,6 +5461,13 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
return NewRep;
}
+bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
+ if (const ObjCForCollectionStmt * CS =
+ dyn_cast<ObjCForCollectionStmt>(Stmts.back()))
+ return CS->getElement() == DS;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Function Body / Expression rewriting
//===----------------------------------------------------------------------===//
@@ -5681,7 +5690,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// for (id <FooProtocol> index in someArray) ;
// This is because RewriteObjCForCollectionStmt() does textual rewriting
// and it depends on the original text locations/positions.
- if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS))
RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
// Blocks rewrite rules.
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 63f561d..6a42224 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/DeclObjC.h"
@@ -26,6 +27,8 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValuesV2.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Casting.h"
@@ -289,7 +292,7 @@ struct CheckFallThroughDiagnostics {
/// of a noreturn function. We assume that functions and blocks not marked
/// noreturn will return.
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
- QualType BlockTy,
+ const BlockExpr *blkExpr,
const CheckFallThroughDiagnostics& CD,
AnalysisContext &AC) {
@@ -306,6 +309,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
+ QualType BlockTy = blkExpr->getType();
if (const FunctionType *FT =
BlockTy->getPointeeType()->getAs<FunctionType>()) {
if (FT->getResultType()->isVoidType())
@@ -477,11 +481,20 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
Diagnostic::Ignored);
}
+static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
+ for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ i = fscope->PossiblyUnreachableDiags.begin(),
+ e = fscope->PossiblyUnreachableDiags.end();
+ i != e; ++i) {
+ const sema::PossiblyUnreachableDiag &D = *i;
+ S.Diag(D.Loc, D.PD);
+ }
+}
+
void clang::sema::
AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const Decl *D, QualType BlockTy) {
-
- assert(BlockTy.isNull() || isa<BlockDecl>(D));
+ sema::FunctionScopeInfo *fscope,
+ const Decl *D, const BlockExpr *blkExpr) {
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
@@ -491,9 +504,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// time.
Diagnostic &Diags = S.getDiagnostics();
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
- return;
-
// Do not do any analysis for declarations in system headers if we are
// going to just ignore them.
if (Diags.getSuppressSystemWarnings() &&
@@ -504,6 +514,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (cast<DeclContext>(D)->isDependentContext())
return;
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) {
+ // Flush out any possibly unreachable diagnostics.
+ flushDiagnostics(S, fscope);
+ return;
+ }
+
const Stmt *Body = D->getBody();
assert(Body);
@@ -512,12 +528,40 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false,
/*addImplicitDtors=*/true, /*addInitializers=*/true);
+ // Emit delayed diagnostics.
+ if (!fscope->PossiblyUnreachableDiags.empty()) {
+ bool analyzed = false;
+ if (CFGReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis())
+ if (CFGStmtMap *csm = AC.getCFGStmtMap()) {
+ analyzed = true;
+ for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ i = fscope->PossiblyUnreachableDiags.begin(),
+ e = fscope->PossiblyUnreachableDiags.end();
+ i != e; ++i) {
+ const sema::PossiblyUnreachableDiag &D = *i;
+ if (const CFGBlock *blk = csm->getBlock(D.stmt)) {
+ // Can this block be reached from the entrance?
+ if (cra->isReachable(&AC.getCFG()->getEntry(), blk))
+ S.Diag(D.Loc, D.PD);
+ }
+ else {
+ // Emit the warning anyway if we cannot map to a basic block.
+ S.Diag(D.Loc, D.PD);
+ }
+ }
+ }
+
+ if (!analyzed)
+ flushDiagnostics(S, fscope);
+ }
+
+
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
: CheckFallThroughDiagnostics::MakeForFunction(D));
- CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+ CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
}
// Warning: check for unreachable code
@@ -550,21 +594,3 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
}
-
-void clang::sema::
-AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const BlockExpr *E) {
- return IssueWarnings(P, E->getBlockDecl(), E->getType());
-}
-
-void clang::sema::
-AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const ObjCMethodDecl *D) {
- return IssueWarnings(P, D, QualType());
-}
-
-void clang::sema::
-AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const FunctionDecl *D) {
- return IssueWarnings(P, D, QualType());
-}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index bc289ec..037594a 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -14,6 +14,9 @@
#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
@@ -44,6 +47,239 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
EndLocation = TemplateId->RAngleLoc;
}
+CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &Other)
+ : Range(Other.Range), ScopeRep(Other.ScopeRep), Buffer(0),
+ BufferSize(Other.BufferSize), BufferCapacity(Other.BufferSize)
+{
+ if (BufferSize) {
+ Buffer = static_cast<char *>(malloc(BufferSize));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ }
+}
+
+CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &Other) {
+ Range = Other.Range;
+ ScopeRep = Other.ScopeRep;
+ if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
+ // Re-use our storage.
+ BufferSize = Other.BufferSize;
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ return *this;
+ }
+
+ if (BufferCapacity)
+ free(Buffer);
+ if (Other.Buffer) {
+ BufferSize = Other.BufferSize;
+ BufferCapacity = BufferSize;
+ Buffer = static_cast<char *>(malloc(BufferSize));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ } else {
+ Buffer = 0;
+ BufferSize = 0;
+ BufferCapacity = 0;
+ }
+ return *this;
+}
+
+CXXScopeSpec::~CXXScopeSpec() {
+ if (BufferCapacity)
+ free(Buffer);
+}
+
+namespace {
+ void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ if (BufferSize + (End - Start) > BufferCapacity) {
+ // Reallocate the buffer.
+ unsigned NewCapacity
+ = std::max((unsigned)(BufferCapacity? BufferCapacity * 2
+ : sizeof(void*) * 2),
+ (unsigned)(BufferSize + (End - Start)));
+ char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
+ memcpy(NewBuffer, Buffer, BufferSize);
+
+ if (BufferCapacity)
+ free(Buffer);
+ Buffer = NewBuffer;
+ BufferCapacity = NewCapacity;
+ }
+
+ memcpy(Buffer + BufferSize, Start, End - Start);
+ BufferSize += End-Start;
+ }
+
+ /// \brief Save a source location to the given buffer.
+ void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
+ unsigned &BufferSize, unsigned &BufferCapacity) {
+ unsigned Raw = Loc.getRawEncoding();
+ Append(reinterpret_cast<char *>(&Raw),
+ reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
+ Buffer, BufferSize, BufferCapacity);
+ }
+
+ /// \brief Save a pointer to the given buffer.
+ void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ Append(reinterpret_cast<char *>(&Ptr),
+ reinterpret_cast<char *>(&Ptr) + sizeof(void *),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc,
+ TypeLoc TL, SourceLocation ColonColonLoc) {
+ ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep,
+ TemplateKWLoc.isValid(),
+ TL.getTypePtr());
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(TL.getBeginLoc());
+ Range.setEnd(ColonColonLoc);
+
+ // Push source-location info into the buffer.
+ SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+ assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation ColonColonLoc) {
+ ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Identifier);
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(IdentifierLoc);
+ Range.setEnd(ColonColonLoc);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+ assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace,
+ SourceLocation NamespaceLoc,
+ SourceLocation ColonColonLoc) {
+ ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Namespace);
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(NamespaceLoc);
+ Range.setEnd(ColonColonLoc);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+ assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
+ SourceLocation AliasLoc,
+ SourceLocation ColonColonLoc) {
+ ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Alias);
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(AliasLoc);
+ Range.setEnd(ColonColonLoc);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+ assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::MakeGlobal(ASTContext &Context,
+ SourceLocation ColonColonLoc) {
+ assert(!ScopeRep && "Already have a nested-name-specifier!?");
+ ScopeRep = NestedNameSpecifier::GlobalSpecifier(Context);
+ Range = SourceRange(ColonColonLoc);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+ assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::MakeTrivial(ASTContext &Context,
+ NestedNameSpecifier *Qualifier, SourceRange R) {
+ ScopeRep = Qualifier;
+ Range = R;
+
+ // Construct bogus (but well-formed) source information for the
+ // nested-name-specifier.
+ BufferSize = 0;
+ llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
+ for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
+ Stack.push_back(NNS);
+ while (!Stack.empty()) {
+ NestedNameSpecifier *NNS = Stack.back();
+ Stack.pop_back();
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ TypeSourceInfo *TSInfo
+ = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
+ R.getBegin());
+ SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
+ BufferCapacity);
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ break;
+ }
+
+ // Save the location of the '::'.
+ SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+
+void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
+ if (!Other) {
+ Range = SourceRange();
+ ScopeRep = 0;
+ return;
+ }
+
+ if (BufferCapacity)
+ free(Buffer);
+
+ // Rather than copying the data (which is wasteful), "adopt" the
+ // pointer (which points into the ASTContext) but set the capacity to zero to
+ // indicate that we don't own it.
+ Range = Other.getSourceRange();
+ ScopeRep = Other.getNestedNameSpecifier();
+ Buffer = static_cast<char *>(Other.getOpaqueData());
+ BufferSize = Other.getDataLength();
+ BufferCapacity = 0;
+}
+
+NestedNameSpecifierLoc
+CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
+ if (isEmpty() || isInvalid())
+ return NestedNameSpecifierLoc();
+
+ // If we adopted our data pointer from elsewhere in the AST context, there's
+ // no need to copy the memory.
+ if (BufferCapacity == 0)
+ return NestedNameSpecifierLoc(ScopeRep, Buffer);
+
+ void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
+ memcpy(Mem, Buffer, BufferSize);
+ return NestedNameSpecifierLoc(ScopeRep, Mem);
+}
+
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs,
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 23a3c24..0c39e13 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -48,6 +48,7 @@ void FunctionScopeInfo::Clear() {
SwitchStack.clear();
Returns.clear();
ErrorTrap.reset();
+ PossiblyUnreachableDiags.clear();
}
BlockScopeInfo::~BlockScopeInfo() { }
@@ -466,6 +467,12 @@ void Sema::ActOnEndOfTranslationUnit() {
checkUndefinedInternals(*this);
}
+ // Check we've noticed that we're no longer parsing the initializer for every
+ // variable. If we miss cases, then at best we have a performance issue and
+ // at worst a rejects-valid bug.
+ assert(ParsingInitForAutoVars.empty() &&
+ "Didn't unmark var as having its initializer parsed");
+
TUScope = 0;
}
@@ -625,11 +632,27 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PopFunctionOrBlockScope() {
- FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
+void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
+ const Decl *D, const BlockExpr *blkExpr) {
+ FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
- if (FunctionScopes.back() != Scope)
+
+ // Issue any analysis-based warnings.
+ if (WP && D)
+ AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
+ else {
+ for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ i = Scope->PossiblyUnreachableDiags.begin(),
+ e = Scope->PossiblyUnreachableDiags.end();
+ i != e; ++i) {
+ const sema::PossiblyUnreachableDiag &D = *i;
+ Diag(D.Loc, D.PD);
+ }
+ }
+
+ if (FunctionScopes.back() != Scope) {
delete Scope;
+ }
}
/// \brief Determine whether any errors occurred within this function/method/
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index aa0efcd..7ad4b45 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
+#include "TypeLocBuilder.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -138,6 +139,9 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
case NestedNameSpecifier::Namespace:
return NNS->getAsNamespace();
+ case NestedNameSpecifier::NamespaceAlias:
+ return NNS->getAsNamespaceAlias()->getNamespace();
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
@@ -219,7 +223,7 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
Context.getTypeDeclType(Tag),
PDiag(diag::err_incomplete_nested_name_spec)
<< SS.getRange())) {
- SS.setScopeRep(0); // Mark the ScopeSpec invalid.
+ SS.SetInvalid(SS.getRange());
return true;
}
}
@@ -227,11 +231,10 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
return false;
}
-/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
-/// global scope ('::').
-Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
- SourceLocation CCLoc) {
- return NestedNameSpecifier::GlobalSpecifier(Context);
+bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
+ CXXScopeSpec &SS) {
+ SS.MakeGlobal(Context, CCLoc);
+ return false;
}
/// \brief Determines whether the given declaration is an valid acceptable
@@ -352,22 +355,21 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery. This means that it should not emit diagnostics, it should
-/// just return null on failure. It also means it should only return a valid
+/// just return true on failure. It also means it should only return a valid
/// scope if it *knows* that the result is correct. It should not return in a
-/// dependent context, for example.
-Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation IdLoc,
- SourceLocation CCLoc,
- IdentifierInfo &II,
- QualType ObjectType,
- NamedDecl *ScopeLookupResult,
- bool EnteringContext,
- bool ErrorRecoveryLookup) {
- NestedNameSpecifier *Prefix
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-
- LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+/// dependent context, for example. Nor will it extend \p SS with the scope
+/// specifier.
+bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
+ IdentifierInfo &Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation CCLoc,
+ QualType ObjectType,
+ bool EnteringContext,
+ CXXScopeSpec &SS,
+ NamedDecl *ScopeLookupResult,
+ bool ErrorRecoveryLookup) {
+ LookupResult Found(*this, &Identifier, IdentifierLoc,
+ LookupNestedNameSpecifierName);
// Determine where to perform name lookup
DeclContext *LookupCtx = 0;
@@ -397,7 +399,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// The declaration context must be complete.
if (!LookupCtx->isDependentContext() &&
RequireCompleteDeclContext(SS, LookupCtx))
- return 0;
+ return true;
LookupQualifiedName(Found, LookupCtx);
@@ -442,16 +444,14 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
!cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) {
// Don't speculate if we're just trying to improve error recovery.
if (ErrorRecoveryLookup)
- return 0;
+ return true;
// We were not able to compute the declaration context for a dependent
// base object type or prior nested-name-specifier, so this
// nested-name-specifier refers to an unknown specialization. Just build
// a dependent nested-name-specifier.
- if (!Prefix)
- return NestedNameSpecifier::Create(Context, &II);
-
- return NestedNameSpecifier::Create(Context, Prefix, &II);
+ SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
+ return false;
}
// FIXME: Deal with ambiguities cleanly.
@@ -480,7 +480,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
<< ND->getDeclName();
} else {
Found.clear();
- Found.setLookupName(&II);
+ Found.setLookupName(&Identifier);
}
}
@@ -497,7 +497,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// scope, reconstruct the result from the template instantiation itself.
NamedDecl *OuterDecl;
if (S) {
- LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+ LookupResult FoundOuter(*this, &Identifier, IdentifierLoc,
+ LookupNestedNameSpecifierName);
LookupName(FoundOuter, S);
OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
} else
@@ -509,39 +510,72 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
- if (ErrorRecoveryLookup)
- return 0;
-
- Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
- << &II;
- Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
- << ObjectType;
- Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
-
- // Fall through so that we'll pick the name we found in the object
- // type, since that's probably what the user wanted anyway.
- }
+ if (ErrorRecoveryLookup)
+ return true;
+
+ Diag(IdentifierLoc,
+ diag::err_nested_name_member_ref_lookup_ambiguous)
+ << &Identifier;
+ Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+ << ObjectType;
+ Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
+
+ // Fall through so that we'll pick the name we found in the object
+ // type, since that's probably what the user wanted anyway.
+ }
}
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
- return NestedNameSpecifier::Create(Context, Prefix, Namespace);
+ // If we're just performing this lookup for error-recovery purposes,
+ // don't extend the nested-name-specifier. Just return now.
+ if (ErrorRecoveryLookup)
+ return false;
+
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) {
+ SS.Extend(Context, Namespace, IdentifierLoc, CCLoc);
+ return false;
+ }
- // FIXME: It would be nice to maintain the namespace alias name, then
- // see through that alias when resolving the nested-name-specifier down to
- // a declaration context.
- if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
- return NestedNameSpecifier::Create(Context, Prefix,
- Alias->getNamespace());
+ if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) {
+ SS.Extend(Context, Alias, IdentifierLoc, CCLoc);
+ return false;
+ }
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
- return NestedNameSpecifier::Create(Context, Prefix, false,
- T.getTypePtr());
+ TypeLocBuilder TLB;
+ if (isa<InjectedClassNameType>(T)) {
+ InjectedClassNameTypeLoc InjectedTL
+ = TLB.push<InjectedClassNameTypeLoc>(T);
+ InjectedTL.setNameLoc(IdentifierLoc);
+ } else if (isa<RecordDecl>(SD)) {
+ RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
+ RecordTL.setNameLoc(IdentifierLoc);
+ } else if (isa<TypedefDecl>(SD)) {
+ TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
+ TypedefTL.setNameLoc(IdentifierLoc);
+ } else if (isa<EnumDecl>(SD)) {
+ EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T);
+ EnumTL.setNameLoc(IdentifierLoc);
+ } else if (isa<TemplateTypeParmDecl>(SD)) {
+ TemplateTypeParmTypeLoc TemplateTypeTL
+ = TLB.push<TemplateTypeParmTypeLoc>(T);
+ TemplateTypeTL.setNameLoc(IdentifierLoc);
+ } else {
+ assert(isa<UnresolvedUsingTypenameDecl>(SD) &&
+ "Unhandled TypeDecl node in nested-name-specifier");
+ UnresolvedUsingTypeLoc UnresolvedTL
+ = TLB.push<UnresolvedUsingTypeLoc>(T);
+ UnresolvedTL.setNameLoc(IdentifierLoc);
+ }
+
+ SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
+ CCLoc);
+ return false;
}
// Otherwise, we have an error case. If we don't want diagnostics, just
// return an error now.
if (ErrorRecoveryLookup)
- return 0;
+ return true;
// If we didn't find anything during our lookup, try again with
// ordinary name lookup, which can help us produce better error
@@ -555,36 +589,34 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (!Found.empty())
DiagID = diag::err_expected_class_or_namespace;
else if (SS.isSet()) {
- Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
- return 0;
+ Diag(IdentifierLoc, diag::err_no_member)
+ << &Identifier << LookupCtx << SS.getRange();
+ return true;
} else
DiagID = diag::err_undeclared_var_use;
if (SS.isSet())
- Diag(IdLoc, DiagID) << &II << SS.getRange();
+ Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange();
else
- Diag(IdLoc, DiagID) << &II;
+ Diag(IdentifierLoc, DiagID) << &Identifier;
- return 0;
+ return true;
}
-/// ActOnCXXNestedNameSpecifier - Called during parsing of a
-/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
-/// we want to resolve "bar::". 'SS' is empty or the previously parsed
-/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
-/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
-/// Returns a CXXScopeTy* object representing the C++ scope.
-Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation IdLoc,
- SourceLocation CCLoc,
- IdentifierInfo &II,
- ParsedType ObjectTypePtr,
- bool EnteringContext) {
- return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
- GetTypeFromParser(ObjectTypePtr),
- /*ScopeLookupResult=*/0, EnteringContext,
- false);
+bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ IdentifierInfo &Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation CCLoc,
+ ParsedType ObjectType,
+ bool EnteringContext,
+ CXXScopeSpec &SS) {
+ if (SS.isInvalid())
+ return true;
+
+ return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc,
+ GetTypeFromParser(ObjectType),
+ EnteringContext, SS,
+ /*ScopeLookupResult=*/0, false);
}
/// IsInvalidUnlessNestedName - This method is used for error recovery
@@ -594,23 +626,71 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
///
/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier.
bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
- IdentifierInfo &II, ParsedType ObjectType,
+ IdentifierInfo &Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation ColonLoc,
+ ParsedType ObjectType,
bool EnteringContext) {
- return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(),
- II, GetTypeFromParser(ObjectType),
- /*ScopeLookupResult=*/0, EnteringContext,
- true);
+ if (SS.isInvalid())
+ return false;
+
+ return !BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, ColonLoc,
+ GetTypeFromParser(ObjectType),
+ EnteringContext, SS,
+ /*ScopeLookupResult=*/0, true);
}
-Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
- ParsedType Ty,
- SourceRange TypeRange,
- SourceLocation CCLoc) {
- NestedNameSpecifier *Prefix = SS.getScopeRep();
- QualType T = GetTypeFromParser(Ty);
- return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
- T.getTypePtr());
+bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ ParsedType Type,
+ SourceLocation CCLoc,
+ CXXScopeSpec &SS) {
+ if (SS.isInvalid())
+ return true;
+
+ TypeSourceInfo *TSInfo;
+ QualType T = GetTypeFromParser(Type, &TSInfo);
+ if (T.isNull())
+ return true;
+
+ assert(TSInfo && "Not TypeSourceInfo in nested-name-specifier?");
+ // FIXME: location of the 'template' keyword?
+ SS.Extend(Context, SourceLocation(), TSInfo->getTypeLoc(), CCLoc);
+ return false;
+}
+
+namespace {
+ /// \brief A structure that stores a nested-name-specifier annotation,
+ /// including both the nested-name-specifier
+ struct NestedNameSpecifierAnnotation {
+ NestedNameSpecifier *NNS;
+ };
+}
+
+void *Sema::SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS) {
+ if (SS.isEmpty() || SS.isInvalid())
+ return 0;
+
+ void *Mem = Context.Allocate((sizeof(NestedNameSpecifierAnnotation) +
+ SS.location_size()),
+ llvm::alignOf<NestedNameSpecifierAnnotation>());
+ NestedNameSpecifierAnnotation *Annotation
+ = new (Mem) NestedNameSpecifierAnnotation;
+ Annotation->NNS = SS.getScopeRep();
+ memcpy(Annotation + 1, SS.location_data(), SS.location_size());
+ return Annotation;
+}
+
+void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr,
+ SourceRange AnnotationRange,
+ CXXScopeSpec &SS) {
+ if (!AnnotationPtr) {
+ SS.SetInvalid(AnnotationRange);
+ return;
+ }
+
+ NestedNameSpecifierAnnotation *Annotation
+ = static_cast<NestedNameSpecifierAnnotation *>(AnnotationPtr);
+ SS.Adopt(NestedNameSpecifierLoc(Annotation->NNS, Annotation + 1));
}
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
@@ -636,6 +716,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
switch (Qualifier->getKind()) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
// These are always namespace scopes. We never want to enter a
// namespace scope from anything but a file context.
return CurContext->getRedeclContext()->isFileContext();
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5566654..d83809d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -66,6 +66,26 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
return false;
}
+/// Checks that a call expression's argument count is the desired number.
+/// This is useful when doing custom type-checking. Returns true on error.
+static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
+ unsigned argCount = call->getNumArgs();
+ if (argCount == desiredArgCount) return false;
+
+ if (argCount < desiredArgCount)
+ return S.Diag(call->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/ << desiredArgCount << argCount
+ << call->getSourceRange();
+
+ // Highlight all the excess arguments.
+ SourceRange range(call->getArg(desiredArgCount)->getLocStart(),
+ call->getArg(argCount - 1)->getLocEnd());
+
+ return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/ << desiredArgCount << argCount
+ << call->getArg(1)->getSourceRange();
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult TheCallResult(Owned(TheCall));
@@ -137,15 +157,14 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinLongjmp(TheCall))
return ExprError();
break;
+
+ case Builtin::BI__builtin_classify_type:
+ if (checkArgCount(*this, TheCall, 1)) return true;
+ TheCall->setType(Context.IntTy);
+ break;
case Builtin::BI__builtin_constant_p:
- if (TheCall->getNumArgs() == 0)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << 1 << 0 << TheCall->getSourceRange();
- if (TheCall->getNumArgs() > 1)
- return Diag(TheCall->getArg(1)->getLocStart(),
- diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << 1 << TheCall->getNumArgs()
- << TheCall->getArg(1)->getSourceRange();
+ if (checkArgCount(*this, TheCall, 1)) return true;
+ TheCall->setType(Context.IntTy);
break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_sub:
@@ -875,7 +894,7 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
return false;
}
-// Handle i > 1 ? "x" : "y", recursivelly
+// Handle i > 1 ? "x" : "y", recursively.
bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
@@ -918,6 +937,12 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
}
return false;
+ case Stmt::PredefinedExprClass:
+ // While __func__, etc., are technically not string literals, they
+ // cannot contain format specifiers and thus are not a security
+ // liability.
+ return true;
+
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
@@ -2861,6 +2886,17 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return DiagnoseImpCast(S, E, T, CC, DiagID);
}
+ // Diagnose conversions between different enumeration types.
+ if (const EnumType *SourceEnum = Source->getAs<EnumType>())
+ if (const EnumType *TargetEnum = Target->getAs<EnumType>())
+ if ((SourceEnum->getDecl()->getIdentifier() ||
+ SourceEnum->getDecl()->getTypedefForAnonDecl()) &&
+ (TargetEnum->getDecl()->getIdentifier() ||
+ TargetEnum->getDecl()->getTypedefForAnonDecl()) &&
+ SourceEnum != TargetEnum)
+ return DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_different_enum_types);
+
return;
}
@@ -3112,7 +3148,7 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (!IndexExpr->isIntegerConstantExpr(index, Context))
return;
- if (!index.isNegative()) {
+ if (index.isUnsigned() || !index.isNegative()) {
llvm::APInt size = ArrayTy->getSize();
if (!size.isStrictlyPositive())
return;
@@ -3124,12 +3160,15 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (index.slt(size))
return;
- Diag(E->getBase()->getLocStart(), diag::warn_array_index_exceeds_bounds)
- << index.toString(10, true) << size.toString(10, true)
- << IndexExpr->getSourceRange();
+ DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
+ PDiag(diag::warn_array_index_exceeds_bounds)
+ << index.toString(10, true) << size.toString(10, true)
+ << IndexExpr->getSourceRange());
} else {
- Diag(E->getBase()->getLocStart(), diag::warn_array_index_precedes_bounds)
- << index.toString(10, true) << IndexExpr->getSourceRange();
+ DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
+ PDiag(diag::warn_array_index_precedes_bounds)
+ << index.toString(10, true)
+ << IndexExpr->getSourceRange());
}
const NamedDecl *ND = NULL;
@@ -3138,7 +3177,8 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
if (ND)
- Diag(ND->getLocStart(), diag::note_array_index_out_of_bounds)
- << ND->getDeclName();
+ DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
+ PDiag(diag::note_array_index_out_of_bounds)
+ << ND->getDeclName());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index dd30c12..d6efd7a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2895,8 +2895,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
if (!SS.isSet()) return;
- DD->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
- SS.getRange());
+ DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext()));
}
NamedDecl*
@@ -3026,11 +3025,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
II, R, TInfo, SC, SCAsWritten);
- // If this decl has an auto type in need of deduction, mark the VarDecl so
- // we can diagnose uses of it in its own initializer.
- if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) {
- NewVD->setParsingAutoInit(R->getContainedAutoType());
- }
+ // If this decl has an auto type in need of deduction, make a note of the
+ // Decl so we can diagnose uses of it in its own initializer.
+ if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
+ R->getContainedAutoType())
+ ParsingInitForAutoVars.insert(NewVD);
if (D.isInvalidType() || Invalid)
NewVD->setInvalidDecl();
@@ -4534,8 +4533,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
- VDecl->setParsingAutoInit(false);
-
QualType DeducedType;
if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
@@ -4800,9 +4797,8 @@ void Sema::ActOnInitializerError(Decl *D) {
if (!VD) return;
// Auto types are meaningless if we can't make sense of the initializer.
- if (VD->isParsingAutoInit()) {
- VD->setParsingAutoInit(false);
- VD->setInvalidDecl();
+ if (ParsingInitForAutoVars.count(D)) {
+ D->setInvalidDecl();
return;
}
@@ -4840,8 +4836,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// C++0x [dcl.spec.auto]p3
if (TypeMayContainAuto && Type->getContainedAutoType()) {
- Var->setParsingAutoInit(false);
-
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
<< Var->getDeclName() << Type;
Var->setInvalidDecl();
@@ -5044,6 +5038,14 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
FinalizeVarWithDestructor(var, recordType);
}
+/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
+/// any semantic actions necessary after any initializer has been attached.
+void
+Sema::FinalizeDeclaration(Decl *ThisDecl) {
+ // Note that we are no longer parsing the initializer for this declaration.
+ ParsingInitForAutoVars.erase(ThisDecl);
+}
+
Sema::DeclGroupPtrTy
Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group, unsigned NumDecls) {
@@ -5052,6 +5054,19 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (DS.isTypeSpecOwned())
Decls.push_back(DS.getRepAsDecl());
+ for (unsigned i = 0; i != NumDecls; ++i)
+ if (Decl *D = Group[i])
+ Decls.push_back(D);
+
+ return BuildDeclaratorGroup(Decls.data(), Decls.size(),
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
+}
+
+/// BuildDeclaratorGroup - convert a list of declarations into a declaration
+/// group, performing any necessary semantic checking.
+Sema::DeclGroupPtrTy
+Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
+ bool TypeMayContainAuto) {
// C++0x [dcl.spec.auto]p7:
// If the type deduced for the template parameter U is not the same in each
// deduction, the program is ill-formed.
@@ -5059,14 +5074,16 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
// between the deduced type U and the deduced type which 'auto' stands for.
// auto a = 0, b = { 1, 2, 3 };
// is legal because the deduced type U is 'int' in both cases.
- bool TypeContainsAuto = DS.getTypeSpecType() == DeclSpec::TST_auto;
- if (TypeContainsAuto && NumDecls > 1) {
+ if (TypeMayContainAuto && NumDecls > 1) {
QualType Deduced;
CanQualType DeducedCanon;
VarDecl *DeducedDecl = 0;
for (unsigned i = 0; i != NumDecls; ++i) {
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
AutoType *AT = D->getType()->getContainedAutoType();
+ // Don't reissue diagnostics when instantiating a template.
+ if (AT && D->isInvalidDecl())
+ break;
if (AT && AT->isDeduced()) {
QualType U = AT->getDeducedType();
CanQualType UCanon = Context.getCanonicalType(U);
@@ -5075,11 +5092,13 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeducedCanon = UCanon;
DeducedDecl = D;
} else if (DeducedCanon != UCanon) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_auto_different_deductions)
+ Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_auto_different_deductions)
<< Deduced << DeducedDecl->getDeclName()
<< U << D->getDeclName()
<< DeducedDecl->getInit()->getSourceRange()
<< D->getInit()->getSourceRange();
+ D->setInvalidDecl();
break;
}
}
@@ -5087,12 +5106,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
}
}
- for (unsigned i = 0; i != NumDecls; ++i)
- if (Decl *D = Group[i])
- Decls.push_back(D);
-
- return DeclGroupPtrTy::make(DeclGroupRef::Create(Context,
- Decls.data(), Decls.size()));
+ return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls));
}
@@ -5537,6 +5551,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
FD = dyn_cast_or_null<FunctionDecl>(dcl);
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
+ sema::AnalysisBasedWarnings::Policy *ActivePolicy = 0;
if (FD) {
FD->setBody(Body);
@@ -5605,13 +5620,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
else if (!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
- QualType ResultType;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) {
- AnalysisWarnings.IssueWarnings(WP, FD);
- } else {
- ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
- AnalysisWarnings.IssueWarnings(WP, MD);
- }
+ ActivePolicy = &WP;
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
@@ -5620,7 +5629,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!IsInstantiation)
PopDeclContext();
- PopFunctionOrBlockScope();
+ PopFunctionOrBlockScope(ActivePolicy, dcl);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
@@ -6435,9 +6444,7 @@ CreateNewDecl:
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- New->setQualifierInfo(NNS, SS.getRange());
+ New->setQualifierInfo(SS.getWithLocInContext(Context));
if (NumMatchedTemplateParamLists > 0) {
New->setTemplateParameterListsInfo(Context,
NumMatchedTemplateParamLists,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cbc940f..893cf6a 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1014,54 +1014,48 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- int noArgs = Attr.getNumArgs();
- if (noArgs > 1) {
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 1) {
S.Diag(Attr.getLoc(),
diag::err_attribute_wrong_number_arguments) << "0 or 1";
return;
}
+
// Handle the case where deprecated attribute has a text message.
- StringLiteral *SE;
- if (noArgs == 1) {
- Expr *ArgExpr = Attr.getArg(0);
- SE = dyn_cast<StringLiteral>(ArgExpr);
+ llvm::StringRef Str;
+ if (NumArgs == 1) {
+ StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
- S.Diag(ArgExpr->getLocStart(),
- diag::err_attribute_not_string) << "deprecated";
+ S.Diag(Attr.getArg(0)->getLocStart(), diag::err_attribute_not_string)
+ << "deprecated";
return;
}
+ Str = SE->getString();
}
- else
- SE = StringLiteral::CreateEmpty(S.Context, 1);
- d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context,
- SE->getString()));
+ d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str));
}
static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- int noArgs = Attr.getNumArgs();
- if (noArgs > 1) {
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 1) {
S.Diag(Attr.getLoc(),
diag::err_attribute_wrong_number_arguments) << "0 or 1";
return;
}
+
// Handle the case where unavailable attribute has a text message.
- StringLiteral *SE;
- if (noArgs == 1) {
- Expr *ArgExpr = Attr.getArg(0);
- SE = dyn_cast<StringLiteral>(ArgExpr);
+ llvm::StringRef Str;
+ if (NumArgs == 1) {
+ StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
- S.Diag(ArgExpr->getLocStart(),
+ S.Diag(Attr.getArg(0)->getLocStart(),
diag::err_attribute_not_string) << "unavailable";
return;
}
+ Str = SE->getString();
}
- else
- SE = StringLiteral::CreateEmpty(S.Context, 1);
- d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context,
- SE->getString()));
+ d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
}
static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -2847,7 +2841,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
FD->getType(), FD->getTypeSourceInfo());
if (FD->getQualifier()) {
FunctionDecl *NewFD = cast<FunctionDecl>(NewD);
- NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange());
+ NewFD->setQualifierInfo(FD->getQualifierLoc());
}
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
@@ -2857,7 +2851,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
VD->getStorageClassAsWritten());
if (VD->getQualifier()) {
VarDecl *NewVD = cast<VarDecl>(NewD);
- NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
+ NewVD->setQualifierInfo(VD->getQualifierLoc());
}
}
return NewD;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e8abab8..f483262 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1078,6 +1078,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (Deleted) // FIXME: Source location is not very good.
SetDeclDeleted(Member, D.getSourceRange().getBegin());
+ FinalizeDeclaration(Member);
+
if (isInstField)
FieldCollector->Add(cast<FieldDecl>(Member));
return Member;
@@ -2586,6 +2588,9 @@ struct CheckAbstractUsage {
void Check(FunctionProtoTypeLoc TL, Sema::AbstractDiagSelID Sel) {
Visit(TL.getResultLoc(), Sema::AbstractReturnType);
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+ if (!TL.getArg(I))
+ continue;
+
TypeSourceInfo *TSI = TL.getArg(I)->getTypeSourceInfo();
if (TSI) Visit(TSI->getTypeLoc(), Sema::AbstractParamType);
}
@@ -3618,8 +3623,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
= UsingDirectiveDecl::Create(Context, CurContext,
/* 'using' */ LBrace,
/* 'namespace' */ SourceLocation(),
- /* qualifier */ SourceRange(),
- /* NNS */ NULL,
+ /* qualifier */ NestedNameSpecifierLoc(),
/* identifier */ SourceLocation(),
Namespc,
/* Ancestor */ CurContext);
@@ -3763,8 +3767,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
CommonAncestor = CommonAncestor->getParent();
UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc,
- SS.getRange(),
- (NestedNameSpecifier *)SS.getScopeRep(),
+ SS.getWithLocInContext(Context),
IdentLoc, Named, CommonAncestor);
PushUsingDirective(S, UDir);
} else {
@@ -3914,16 +3917,16 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
if (OrigDC == CurContext) {
Diag(Using->getLocation(),
diag::err_using_decl_nested_name_specifier_is_current_class)
- << Using->getNestedNameRange();
+ << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target);
return true;
}
- Diag(Using->getNestedNameRange().getBegin(),
+ Diag(Using->getQualifierLoc().getBeginLoc(),
diag::err_using_decl_nested_name_specifier_is_not_base_class)
- << Using->getTargetNestedNameDecl()
+ << Using->getQualifier()
<< cast<CXXRecordDecl>(CurContext)
- << Using->getNestedNameRange();
+ << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target);
return true;
}
@@ -4129,8 +4132,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
LookupQualifiedName(Previous, CurContext);
}
- NestedNameSpecifier *NNS = SS.getScopeRep();
-
// Check for invalid redeclarations.
if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
return 0;
@@ -4141,22 +4142,21 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
DeclContext *LookupContext = computeDeclContext(SS);
NamedDecl *D;
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
if (!LookupContext) {
if (IsTypeName) {
// FIXME: not all declaration name kinds are legal here
D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
UsingLoc, TypenameLoc,
- SS.getRange(), NNS,
+ QualifierLoc,
IdentLoc, NameInfo.getName());
} else {
- D = UnresolvedUsingValueDecl::Create(Context, CurContext,
- UsingLoc, SS.getRange(),
- NNS, NameInfo);
+ D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
+ QualifierLoc, NameInfo);
}
} else {
- D = UsingDecl::Create(Context, CurContext,
- SS.getRange(), UsingLoc, NNS, NameInfo,
- IsTypeName);
+ D = UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
+ NameInfo, IsTypeName);
}
D->setAccess(AS);
CurContext->addDecl(D);
@@ -4247,7 +4247,7 @@ bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
return true;
}
- const Type *SourceType = UD->getTargetNestedNameDecl()->getAsType();
+ const Type *SourceType = UD->getQualifier()->getAsType();
assert(SourceType &&
"Using decl naming constructor doesn't have type in scope spec.");
CXXRecordDecl *TargetClass = cast<CXXRecordDecl>(CurContext);
@@ -4304,15 +4304,15 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
NestedNameSpecifier *DQual;
if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
DTypename = UD->isTypeName();
- DQual = UD->getTargetNestedNameDecl();
+ DQual = UD->getQualifier();
} else if (UnresolvedUsingValueDecl *UD
= dyn_cast<UnresolvedUsingValueDecl>(D)) {
DTypename = false;
- DQual = UD->getTargetNestedNameSpecifier();
+ DQual = UD->getQualifier();
} else if (UnresolvedUsingTypenameDecl *UD
= dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
DTypename = true;
- DQual = UD->getTargetNestedNameSpecifier();
+ DQual = UD->getQualifier();
} else continue;
// using decls differ if one says 'typename' and the other doesn't.
@@ -4542,8 +4542,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
NamespaceAliasDecl *AliasDecl =
NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
- Alias, SS.getRange(),
- (NestedNameSpecifier *)SS.getScopeRep(),
+ Alias, SS.getWithLocInContext(Context),
IdentLoc, R.getFoundDecl());
PushOnScopeChains(AliasDecl, S);
@@ -5080,9 +5079,10 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// reference to operator=; this is required to suppress the virtual
// call mechanism.
CXXScopeSpec SS;
- SS.setRange(Loc);
- SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false,
- T.getTypePtr()));
+ SS.MakeTrivial(S.Context,
+ NestedNameSpecifier::Create(S.Context, 0, false,
+ T.getTypePtr()),
+ Loc);
// Create the reference to operator=.
ExprResult OpEqualRef
@@ -5972,8 +5972,6 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
- VDecl->setParsingAutoInit(false);
-
// FIXME: n3225 doesn't actually seem to indicate this is ill-formed
if (Exprs.size() > 1) {
Diag(Exprs.get()[1]->getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 66f6f2b..652318f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -856,9 +856,21 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) {
static void CheckMethodOverrideReturn(Sema &S,
ObjCMethodDecl *MethodImpl,
- ObjCMethodDecl *MethodIface) {
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl) {
+ if (IsProtocolMethodDecl &&
+ (MethodDecl->getObjCDeclQualifier() !=
+ MethodImpl->getObjCDeclQualifier())) {
+ S.Diag(MethodImpl->getLocation(),
+ diag::warn_conflicting_ret_type_modifiers)
+ << MethodImpl->getDeclName()
+ << getTypeRange(MethodImpl->getResultTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ }
+
if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(),
- MethodIface->getResultType()))
+ MethodDecl->getResultType()))
return;
unsigned DiagID = diag::warn_conflicting_ret_types;
@@ -868,7 +880,7 @@ static void CheckMethodOverrideReturn(Sema &S,
if (const ObjCObjectPointerType *ImplPtrTy =
MethodImpl->getResultType()->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *IfacePtrTy =
- MethodIface->getResultType()->getAs<ObjCObjectPointerType>()) {
+ MethodDecl->getResultType()->getAs<ObjCObjectPointerType>()) {
// Allow non-matching return types as long as they don't violate
// the principle of substitutability. Specifically, we permit
// return types that are subclasses of the declared return type,
@@ -882,20 +894,33 @@ static void CheckMethodOverrideReturn(Sema &S,
S.Diag(MethodImpl->getLocation(), DiagID)
<< MethodImpl->getDeclName()
- << MethodIface->getResultType()
+ << MethodDecl->getResultType()
<< MethodImpl->getResultType()
<< getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodIface->getLocation(), diag::note_previous_definition)
- << getTypeRange(MethodIface->getResultTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_definition)
+ << getTypeRange(MethodDecl->getResultTypeSourceInfo());
}
static void CheckMethodOverrideParam(Sema &S,
ObjCMethodDecl *MethodImpl,
- ObjCMethodDecl *MethodIface,
+ ObjCMethodDecl *MethodDecl,
ParmVarDecl *ImplVar,
- ParmVarDecl *IfaceVar) {
+ ParmVarDecl *IfaceVar,
+ bool IsProtocolMethodDecl) {
+ if (IsProtocolMethodDecl &&
+ (ImplVar->getObjCDeclQualifier() !=
+ IfaceVar->getObjCDeclQualifier())) {
+ S.Diag(ImplVar->getLocation(),
+ diag::warn_conflicting_param_modifiers)
+ << getTypeRange(ImplVar->getTypeSourceInfo())
+ << MethodImpl->getDeclName();
+ S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(IfaceVar->getTypeSourceInfo());
+ }
+
QualType ImplTy = ImplVar->getType();
QualType IfaceTy = IfaceVar->getType();
+
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
return;
@@ -927,17 +952,20 @@ static void CheckMethodOverrideParam(Sema &S,
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
- ObjCMethodDecl *IntfMethodDecl) {
- CheckMethodOverrideReturn(*this, ImpMethodDecl, IntfMethodDecl);
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl) {
+ CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
+ IsProtocolMethodDecl);
for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
- IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
+ IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
IM != EM; ++IM, ++IF)
- CheckMethodOverrideParam(*this, ImpMethodDecl, IntfMethodDecl, *IM, *IF);
+ CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF,
+ IsProtocolMethodDecl);
- if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) {
+ if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) {
Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic);
- Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration);
+ Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
}
}
@@ -1061,13 +1089,14 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getInstanceMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *MethodDecl =
CDecl->getInstanceMethod((*I)->getSelector());
- assert(IntfMethodDecl &&
- "IntfMethodDecl is null in ImplMethodsVsClassMethods");
+ assert(MethodDecl &&
+ "MethodDecl is null in ImplMethodsVsClassMethods");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl)
- WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
}
}
@@ -1085,9 +1114,10 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
- ObjCMethodDecl *IntfMethodDecl =
+ ObjCMethodDecl *MethodDecl =
CDecl->getClassMethod((*I)->getSelector());
- WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
}
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 65b57c3..415ab3f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -76,12 +76,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
// See if this is an auto-typed variable whose initializer we are parsing.
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (VD->isParsingAutoInit()) {
- Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
- << D->getDeclName();
- return true;
- }
+ if (ParsingInitForAutoVars.count(D)) {
+ Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
+ << D->getDeclName();
+ return true;
}
// See if the decl is deprecated.
@@ -389,13 +387,13 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
return false;
if (Expr->getType()->isObjCObjectType() &&
- DiagRuntimeBehavior(Expr->getLocStart(),
+ DiagRuntimeBehavior(Expr->getLocStart(), 0,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< Expr->getType() << CT))
return true;
if (!Expr->getType()->isPODType() &&
- DiagRuntimeBehavior(Expr->getLocStart(),
+ DiagRuntimeBehavior(Expr->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< Expr->getType() << CT))
return true;
@@ -1675,20 +1673,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// This is guaranteed from this point on.
assert(!R.empty() || ADL);
- if (VarDecl *Var = R.getAsSingle<VarDecl>()) {
- if (getLangOptions().ObjCNonFragileABI && IvarLookupFollowUp &&
- !(getLangOptions().ObjCDefaultSynthProperties &&
- getLangOptions().ObjCNonFragileABI2) &&
- Var->isFileVarDecl()) {
- ObjCPropertyDecl *Property = canSynthesizeProvisionalIvar(II);
- if (Property) {
- Diag(NameLoc, diag::warn_ivar_variable_conflict) << Var->getDeclName();
- Diag(Property->getLocation(), diag::note_property_declare);
- Diag(Var->getLocation(), diag::note_global_declared_at);
- }
- }
- }
-
// Check whether this might be a C++ implicit instance member access.
// C++ [class.mfct.non-static]p3:
// When an id-expression that is not part of a class member access
@@ -3996,131 +3980,130 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Failure cases.
fail:
- // There's a possible road to recovery for function types.
- const FunctionType *Fun = 0;
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr->getLocEnd());
-
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
- // fall out, handled below.
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- } else if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
+ MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
+ << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, "->");
// Recurse as an -> access.
IsArrow = true;
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
- } else {
- Fun = BaseType->getAs<FunctionType>();
- }
-
- // If the user is trying to apply -> or . to a function pointer
- // type, it's probably because they forgot parentheses to call that
- // function. Suggest the addition of those parentheses, build the
- // call, and continue on.
- if (Fun || BaseType == Context.OverloadTy) {
- bool TryCall;
- if (BaseType == Context.OverloadTy) {
- // Plunder the overload set for something that would make the member
- // expression valid.
- const OverloadExpr *Overloads = cast<OverloadExpr>(BaseExpr);
- UnresolvedSet<4> CandidateOverloads;
- bool HasZeroArgCandidateOverload = false;
- for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
- DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- CandidateOverloads.addDecl(*it);
- if (OverloadDecl->getNumParams() == 0) {
- HasZeroArgCandidateOverload = true;
- }
+ }
+
+ // If the user is trying to apply -> or . to a function name, it's probably
+ // because they forgot parentheses to call that function.
+ bool TryCall = false;
+ bool Overloaded = false;
+ UnresolvedSet<8> AllOverloads;
+ if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr)) {
+ AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
+ TryCall = true;
+ Overloaded = true;
+ } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr)) {
+ if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+ AllOverloads.addDecl(Fun);
+ TryCall = true;
+ }
+ }
+
+ if (TryCall) {
+ // Plunder the overload set for something that would make the member
+ // expression valid.
+ UnresolvedSet<4> ViableOverloads;
+ bool HasViableZeroArgOverload = false;
+ for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
+ DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
+ QualType ResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType())) {
+ ViableOverloads.addDecl(*it);
+ if (OverloadDecl->getMinRequiredArguments() == 0) {
+ HasViableZeroArgOverload = true;
}
}
- if (HasZeroArgCandidateOverload && CandidateOverloads.size() == 1) {
- // We have one reasonable overload, and there's only one way to call it,
- // so emit a fixit and try to recover
- Diag(ParenInsertionLoc, diag::err_member_reference_needs_call)
- << 1
- << BaseExpr->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- TryCall = true;
- } else {
- Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
- << 0
- << BaseExpr->getSourceRange();
- int CandidateOverloadCount = CandidateOverloads.size();
- int I;
- for (I = 0; I < CandidateOverloadCount; ++I) {
- // FIXME: Magic number for max shown overloads stolen from
- // OverloadCandidateSet::NoteCandidates.
- if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
- break;
- }
- Diag(CandidateOverloads[I].getDecl()->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
- }
- if (I != CandidateOverloadCount) {
- Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
- << int(CandidateOverloadCount - I);
+ }
+
+ if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
+ Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ << 1 << 0
+ << BaseExpr->getSourceRange();
+ int ViableOverloadCount = ViableOverloads.size();
+ int I;
+ for (I = 0; I < ViableOverloadCount; ++I) {
+ // FIXME: Magic number for max shown overloads stolen from
+ // OverloadCandidateSet::NoteCandidates.
+ if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ break;
}
- return ExprError();
+ Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
+ diag::note_member_ref_possible_intended_overload);
}
- } else {
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
- TryCall = (FPT->getNumArgs() == 0);
- } else {
- TryCall = true;
+ if (I != ViableOverloadCount) {
+ Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
+ << int(ViableOverloadCount - I);
}
-
- if (TryCall) {
- QualType ResultTy = Fun->getResultType();
- TryCall = (!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getAs<PointerType>()->getPointeeType()->isRecordType());
+ return ExprError();
+ }
+ } else {
+ // We don't have an expression that's convenient to get a Decl from, but we
+ // can at least check if the type is "function of 0 arguments which returns
+ // an acceptable type".
+ const FunctionType *Fun = NULL;
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
+ TryCall = true;
}
+ } else if ((Fun = BaseType->getAs<FunctionType>())) {
+ TryCall = true;
}
-
if (TryCall) {
- if (Fun) {
- Diag(BaseExpr->getExprLoc(),
- diag::err_member_reference_needs_call_zero_arg)
- << QualType(Fun, 0)
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
+ if (FPT->getNumArgs() == 0) {
+ QualType ResultTy = Fun->getResultType();
+ TryCall = (!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType());
+ }
}
-
- ExprResult NewBase
- = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
- MultiExprArg(*this, 0, 0), ParenInsertionLoc);
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase.takeAs<Expr>();
-
-
- DefaultFunctionArrayConversion(BaseExpr);
- BaseType = BaseExpr->getType();
-
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
}
}
+ if (TryCall) {
+ // At this point, we know BaseExpr looks like it's potentially callable with
+ // 0 arguments, and that it returns something of a reasonable type, so we
+ // can emit a fixit and carry on pretending that BaseExpr was actually a
+ // CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr->getLocEnd());
+ Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ << int(Overloaded) << 1
+ << BaseExpr->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ ExprResult NewBase = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc);
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase.takeAs<Expr>();
+ DefaultFunctionArrayConversion(BaseExpr);
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
@@ -4298,6 +4281,13 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc) {
+ // Bail out early if calling a builtin with custom typechecking.
+ // We don't need to do this in the
+ if (FDecl)
+ if (unsigned ID = FDecl->getBuiltinID())
+ if (Context.BuiltinInfo.hasCustomTypechecking(ID))
+ return false;
+
// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
// assignment, to the types of the corresponding parameter, ...
unsigned NumArgsInProto = Proto->getNumArgs();
@@ -4625,22 +4615,41 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
RParenLoc);
}
+ unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
+
+ // Bail out early if calling a builtin with custom typechecking.
+ if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
+ return CheckBuiltinFunctionCall(BuiltinID, TheCall);
+
const FunctionType *FuncT;
- if (!Fn->getType()->isBlockPointerType()) {
+ if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
// have type pointer to function".
- const PointerType *PT = Fn->getType()->getAs<PointerType>();
- if (PT == 0)
- return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
- << Fn->getType() << Fn->getSourceRange());
FuncT = PT->getPointeeType()->getAs<FunctionType>();
- } else { // This is a block call.
- FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()->
- getAs<FunctionType>();
- }
- if (FuncT == 0)
+ if (FuncT == 0)
+ return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
+ << Fn->getType() << Fn->getSourceRange());
+ } else if (const BlockPointerType *BPT =
+ Fn->getType()->getAs<BlockPointerType>()) {
+ FuncT = BPT->getPointeeType()->castAs<FunctionType>();
+ } else {
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
+ }
+
+ if (getLangOptions().CUDA) {
+ if (Config) {
+ // CUDA: Kernel calls must be to global functions
+ if (FDecl && !FDecl->hasAttr<CUDAGlobalAttr>())
+ return ExprError(Diag(LParenLoc,diag::err_kern_call_not_global_function)
+ << FDecl->getName() << Fn->getSourceRange());
+
+ // CUDA: Kernel function must have 'void' return type
+ if (!FuncT->getResultType()->isVoidType())
+ return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
+ << Fn->getType() << Fn->getSourceRange());
+ }
+ }
// Check for a valid return type
if (CheckCallReturnType(FuncT->getResultType(),
@@ -4721,7 +4730,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (CheckFunctionCall(FDecl, TheCall))
return ExprError();
- if (unsigned BuiltinID = FDecl->getBuiltinID())
+ if (BuiltinID)
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
} else if (NDecl) {
if (CheckBlockCall(NDecl, TheCall))
@@ -6372,8 +6381,8 @@ QualType Sema::CheckMultiplyDivideOperands(
// Check for division by zero.
if (isDiv &&
rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero)
- << rex->getSourceRange());
+ DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_division_by_zero)
+ << rex->getSourceRange());
return compType;
}
@@ -6394,8 +6403,8 @@ QualType Sema::CheckRemainderOperands(
// Check for remainder by zero.
if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero)
- << rex->getSourceRange());
+ DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_remainder_by_zero)
+ << rex->getSourceRange());
return compType;
}
@@ -6629,9 +6638,61 @@ static bool isScopedEnumerationType(QualType T) {
return false;
}
+static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex,
+ SourceLocation Loc, unsigned Opc,
+ QualType LHSTy) {
+ llvm::APSInt Right;
+ // Check right/shifter operand
+ if (rex->isValueDependent() || !rex->isIntegerConstantExpr(Right, S.Context))
+ return;
+
+ if (Right.isNegative()) {
+ S.Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
+ return;
+ }
+ llvm::APInt LeftBits(Right.getBitWidth(),
+ S.Context.getTypeSize(lex->getType()));
+ if (Right.uge(LeftBits)) {
+ S.Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
+ return;
+ }
+ if (Opc != BO_Shl)
+ return;
+
+ // When left shifting an ICE which is signed, we can check for overflow which
+ // according to C++ has undefined behavior ([expr.shift] 5.8/2). Unsigned
+ // integers have defined behavior modulo one more than the maximum value
+ // representable in the result type, so never warn for those.
+ llvm::APSInt Left;
+ if (lex->isValueDependent() || !lex->isIntegerConstantExpr(Left, S.Context) ||
+ LHSTy->hasUnsignedIntegerRepresentation())
+ return;
+ llvm::APInt ResultBits =
+ static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits();
+ if (LeftBits.uge(ResultBits))
+ return;
+ llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue());
+ Result = Result.shl(Right);
+
+ // If we are only missing a sign bit, this is less likely to result in actual
+ // bugs -- if the result is cast back to an unsigned type, it will have the
+ // expected value. Thus we place this behind a different warning that can be
+ // turned off separately if needed.
+ if (LeftBits == ResultBits - 1) {
+ S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit)
+ << Result.toString(10) << LHSTy
+ << lex->getSourceRange() << rex->getSourceRange();
+ return;
+ }
+
+ S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
+ << Result.toString(10) << Result.getMinSignedBits() << LHSTy
+ << Left.getBitWidth() << lex->getSourceRange() << rex->getSourceRange();
+}
+
// C99 6.5.7
QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
- bool isCompAssign) {
+ unsigned Opc, bool isCompAssign) {
// C99 6.5.7p2: Each of the operands shall have integer type.
if (!lex->getType()->hasIntegerRepresentation() ||
!rex->getType()->hasIntegerRepresentation())
@@ -6662,19 +6723,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
UsualUnaryConversions(rex);
// Sanity-check shift operands
- llvm::APSInt Right;
- // Check right/shifter operand
- if (!rex->isValueDependent() &&
- rex->isIntegerConstantExpr(Right, Context)) {
- if (Right.isNegative())
- Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
- else {
- llvm::APInt LeftBits(Right.getBitWidth(),
- Context.getTypeSize(lex->getType()));
- if (Right.uge(LeftBits))
- Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
- }
- }
+ DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy);
// "The type of the result is that of the promoted left operand."
return LHSTy;
@@ -6738,7 +6787,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
if (DRL->getDecl() == DRR->getDecl() &&
!IsWithinTemplateSpecialization(DRL->getDecl())) {
- DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always)
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
<< 0 // self-
<< (Opc == BO_EQ
|| Opc == BO_LE
@@ -6760,7 +6809,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
always_evals_to = 2; // e.g. array1 <= array2
break;
}
- DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always)
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
<< 1 // array
<< always_evals_to);
}
@@ -6801,7 +6850,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
default: assert(false && "Invalid comparison operator");
}
- DiagRuntimeBehavior(Loc,
+ DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
<< literalString->getSourceRange());
@@ -7111,7 +7160,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
if (DRL->getDecl() == DRR->getDecl())
- DiagRuntimeBehavior(Loc,
+ DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_comparison_always)
<< 0 // self-
<< 2 // "a constant"
@@ -7372,9 +7421,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
UO->getSubExpr()->IgnoreParenCasts()->
isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) &&
!UO->getType().isVolatileQualified()) {
- Diag(UO->getOperatorLoc(), diag::warn_indirection_through_null)
- << UO->getSubExpr()->getSourceRange();
- Diag(UO->getOperatorLoc(), diag::note_indirection_through_null);
+ DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ PDiag(diag::warn_indirection_through_null)
+ << UO->getSubExpr()->getSourceRange());
+ DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ PDiag(diag::note_indirection_through_null));
}
// Check for trivial buffer overflows.
@@ -7959,7 +8010,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_Shl:
case BO_Shr:
- ResultTy = CheckShiftOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc);
break;
case BO_LE:
case BO_LT:
@@ -8006,7 +8057,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_ShlAssign:
case BO_ShrAssign:
- CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
+ CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull())
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
@@ -8563,7 +8614,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// (clause 9).
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
- DiagRuntimeBehavior(BuiltinLoc,
+ DiagRuntimeBehavior(BuiltinLoc, 0,
PDiag(diag::warn_offsetof_non_pod_type)
<< SourceRange(CompPtr[0].LocStart, OC.LocEnd)
<< CurrentType))
@@ -8907,12 +8958,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
- // Issue any analysis-based warnings.
- const sema::AnalysisBasedWarnings::Policy &WP =
- AnalysisWarnings.getDefaultPolicy();
- AnalysisWarnings.IssueWarnings(WP, Result);
-
- PopFunctionOrBlockScope();
+ const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
+ PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
return Owned(Result);
}
@@ -9350,9 +9397,12 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
- // Keep track of used but undefined variables.
+ // Keep track of used but undefined variables. We make a hole in
+ // the warning for static const data members with in-line
+ // initializers.
if (Var->hasDefinition() == VarDecl::DeclarationOnly
- && Var->getLinkage() != ExternalLinkage) {
+ && Var->getLinkage() != ExternalLinkage
+ && !(Var->isStaticDataMember() && Var->hasInit())) {
SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
@@ -9484,7 +9534,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
/// behavior of a program, such as passing a non-POD value through an ellipsis.
/// Failure to do so will likely result in spurious diagnostics or failures
/// during overload resolution or within sizeof/alignof/typeof/typeid.
-bool Sema::DiagRuntimeBehavior(SourceLocation Loc,
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context ) {
case Unevaluated:
@@ -9493,7 +9543,13 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc,
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
- Diag(Loc, PD);
+ if (stmt && getCurFunctionOrMethodDecl()) {
+ FunctionScopes.back()->PossiblyUnreachableDiags.
+ push_back(sema::PossiblyUnreachableDiag(PD, Loc, stmt));
+ }
+ else
+ Diag(Loc, PD);
+
return true;
case PotentiallyPotentiallyEvaluated:
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index f9c2c9a..6dd7aab 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -107,7 +107,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// Nothing left to do.
} else if (LookAtPrefix && (Prefix = NNS->getPrefix())) {
CXXScopeSpec PrefixSS;
- PrefixSS.setScopeRep(Prefix);
+ PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data()));
LookupCtx = computeDeclContext(PrefixSS, EnteringContext);
isDependent = isDependentScopeSpecifier(PrefixSS);
} else if (ObjectTypePtr) {
@@ -476,7 +476,9 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
/// ActOnCXXThrow - Parse throw expressions.
ExprResult
Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) {
- if (!getLangOptions().Exceptions)
+ // Don't report an error if 'throw' is used in system headers.
+ if (!getLangOptions().Exceptions &&
+ !getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex))
@@ -1347,6 +1349,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_Success: {
// Got one!
FunctionDecl *FnDecl = Best->Function;
+ MarkDeclarationReferenced(StartLoc, FnDecl);
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
@@ -1384,7 +1387,10 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_Deleted:
Diag(StartLoc, diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
- << Name << Range;
+ << Name
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
+ << Range;
Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
return true;
}
@@ -2920,6 +2926,8 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], Sema::AA_Converting))
break;
+ if (Best->Function)
+ Self.MarkDeclarationReferenced(QuestionLoc, Best->Function);
return false;
case OR_No_Viable_Function:
@@ -3580,14 +3588,14 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
}
ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
- TypeSourceInfo *ScopeTypeInfo,
- SourceLocation CCLoc,
- SourceLocation TildeLoc,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeTypeInfo,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destructed,
- bool HasTrailingLParen) {
+ bool HasTrailingLParen) {
TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
// C++ [expr.pseudo]p2:
@@ -3662,7 +3670,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
Expr *Result
= new (Context) CXXPseudoDestructorExpr(Context, Base,
OpKind == tok::arrow, OpLoc,
- SS.getScopeRep(), SS.getRange(),
+ SS.getWithLocInContext(Context),
ScopeTypeInfo,
CCLoc,
TildeLoc,
@@ -3675,14 +3683,14 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
}
ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- CXXScopeSpec &SS,
- UnqualifiedId &FirstTypeName,
- SourceLocation CCLoc,
- SourceLocation TildeLoc,
- UnqualifiedId &SecondTypeName,
- bool HasTrailingLParen) {
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ CXXScopeSpec &SS,
+ UnqualifiedId &FirstTypeName,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ UnqualifiedId &SecondTypeName,
+ bool HasTrailingLParen) {
assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
"Invalid first type name in pseudo-destructor");
@@ -3714,8 +3722,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
// record types and dependent types matter.
ParsedType ObjectTypePtrForLookup;
if (!SS.isSet()) {
- if (const Type *T = ObjectType->getAs<RecordType>())
- ObjectTypePtrForLookup = ParsedType::make(QualType(T, 0));
+ if (ObjectType->isRecordType())
+ ObjectTypePtrForLookup = ParsedType::make(ObjectType);
else if (ObjectType->isDependentType())
ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy);
}
@@ -3784,7 +3792,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
ParsedType T = getTypeName(*FirstTypeName.Identifier,
FirstTypeName.StartLocation,
- S, &SS, false, false, ObjectTypePtrForLookup);
+ S, &SS, true, false, ObjectTypePtrForLookup);
if (!T) {
Diag(FirstTypeName.StartLocation,
diag::err_pseudo_dtor_destructor_non_type)
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index b9a6a57..5882da0 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -31,10 +31,8 @@ using namespace clang;
// Sema Initialization Checking
//===----------------------------------------------------------------------===//
-static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
- const ArrayType *AT = Context.getAsArrayType(DeclType);
- if (!AT) return 0;
-
+static Expr *IsStringInit(Expr *Init, const ArrayType *AT,
+ ASTContext &Context) {
if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT))
return 0;
@@ -66,13 +64,20 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
return 0;
}
-static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
+static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) {
+ const ArrayType *arrayType = Context.getAsArrayType(declType);
+ if (!arrayType) return 0;
+
+ return IsStringInit(init, arrayType, Context);
+}
+
+static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
+ Sema &S) {
// Get the length of the string as parsed.
uint64_t StrLength =
cast<ConstantArrayType>(Str->getType())->getSize().getZExtValue();
- const ArrayType *AT = S.Context.getAsArrayType(DeclT);
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
// C99 6.7.8p14. We have an array of character type with unknown size
// being initialized to a string literal.
@@ -651,82 +656,93 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
- } else if (Expr *Str = IsStringInit(expr, ElemType, SemaRef.Context)) {
- CheckStringInit(Str, ElemType, SemaRef);
- UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
- ++Index;
+ return;
} else if (ElemType->isScalarType()) {
- CheckScalarType(Entity, IList, ElemType, Index,
- StructuredList, StructuredIndex);
+ return CheckScalarType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
} else if (ElemType->isReferenceType()) {
- CheckReferenceType(Entity, IList, ElemType, Index,
- StructuredList, StructuredIndex);
- } else {
- if (SemaRef.getLangOptions().CPlusPlus) {
- // C++ [dcl.init.aggr]p12:
- // All implicit type conversions (clause 4) are considered when
- // initializing the aggregate member with an ini- tializer from
- // an initializer-list. If the initializer can initialize a
- // member, the member is initialized. [...]
-
- // FIXME: Better EqualLoc?
- InitializationKind Kind =
- InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation());
- InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1);
-
- if (Seq) {
- ExprResult Result =
- Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
- if (Result.isInvalid())
- hadError = true;
-
- UpdateStructuredListElement(StructuredList, StructuredIndex,
- Result.takeAs<Expr>());
- ++Index;
- return;
- }
+ return CheckReferenceType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
+ }
- // Fall through for subaggregate initialization
- } else {
- // C99 6.7.8p13:
- //
- // The initializer for a structure or union object that has
- // automatic storage duration shall be either an initializer
- // list as described below, or a single expression that has
- // compatible structure or union type. In the latter case, the
- // initial value of the object, including unnamed members, is
- // that of the expression.
- if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
- SemaRef.CheckSingleAssignmentConstraints(ElemType, expr)
- == Sema::Compatible) {
- SemaRef.DefaultFunctionArrayLvalueConversion(expr);
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
- ++Index;
- return;
- }
+ if (const ArrayType *arrayType = SemaRef.Context.getAsArrayType(ElemType)) {
+ // arrayType can be incomplete if we're initializing a flexible
+ // array member. There's nothing we can do with the completed
+ // type here, though.
- // Fall through for subaggregate initialization
+ if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) {
+ CheckStringInit(Str, ElemType, arrayType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ ++Index;
+ return;
}
+ // Fall through for subaggregate initialization.
+
+ } else if (SemaRef.getLangOptions().CPlusPlus) {
// C++ [dcl.init.aggr]p12:
+ // All implicit type conversions (clause 4) are considered when
+ // initializing the aggregate member with an ini- tializer from
+ // an initializer-list. If the initializer can initialize a
+ // member, the member is initialized. [...]
+
+ // FIXME: Better EqualLoc?
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation());
+ InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1);
+
+ if (Seq) {
+ ExprResult Result =
+ Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
+ if (Result.isInvalid())
+ hadError = true;
+
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.takeAs<Expr>());
+ ++Index;
+ return;
+ }
+
+ // Fall through for subaggregate initialization
+ } else {
+ // C99 6.7.8p13:
//
- // [...] Otherwise, if the member is itself a non-empty
- // subaggregate, brace elision is assumed and the initializer is
- // considered for the initialization of the first member of
- // the subaggregate.
- if (ElemType->isAggregateType() || ElemType->isVectorType()) {
- CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
- StructuredIndex);
- ++StructuredIndex;
- } else {
- // We cannot initialize this element, so let
- // PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
- SemaRef.Owned(expr));
- hadError = true;
+ // The initializer for a structure or union object that has
+ // automatic storage duration shall be either an initializer
+ // list as described below, or a single expression that has
+ // compatible structure or union type. In the latter case, the
+ // initial value of the object, including unnamed members, is
+ // that of the expression.
+ if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
+ SemaRef.CheckSingleAssignmentConstraints(ElemType, expr)
+ == Sema::Compatible) {
+ SemaRef.DefaultFunctionArrayLvalueConversion(expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
- ++StructuredIndex;
+ return;
}
+
+ // Fall through for subaggregate initialization
+ }
+
+ // C++ [dcl.init.aggr]p12:
+ //
+ // [...] Otherwise, if the member is itself a non-empty
+ // subaggregate, brace elision is assumed and the initializer is
+ // considered for the initialization of the first member of
+ // the subaggregate.
+ if (ElemType->isAggregateType() || ElemType->isVectorType()) {
+ CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
+ StructuredIndex);
+ ++StructuredIndex;
+ } else {
+ // We cannot initialize this element, so let
+ // PerformCopyInitialization produce the appropriate diagnostic.
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
+ SemaRef.Owned(expr));
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
}
}
@@ -936,11 +952,13 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
+ const ArrayType *arrayType = SemaRef.Context.getAsArrayType(DeclType);
+
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
- if (Expr *Str = IsStringInit(IList->getInit(Index), DeclType,
+ if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType,
SemaRef.Context)) {
- CheckStringInit(Str, DeclType, SemaRef);
+ CheckStringInit(Str, DeclType, arrayType, SemaRef);
// We place the string literal directly into the resulting
// initializer list. This is the only place where the structure
// of the structured initializer list doesn't match exactly,
@@ -952,8 +970,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
return;
}
}
- if (const VariableArrayType *VAT =
- SemaRef.Context.getAsVariableArrayType(DeclType)) {
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(arrayType)) {
// Check for VLAs; in standard C it would be possible to check this
// earlier, but I don't know where clang accepts VLAs (gcc accepts
// them in all sorts of strange places).
@@ -970,16 +987,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
llvm::APSInt maxElements(elementIndex.getBitWidth(),
elementIndex.isUnsigned());
bool maxElementsKnown = false;
- if (const ConstantArrayType *CAT =
- SemaRef.Context.getAsConstantArrayType(DeclType)) {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(arrayType)) {
maxElements = CAT->getSize();
elementIndex = elementIndex.extOrTrunc(maxElements.getBitWidth());
elementIndex.setIsUnsigned(maxElements.isUnsigned());
maxElementsKnown = true;
}
- QualType elementType = SemaRef.Context.getAsArrayType(DeclType)
- ->getElementType();
+ QualType elementType = arrayType->getElementType();
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
@@ -2059,6 +2074,7 @@ void InitializationSequence::Step::Destroy() {
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
+ case SK_ArrayInit:
break;
case SK_ConversionSequence:
@@ -2090,6 +2106,8 @@ bool InitializationSequence::isAmbiguous() const {
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
case FK_Incomplete:
+ case FK_ArrayTypeMismatch:
+ case FK_NonConstantArrayInit:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -2232,6 +2250,13 @@ void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddArrayInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_ArrayInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
SequenceKind = FailedSequence;
@@ -2416,6 +2441,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
FunctionDecl *Function = Best->Function;
+ // This is the overload that will actually be used for the initialization, so
+ // mark it as used.
+ S.MarkDeclarationReferenced(DeclLoc, Function);
+
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
T2 = Function->getResultType();
@@ -3020,6 +3049,7 @@ static void TryUserDefinedConversion(Sema &S,
}
FunctionDecl *Function = Best->Function;
+ S.MarkDeclarationReferenced(DeclLoc, Function);
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
@@ -3054,6 +3084,25 @@ static void TryUserDefinedConversion(Sema &S,
}
}
+/// \brief Determine whether we have compatible array types for the
+/// purposes of GNU by-copy array initialization.
+static bool hasCompatibleArrayTypes(ASTContext &Context,
+ const ArrayType *Dest,
+ const ArrayType *Source) {
+ // If the source and destination array types are equivalent, we're
+ // done.
+ if (Context.hasSameType(QualType(Dest, 0), QualType(Source, 0)))
+ return true;
+
+ // Make sure that the element types are the same.
+ if (!Context.hasSameType(Dest->getElementType(), Source->getElementType()))
+ return false;
+
+ // The only mismatch we allow is when the destination is an
+ // incomplete array type and the source is a constant array type.
+ return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
+}
+
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -3109,14 +3158,6 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
- // - If the destination type is an array of characters, an array of
- // char16_t, an array of char32_t, or an array of wchar_t, and the
- // initializer is a string literal, see 8.5.2.
- if (Initializer && IsStringInit(Initializer, DestType, Context)) {
- TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
- return;
- }
-
// - If the initializer is (), the object is value-initialized.
if (Kind.getKind() == InitializationKind::IK_Value ||
(Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) {
@@ -3130,10 +3171,34 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
+ // - If the destination type is an array of characters, an array of
+ // char16_t, an array of char32_t, or an array of wchar_t, and the
+ // initializer is a string literal, see 8.5.2.
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
- if (const ArrayType *AT = Context.getAsArrayType(DestType)) {
- if (AT->getElementType()->isAnyCharacterType())
+ if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) {
+ if (Initializer && IsStringInit(Initializer, DestAT, Context)) {
+ TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
+ return;
+ }
+
+ // Note: as an GNU C extension, we allow initialization of an
+ // array from a compound literal that creates an array of the same
+ // type, so long as the initializer has no side effects.
+ if (!S.getLangOptions().CPlusPlus && Initializer &&
+ isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
+ Initializer->getType()->isArrayType()) {
+ const ArrayType *SourceAT
+ = Context.getAsArrayType(Initializer->getType());
+ if (!hasCompatibleArrayTypes(S.Context, DestAT, SourceAT))
+ SetFailed(FK_ArrayTypeMismatch);
+ else if (Initializer->HasSideEffects(S.Context))
+ SetFailed(FK_NonConstantArrayInit);
+ else {
+ setSequenceKind(ArrayInit);
+ AddArrayInitStep(DestType);
+ }
+ } else if (DestAT->getElementType()->isAnyCharacterType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
else
SetFailed(FK_ArrayNeedsInitList);
@@ -3482,6 +3547,8 @@ static ExprResult CopyObject(Sema &S,
return S.Owned(CurInitExpr);
}
+ S.MarkDeclarationReferenced(Loc, Constructor);
+
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
// the copy constructor may have default arguments).
@@ -3616,7 +3683,8 @@ InitializationSequence::Perform(Sema &S,
case SK_ListInitialization:
case SK_CAssignment:
case SK_StringInit:
- case SK_ObjCObjectConversion: {
+ case SK_ObjCObjectConversion:
+ case SK_ArrayInit: {
assert(Args.size() == 1);
Expr *CurInitExpr = Args.get()[0];
if (!CurInitExpr) return ExprError();
@@ -4029,7 +4097,8 @@ InitializationSequence::Perform(Sema &S,
case SK_StringInit: {
QualType Ty = Step->Type;
- CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S);
+ CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty,
+ S.Context.getAsArrayType(Ty), S);
break;
}
@@ -4040,6 +4109,30 @@ InitializationSequence::Perform(Sema &S,
CurInit.release();
CurInit = S.Owned(CurInitExpr);
break;
+
+ case SK_ArrayInit:
+ // Okay: we checked everything before creating this step. Note that
+ // this is a GNU extension.
+ S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
+ << Step->Type << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+
+ // If the destination type is an incomplete array type, update the
+ // type accordingly.
+ if (ResultType) {
+ if (const IncompleteArrayType *IncompleteDest
+ = S.Context.getAsIncompleteArrayType(Step->Type)) {
+ if (const ConstantArrayType *ConstantSource
+ = S.Context.getAsConstantArrayType(CurInitExpr->getType())) {
+ *ResultType = S.Context.getConstantArrayType(
+ IncompleteDest->getElementType(),
+ ConstantSource->getSize(),
+ ArrayType::Normal, 0);
+ }
+ }
+ }
+
+ break;
}
}
@@ -4081,6 +4174,17 @@ bool InitializationSequence::Diagnose(Sema &S,
<< (Failure == FK_ArrayNeedsInitListOrStringLiteral);
break;
+ case FK_ArrayTypeMismatch:
+ case FK_NonConstantArrayInit:
+ S.Diag(Kind.getLocation(),
+ (Failure == FK_ArrayTypeMismatch
+ ? diag::err_array_init_different_type
+ : diag::err_array_init_non_constant_array))
+ << DestType.getNonReferenceType()
+ << Args[0]->getType()
+ << Args[0]->getSourceRange();
+ break;
+
case FK_AddressOfOverloadFailed: {
DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(Args[0],
@@ -4338,6 +4442,14 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
OS << "array requires initializer list or string literal";
break;
+ case FK_ArrayTypeMismatch:
+ OS << "array type mismatch";
+ break;
+
+ case FK_NonConstantArrayInit:
+ OS << "non-constant array initializer";
+ break;
+
case FK_AddressOfOverloadFailed:
OS << "address of overloaded function failed";
break;
@@ -4441,6 +4553,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case StringInit:
OS << "String initialization: ";
break;
+
+ case ArrayInit:
+ OS << "Array initialization: ";
+ break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4520,6 +4636,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case SK_ObjCObjectConversion:
OS << "Objective-C object conversion";
break;
+
+ case SK_ArrayInit:
+ OS << "array initialization";
+ break;
}
}
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 0fd0e08..3deb403 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -1132,7 +1133,11 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (AllowBuiltinCreation)
return LookupBuiltin(*this, R);
- return false;
+ // If we didn't find a use of this identifier, the ExternalSource
+ // may be able to handle the situation.
+ // Note: some lookup failures are expected!
+ // See e.g. R.isForRedeclaration().
+ return (ExternalSource && ExternalSource->LookupUnqualified(R, S));
}
/// @brief Perform qualified name lookup in the namespaces nominated by
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6fb789c..8d03285 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2261,6 +2261,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
+ S.MarkDeclarationReferenced(From->getLocStart(), Constructor);
+
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
// constructor (12.3.1), the initial standard conversion
@@ -2282,6 +2284,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
+ S.MarkDeclarationReferenced(From->getLocStart(), Conversion);
+
// C++ [over.ics.user]p1:
//
// [...] If the user-defined conversion is specified by a
@@ -3068,6 +3072,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!Best->FinalConversion.DirectBinding)
return false;
+ if (Best->Function)
+ S.MarkDeclarationReferenced(DeclLoc, Best->Function);
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
@@ -6280,15 +6286,6 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Best->Function->getAttr<UnavailableAttr>()))
return OR_Deleted;
- // C++ [basic.def.odr]p2:
- // An overloaded function is used if it is selected by overload resolution
- // when referred to from a potentially-evaluated expression. [Note: this
- // covers calls to named functions (5.2.2), operator overloading
- // (clause 13), user-defined conversions (12.3.2), allocation function for
- // placement new (5.3.4), as well as non-default initialization (8.5).
- if (Best->Function)
- S.MarkDeclarationReferenced(Loc, Best->Function);
-
return OR_Success;
}
@@ -7078,16 +7075,6 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
S.Diag(OpLoc, diag::note_ovl_too_many_candidates) << int(E - I);
}
-static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
- if (isa<UnresolvedLookupExpr>(E))
- return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D);
-
- return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D);
-}
-
-
-
-
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
@@ -7603,10 +7590,9 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
SourceLocation RParenLoc) {
CXXScopeSpec SS;
- if (ULE->getQualifier()) {
- SS.setScopeRep(ULE->getQualifier());
- SS.setRange(ULE->getQualifierRange());
- }
+ if (ULE->getQualifier())
+ SS.MakeTrivial(SemaRef.Context,
+ ULE->getQualifier(), ULE->getQualifierRange());
TemplateArgumentListInfo TABuffer;
const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
@@ -7691,6 +7677,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
+ MarkDeclarationReferenced(Fn->getExprLoc(), FDecl);
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl.getDecl(),
ULE->getNameLoc());
@@ -7713,11 +7700,15 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
break;
case OR_Deleted:
- Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << ULE->getName()
- << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ {
+ Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << ULE->getName()
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
+ << Fn->getSourceRange();
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ }
break;
}
@@ -7824,6 +7815,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched an overloaded operator. Build a call to that
// operator.
+ MarkDeclarationReferenced(OpLoc, FnDecl);
+
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
@@ -7895,6 +7888,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< UnaryOperator::getOpcodeStr(Opc)
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
<< Input->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
return ExprError();
@@ -8047,6 +8042,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched an overloaded operator. Build a call to that
// operator.
+ MarkDeclarationReferenced(OpLoc, FnDecl);
+
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
@@ -8161,6 +8158,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2);
return ExprError();
@@ -8228,6 +8227,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
+ MarkDeclarationReferenced(LLoc, FnDecl);
+
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
@@ -8307,6 +8308,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
case OR_Deleted:
Diag(LLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted() << "[]"
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
"[]", LLoc);
@@ -8399,6 +8402,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
+ MarkDeclarationReferenced(UnresExpr->getMemberLoc(), Method);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@@ -8422,7 +8426,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
case OR_Deleted:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
- << DeclName << MemExprE->getSourceRange();
+ << DeclName
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
+ << MemExprE->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -8594,7 +8601,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
- << Object->getType() << Object->getSourceRange();
+ << Object->getType()
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
+ << Object->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -8626,6 +8636,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
RParenLoc);
}
+ MarkDeclarationReferenced(LParenLoc, Best->Function);
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
@@ -8799,11 +8810,15 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
- << "->" << Base->getSourceRange();
+ << "->"
+ << Best->Function->getMessageUnavailableAttr(
+ !Best->Function->isDeleted())
+ << Base->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1);
return ExprError();
}
+ MarkDeclarationReferenced(OpLoc, Best->Function);
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index e995e8f..89957e6 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -92,6 +93,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
unsigned DiagID = diag::warn_unused_expr;
if (const ExprWithCleanups *Temps = dyn_cast<ExprWithCleanups>(E))
E = Temps->getSubExpr();
+ if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = TempExpr->getSubExpr();
E = E->IgnoreParenImpCasts();
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
@@ -143,7 +146,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
- DiagRuntimeBehavior(Loc, PDiag(DiagID) << R1 << R2);
+ DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2);
}
StmtResult
@@ -499,8 +502,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
bool HasDependentValue
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
unsigned CondWidth
- = HasDependentValue? 0
- : static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion));
+ = HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType();
// Accumulate all of the case values in a vector so that we can sort them
@@ -1392,19 +1394,29 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
return true;
}
+/// isOperandMentioned - Return true if the specified operand # is mentioned
+/// anywhere in the decomposed asm string.
+static bool isOperandMentioned(unsigned OpNo,
+ llvm::ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
+ for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
+ const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == OpNo)
+ return true;
+ }
+
+ return false;
+}
-StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
- bool IsSimple,
- bool IsVolatile,
- unsigned NumOutputs,
- unsigned NumInputs,
- IdentifierInfo **Names,
- MultiExprArg constraints,
- MultiExprArg exprs,
- Expr *asmString,
- MultiExprArg clobbers,
- SourceLocation RParenLoc,
- bool MSAsm) {
+StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ MultiExprArg constraints, MultiExprArg exprs,
+ Expr *asmString, MultiExprArg clobbers,
+ SourceLocation RParenLoc, bool MSAsm) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
reinterpret_cast<StringLiteral**>(constraints.get());
@@ -1529,8 +1541,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (!Info.hasTiedOperand()) continue;
unsigned TiedTo = Info.getTiedOperand();
+ unsigned InputOpNo = i+NumOutputs;
Expr *OutputExpr = Exprs[TiedTo];
- Expr *InputExpr = Exprs[i+NumOutputs];
+ Expr *InputExpr = Exprs[InputOpNo];
QualType InTy = InputExpr->getType();
QualType OutTy = OutputExpr->getType();
if (Context.hasSameType(InTy, OutTy))
@@ -1569,30 +1582,22 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
continue;
// If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote it and the asm string won't notice. Check this
- // case now.
+ // then we can promote the smaller one to a larger input and the asm string
+ // won't notice.
bool SmallerValueMentioned = false;
- for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
- AsmStmt::AsmStringPiece &Piece = Pieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == i+NumOutputs) {
- if (InSize < OutSize) {
- SmallerValueMentioned = true;
- break;
- }
- }
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == TiedTo) {
- if (InSize > OutSize) {
- SmallerValueMentioned = true;
- break;
- }
- }
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (isOperandMentioned(InputOpNo, Pieces)) {
+ // This is a use in the asm string of the smaller operand. Since we
+ // codegen this by promoting to a wider value, the asm will get printed
+ // "wrong".
+ SmallerValueMentioned |= InSize < OutSize;
+ }
+ if (isOperandMentioned(TiedTo, Pieces)) {
+ // If this is a reference to the output, and if the output is the larger
+ // value, then it's ok because we'll promote the input to the larger type.
+ SmallerValueMentioned |= OutSize < InSize;
}
// If the smaller value wasn't mentioned in the asm string, and if the
@@ -1601,7 +1606,20 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (!SmallerValueMentioned && InputDomain != AD_Other &&
OutputConstraintInfos[TiedTo].allowsRegister())
continue;
-
+
+ // Either both of the operands were mentioned or the smaller one was
+ // mentioned. One more special case that we'll allow: if the tied input is
+ // integer, unmentioned, and is a constant, then we'll allow truncating it
+ // down to the size of the destination.
+ if (InputDomain == AD_Int && OutputDomain == AD_Int &&
+ !isOperandMentioned(InputOpNo, Pieces) &&
+ InputExpr->isEvaluatable(Context)) {
+ ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast);
+ Exprs[InputOpNo] = InputExpr;
+ NS->setInputExpr(i, InputExpr);
+ continue;
+ }
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -1747,8 +1765,10 @@ public:
StmtResult
Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
MultiStmtArg RawHandlers) {
- if (!getLangOptions().Exceptions)
- Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+ // Don't report an error if 'try' is used in system headers.
+ if (!getLangOptions().Exceptions &&
+ !getSourceManager().isInSystemHeader(TryLoc))
+ Diag(TryLoc, diag::err_exceptions_disabled) << "try";
unsigned NumHandlers = RawHandlers.size();
assert(NumHandlers > 0 &&
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f0a0103..f02dd25 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -400,8 +400,7 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
return Owned(DependentScopeDeclRefExpr::Create(Context,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
- SS.getRange(),
+ SS.getWithLocInContext(Context),
NameInfo,
TemplateArgs));
}
@@ -783,8 +782,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
if (SS.isSet())
- T->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
- SS.getRange());
+ T->setQualifierInfo(SS.getWithLocInContext(T->getASTContext()));
}
DeclResult
@@ -2333,9 +2331,13 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
DeclarationNameInfo NameInfo(DTN->getIdentifier(),
Arg.getTemplateNameLoc());
+ // FIXME: TemplateArgumentLoc should store a NestedNameSpecifierLoc
+ // for the template name.
+ CXXScopeSpec SS;
+ SS.MakeTrivial(Context, DTN->getQualifier(),
+ Arg.getTemplateQualifierRange());
Expr *E = DependentScopeDeclRefExpr::Create(Context,
- DTN->getQualifier(),
- Arg.getTemplateQualifierRange(),
+ SS.getWithLocInContext(Context),
NameInfo);
// If we parsed the template argument as a pack expansion, create a
@@ -2868,6 +2870,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return false;
@@ -3610,7 +3613,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
= NestedNameSpecifier::Create(Context, 0, false,
ClassType.getTypePtr());
CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(Context, Qualifier, Loc);
// The actual value-ness of this is unimportant, but for
// internal consistency's sake, references to instance methods
@@ -5997,8 +6000,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
SourceLocation KeywordLoc, SourceRange NNSRange,
SourceLocation IILoc) {
CXXScopeSpec SS;
- SS.setScopeRep(NNS);
- SS.setRange(NNSRange);
+ SS.MakeTrivial(Context, NNS, NNSRange);
DeclContext *Ctx = computeDeclContext(SS);
if (!Ctx) {
@@ -6036,7 +6038,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
<< Name << Ctx << FullRange;
if (UnresolvedUsingValueDecl *Using
= dyn_cast<UnresolvedUsingValueDecl>(Result.getRepresentativeDecl())){
- SourceLocation Loc = Using->getTargetNestedNameRange().getBegin();
+ SourceLocation Loc = Using->getQualifierLoc().getBeginLoc();
Diag(Loc, diag::note_using_value_decl_missing_typename)
<< FixItHint::CreateInsertion(Loc, "typename ");
}
@@ -6168,16 +6170,18 @@ ExprResult Sema::RebuildExprInCurrentInstantiation(Expr *E) {
}
bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
- if (SS.isInvalid()) return true;
+ if (SS.isInvalid())
+ return true;
- NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(),
DeclarationName());
- NestedNameSpecifier *Rebuilt =
- Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange());
- if (!Rebuilt) return true;
+ NestedNameSpecifierLoc Rebuilt
+ = Rebuilder.TransformNestedNameSpecifierLoc(QualifierLoc);
+ if (!Rebuilt)
+ return true;
- SS.setScopeRep(Rebuilt);
+ SS.Adopt(Rebuilt);
return false;
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index bd0a618..139fafb 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -3004,12 +3004,12 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) {
LocalInstantiationScope InstScope(*this);
// Build template<class TemplParam> void Func(FuncParam);
- NamedDecl *TemplParam
- = TemplateTypeParmDecl::Create(Context, 0, Loc, 0, 0, 0, false, false);
- TemplateParameterList *TemplateParams
- = TemplateParameterList::Create(Context, Loc, Loc, &TemplParam, 1, Loc);
-
QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false);
+ TemplateTypeParmDecl TemplParam(0, Loc, 0, false, TemplArg, false);
+ NamedDecl *TemplParamPtr = &TemplParam;
+ FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr,
+ Loc);
+
QualType FuncParam =
SubstituteAutoTransform(*this, TemplArg).TransformType(Type);
@@ -3018,13 +3018,13 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) {
Deduced.resize(1);
QualType InitType = Init->getType();
unsigned TDF = 0;
- if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
+ if (AdjustFunctionParmAndArgTypesForDeduction(*this, &TemplateParams,
FuncParam, InitType, Init,
TDF))
return false;
TemplateDeductionInfo Info(Context, Loc);
- if (::DeduceTemplateArguments(*this, TemplateParams,
+ if (::DeduceTemplateArguments(*this, &TemplateParams,
FuncParam, InitType, Info, Deduced,
TDF))
return false;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 44f5913..ae0ac9c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2140,6 +2140,17 @@ Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
return Instantiator.TransformNestedNameSpecifier(NNS, Range);
}
+NestedNameSpecifierLoc
+Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!NNS)
+ return NestedNameSpecifierLoc();
+
+ TemplateInstantiator Instantiator(*this, TemplateArgs, NNS.getBeginLoc(),
+ DeclarationName());
+ return Instantiator.TransformNestedNameSpecifierLoc(NNS);
+}
+
/// \brief Do template substitution on declaration name info.
DeclarationNameInfo
Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c0150c0..3a40b6f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -27,33 +27,33 @@ using namespace clang;
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) {
- NestedNameSpecifier *OldQual = OldDecl->getQualifier();
- if (!OldQual) return false;
-
- SourceRange QualRange = OldDecl->getQualifierRange();
-
- NestedNameSpecifier *NewQual
- = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
- if (!NewQual)
+ if (!OldDecl->getQualifierLoc())
+ return false;
+
+ NestedNameSpecifierLoc NewQualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ TemplateArgs);
+
+ if (!NewQualifierLoc)
return true;
-
- NewDecl->setQualifierInfo(NewQual, QualRange);
+
+ NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
- NestedNameSpecifier *OldQual = OldDecl->getQualifier();
- if (!OldQual) return false;
-
- SourceRange QualRange = OldDecl->getQualifierRange();
-
- NestedNameSpecifier *NewQual
- = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
- if (!NewQual)
+ if (!OldDecl->getQualifierLoc())
+ return false;
+
+ NestedNameSpecifierLoc NewQualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ TemplateArgs);
+
+ if (!NewQualifierLoc)
return true;
-
- NewDecl->setQualifierInfo(NewQual, QualRange);
+
+ NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
@@ -120,9 +120,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
= NamespaceAliasDecl::Create(SemaRef.Context, Owner,
D->getNamespaceLoc(),
D->getAliasLoc(),
- D->getNamespace()->getIdentifier(),
- D->getQualifierRange(),
- D->getQualifier(),
+ D->getIdentifier(),
+ D->getQualifierLoc(),
D->getTargetNameLoc(),
D->getNamespace());
Owner->addDecl(Inst);
@@ -642,12 +641,12 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Instantiate the qualifier. We have to do this first in case
// we're a friend declaration, because if we are then we need to put
// the new declaration in the appropriate context.
- NestedNameSpecifier *Qualifier = Pattern->getQualifier();
- if (Qualifier) {
- Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
- Pattern->getQualifierRange(),
- TemplateArgs);
- if (!Qualifier) return 0;
+ NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
+ TemplateArgs);
+ if (!QualifierLoc)
+ return 0;
}
CXXRecordDecl *PrevDecl = 0;
@@ -668,10 +667,9 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// the appropriate context.
DeclContext *DC = Owner;
if (isFriend) {
- if (Qualifier) {
+ if (QualifierLoc) {
CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(Pattern->getQualifierRange());
+ SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (!DC) return 0;
} else {
@@ -692,10 +690,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
PrevDecl = PrevClassTemplate->getTemplatedDecl();
}
- if (!PrevClassTemplate && Qualifier) {
+ if (!PrevClassTemplate && QualifierLoc) {
SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
<< D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC
- << Pattern->getQualifierRange();
+ << QualifierLoc.getSourceRange();
return 0;
}
@@ -756,8 +754,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Pattern->getTagKeywordLoc(), PrevDecl,
/*DelayTypeCreation=*/true);
- if (Qualifier)
- RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange());
+ if (QualifierLoc)
+ RecordInst->setQualifierInfo(QualifierLoc);
ClassTemplateDecl *Inst
= ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -969,12 +967,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return 0;
QualType T = TInfo->getType();
- NestedNameSpecifier *Qualifier = D->getQualifier();
- if (Qualifier) {
- Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
- D->getQualifierRange(),
- TemplateArgs);
- if (!Qualifier) return 0;
+ NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
+ TemplateArgs);
+ if (!QualifierLoc)
+ return 0;
}
// If we're instantiating a local function declaration, put the result
@@ -982,10 +980,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
DeclContext *DC;
if (D->getDeclContext()->isFunctionOrMethod())
DC = Owner;
- else if (isFriend && Qualifier) {
+ else if (isFriend && QualifierLoc) {
CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(D->getQualifierRange());
+ SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (!DC) return 0;
} else {
@@ -999,8 +996,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype());
- if (Qualifier)
- Function->setQualifierInfo(Qualifier, D->getQualifierRange());
+ if (QualifierLoc)
+ Function->setQualifierInfo(QualifierLoc);
DeclContext *LexicalDC = Owner;
if (!isFriend && D->isOutOfLine()) {
@@ -1262,20 +1259,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return 0;
}
- NestedNameSpecifier *Qualifier = D->getQualifier();
- if (Qualifier) {
- Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
- D->getQualifierRange(),
+ NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
- if (!Qualifier) return 0;
+ if (!QualifierLoc)
+ return 0;
}
DeclContext *DC = Owner;
if (isFriend) {
- if (Qualifier) {
+ if (QualifierLoc) {
CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(D->getQualifierRange());
+ SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (DC && SemaRef.RequireCompleteDeclContext(SS, DC))
@@ -1318,8 +1314,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isInlineSpecified());
}
- if (Qualifier)
- Method->setQualifierInfo(Qualifier, D->getQualifierRange());
+ if (QualifierLoc)
+ Method->setQualifierInfo(QualifierLoc);
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -1641,12 +1637,13 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
}
Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
- // Using directives are never dependent, so they require no explicit
+ // Using directives are never dependent (and never contain any types or
+ // expressions), so they require no explicit instantiation work.
UsingDirectiveDecl *Inst
= UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getNamespaceKeyLocation(),
- D->getQualifierRange(), D->getQualifier(),
+ D->getQualifierLoc(),
D->getIdentLocation(),
D->getNominatedNamespace(),
D->getCommonAncestor());
@@ -1664,12 +1661,11 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
// template struct t<int>;
// Here, in using s1::f1, s1 refers to t<T>::s1;
// we need to substitute for t<int>::s1.
- NestedNameSpecifier *NNS =
- SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameDecl(),
- D->getNestedNameRange(),
- TemplateArgs);
- if (!NNS)
- return 0;
+ NestedNameSpecifierLoc QualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
+ TemplateArgs);
+ if (!QualifierLoc)
+ return 0;
// The name info is non-dependent, so no transformation
// is required.
@@ -1684,16 +1680,13 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
Sema::ForRedeclaration);
UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
- D->getNestedNameRange(),
D->getUsingLocation(),
- NNS,
+ QualifierLoc,
NameInfo,
D->isTypeName());
CXXScopeSpec SS;
- SS.setScopeRep(NNS);
- SS.setRange(D->getNestedNameRange());
-
+ SS.Adopt(QualifierLoc);
if (CheckRedeclaration) {
Prev.setHideTags(false);
SemaRef.LookupQualifiedName(Prev, Owner);
@@ -1752,16 +1745,14 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
- NestedNameSpecifier *NNS =
- SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
- D->getTargetNestedNameRange(),
- TemplateArgs);
- if (!NNS)
+ NestedNameSpecifierLoc QualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
+ TemplateArgs);
+ if (!QualifierLoc)
return 0;
CXXScopeSpec SS;
- SS.setRange(D->getTargetNestedNameRange());
- SS.setScopeRep(NNS);
+ SS.Adopt(QualifierLoc);
// Since NameInfo refers to a typename, it cannot be a C++ special name.
// Hence, no tranformation is required for it.
@@ -1779,16 +1770,13 @@ Decl * TemplateDeclInstantiator
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
- NestedNameSpecifier *NNS =
- SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
- D->getTargetNestedNameRange(),
- TemplateArgs);
- if (!NNS)
+ NestedNameSpecifierLoc QualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs);
+ if (!QualifierLoc)
return 0;
-
+
CXXScopeSpec SS;
- SS.setRange(D->getTargetNestedNameRange());
- SS.setScopeRep(NNS);
+ SS.Adopt(QualifierLoc);
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index c88baa5..ba80076 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1395,6 +1395,56 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) {
return QT;
}
+static void DiagnoseIgnoredQualifiers(unsigned Quals,
+ SourceLocation ConstQualLoc,
+ SourceLocation VolatileQualLoc,
+ SourceLocation RestrictQualLoc,
+ Sema& S) {
+ std::string QualStr;
+ unsigned NumQuals = 0;
+ SourceLocation Loc;
+
+ FixItHint ConstFixIt;
+ FixItHint VolatileFixIt;
+ FixItHint RestrictFixIt;
+
+ // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
+ // find a range and grow it to encompass all the qualifiers, regardless of
+ // the order in which they textually appear.
+ if (Quals & Qualifiers::Const) {
+ ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
+ Loc = ConstQualLoc;
+ ++NumQuals;
+ QualStr = "const";
+ }
+ if (Quals & Qualifiers::Volatile) {
+ VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
+ if (NumQuals == 0) {
+ Loc = VolatileQualLoc;
+ QualStr = "volatile";
+ } else {
+ QualStr += " volatile";
+ }
+ ++NumQuals;
+ }
+ if (Quals & Qualifiers::Restrict) {
+ RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
+ if (NumQuals == 0) {
+ Loc = RestrictQualLoc;
+ QualStr = "restrict";
+ } else {
+ QualStr += " restrict";
+ }
+ ++NumQuals;
+ }
+
+ assert(NumQuals > 0 && "No known qualifiers?");
+
+ S.Diag(Loc, diag::warn_qual_return_type)
+ << QualStr << NumQuals
+ << ConstFixIt << VolatileFixIt << RestrictFixIt;
+}
+
/// GetTypeForDeclarator - Convert the type for the specified
/// declarator to Type instances.
///
@@ -1450,8 +1500,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getAttributes())
distributeTypeAttrsFromDeclarator(state, T);
+ // C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
+ // In C++0x, a function declarator using 'auto' must have a trailing return
+ // type (this is checked later) and we can skip this. In other languages
+ // using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- !D.isFunctionDeclarator()) {
+ (!getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
@@ -1483,7 +1537,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case Declarator::TypeNameContext:
if (!AutoAllowedInTypeName)
- Error = 8; // Generic
+ Error = 10; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
@@ -1492,6 +1546,32 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ Error = 8;
+
+ // In Objective-C it is an error to use 'auto' on a function declarator.
+ if (D.isFunctionDeclarator())
+ Error = 9;
+
+ // C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
+ // contains a trailing return type. That is only legal at the outermost
+ // level. Check all declarator chunks (outermost first) anyway, to give
+ // better diagnostics.
+ if (getLangOptions().CPlusPlus0x && Error != -1) {
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ unsigned chunkIndex = e - i - 1;
+ state.setCurrentChunkIndex(chunkIndex);
+ DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
+ if (DeclType.Kind == DeclaratorChunk::Function) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (FTI.TrailingReturnType) {
+ Error = -1;
+ break;
+ }
+ }
+ }
+ }
+
if (Error != -1) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
<< Error;
@@ -1499,7 +1579,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
D.setInvalidType(true);
}
}
-
+
if (T.isNull())
return Context.getNullTypeSourceInfo();
@@ -1600,21 +1680,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// of the type, otherwise the argument list is ().
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- // C99 6.7.5.3p1: The return type may not be a function or array type.
- // For conversion functions, we'll diagnose this particular error later.
- if ((T->isArrayType() || T->isFunctionType()) &&
- (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
- unsigned diagID = diag::err_func_returning_array_function;
- // Last processing chunk in block context means this function chunk
- // represents the block.
- if (chunkIndex == 0 &&
- D.getContext() == Declarator::BlockLiteralContext)
- diagID = diag::err_block_returning_array_function;
- Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
- T = Context.IntTy;
- D.setInvalidType(true);
- }
-
// Check for auto functions and trailing return type and adjust the
// return type accordingly.
if (!D.isInvalidType()) {
@@ -1627,8 +1692,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.TrailingReturnType) {
- if (T.hasQualifiers() || !isa<AutoType>(T)) {
- // T must be exactly 'auto' at this point. See CWG issue 681.
+ // T must be exactly 'auto' at this point. See CWG issue 681.
+ if (isa<ParenType>(T)) {
+ Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ diag::err_trailing_return_in_parens)
+ << T << D.getDeclSpec().getSourceRange();
+ D.setInvalidType(true);
+ } else if (T.hasQualifiers() || !isa<AutoType>(T)) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -1641,48 +1711,48 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
+ // C99 6.7.5.3p1: The return type may not be a function or array type.
+ // For conversion functions, we'll diagnose this particular error later.
+ if ((T->isArrayType() || T->isFunctionType()) &&
+ (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
+ unsigned diagID = diag::err_func_returning_array_function;
+ // Last processing chunk in block context means this function chunk
+ // represents the block.
+ if (chunkIndex == 0 &&
+ D.getContext() == Declarator::BlockLiteralContext)
+ diagID = diag::err_block_returning_array_function;
+ Diag(DeclType.Loc, diagID) << T->isFunctionType() << T;
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
+
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
- if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
+ if (T->isPointerType() && T.getCVRQualifiers() &&
+ (!getLangOptions().CPlusPlus || !T->isDependentType())) {
+ assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
+ DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
+ assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer);
+
+ DeclaratorChunk::PointerTypeInfo &PTI = ReturnTypeChunk.Ptr;
+
+ DiagnoseIgnoredQualifiers(PTI.TypeQuals,
+ SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
+ *this);
+
+ } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
(!getLangOptions().CPlusPlus ||
(!T->isDependentType() && !T->isRecordType()))) {
- unsigned Quals = D.getDeclSpec().getTypeQualifiers();
- std::string QualStr;
- unsigned NumQuals = 0;
- SourceLocation Loc;
- if (Quals & Qualifiers::Const) {
- Loc = D.getDeclSpec().getConstSpecLoc();
- ++NumQuals;
- QualStr = "const";
- }
- if (Quals & Qualifiers::Volatile) {
- if (NumQuals == 0) {
- Loc = D.getDeclSpec().getVolatileSpecLoc();
- QualStr = "volatile";
- } else
- QualStr += " volatile";
- ++NumQuals;
- }
- if (Quals & Qualifiers::Restrict) {
- if (NumQuals == 0) {
- Loc = D.getDeclSpec().getRestrictSpecLoc();
- QualStr = "restrict";
- } else
- QualStr += " restrict";
- ++NumQuals;
- }
- assert(NumQuals > 0 && "No known qualifiers?");
-
- SemaDiagnosticBuilder DB = Diag(Loc, diag::warn_qual_return_type);
- DB << QualStr << NumQuals;
- if (Quals & Qualifiers::Const)
- DB << FixItHint::CreateRemoval(D.getDeclSpec().getConstSpecLoc());
- if (Quals & Qualifiers::Volatile)
- DB << FixItHint::CreateRemoval(D.getDeclSpec().getVolatileSpecLoc());
- if (Quals & Qualifiers::Restrict)
- DB << FixItHint::CreateRemoval(D.getDeclSpec().getRestrictSpecLoc());
+
+ DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
+ D.getDeclSpec().getConstSpecLoc(),
+ D.getDeclSpec().getVolatileSpecLoc(),
+ D.getDeclSpec().getRestrictSpecLoc(),
+ *this);
}
-
+
if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
@@ -1825,6 +1895,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
llvm_unreachable("Nested-name-specifier must name a type");
break;
@@ -2047,7 +2118,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
}
-
+
if (T.isNull())
return Context.getNullTypeSourceInfo();
else if (D.isInvalidType())
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 944e6a1..57a44ad 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -385,6 +385,17 @@ public:
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = 0);
+ /// \brief Transform the given nested-name-specifier with source-location
+ /// information.
+ ///
+ /// By default, transforms all of the types and declarations within the
+ /// nested-name-specifier. Subclasses may override this function to provide
+ /// alternate behavior.
+ NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = 0);
+
/// \brief Transform the given declaration name.
///
/// By default, transforms the types of conversion function, constructor,
@@ -759,8 +770,7 @@ public:
SourceRange NNSRange,
SourceLocation IdLoc) {
CXXScopeSpec SS;
- SS.setScopeRep(NNS);
- SS.setRange(NNSRange);
+ SS.MakeTrivial(SemaRef.Context, NNS, NNSRange);
if (NNS->isDependent()) {
// If the name is still dependent, just build a new dependent name type.
@@ -878,6 +888,16 @@ public:
NamespaceDecl *NS);
/// \brief Build a new nested-name-specifier given the prefix and the
+ /// namespace alias named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceAliasDecl *Alias);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
/// type named in the next step in the nested-name-specifier.
///
/// By default, performs semantic analysis when building the new
@@ -1083,11 +1103,8 @@ public:
StmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- return getSema().Owned(
- new (getSema().Context) DeclStmt(
- DeclGroupRef::Create(getSema().Context,
- Decls, NumDecls),
- StartLoc, EndLoc));
+ Sema::DeclGroupPtrTy DG = getSema().BuildDeclaratorGroup(Decls, NumDecls);
+ return getSema().ActOnDeclStmt(DG, StartLoc, EndLoc);
}
/// \brief Build a new inline asm statement.
@@ -1246,8 +1263,7 @@ public:
const DeclarationNameInfo &NameInfo,
TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(QualifierRange);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
// FIXME: loses template args.
@@ -1268,13 +1284,12 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXPseudoDestructorExpr(Expr *Base,
- SourceLocation OperatorLoc,
- bool isArrow,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TypeSourceInfo *ScopeType,
- SourceLocation CCLoc,
- SourceLocation TildeLoc,
+ SourceLocation OperatorLoc,
+ bool isArrow,
+ CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeType,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed);
/// \brief Build a new unary operator expression.
@@ -1386,8 +1401,7 @@ public:
CXXScopeSpec SS;
if (Qualifier) {
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
}
getSema().DefaultFunctionArrayConversion(Base);
@@ -1873,13 +1887,12 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildDependentScopeDeclRefExpr(NestedNameSpecifier *NNS,
- SourceRange QualifierRange,
+ ExprResult RebuildDependentScopeDeclRefExpr(
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.setRange(QualifierRange);
- SS.setScopeRep(NNS);
+ SS.Adopt(QualifierLoc);
if (TemplateArgs)
return getSema().BuildQualifiedTemplateIdExpr(SS, NameInfo,
@@ -1964,8 +1977,7 @@ public:
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
@@ -1988,8 +2000,7 @@ public:
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
@@ -2263,6 +2274,11 @@ private:
QualType ObjectType,
NamedDecl *FirstQualifierInScope,
NestedNameSpecifier *Prefix);
+
+ TypeLoc TransformTypeInObjectScope(TypeLoc TL,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
+ CXXScopeSpec &SS);
};
template<typename Derived>
@@ -2459,6 +2475,19 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias
+ = cast_or_null<NamespaceAliasDecl>(
+ getDerived().TransformDecl(Range.getBegin(),
+ NNS->getAsNamespaceAlias()));
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ Alias == NNS->getAsNamespaceAlias())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, Alias);
+ }
+
case NestedNameSpecifier::Global:
// There is no meaningful transformation that one could perform on the
// global scope.
@@ -2490,6 +2519,103 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
}
template<typename Derived>
+NestedNameSpecifierLoc
+TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope) {
+ llvm::SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
+ for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
+ Qualifier = Qualifier.getPrefix())
+ Qualifiers.push_back(Qualifier);
+
+ CXXScopeSpec SS;
+ while (!Qualifiers.empty()) {
+ NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
+ NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
+
+ switch (QNNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/0,
+ *QNNS->getAsIdentifier(),
+ Q.getLocalBeginLoc(),
+ Q.getLocalEndLoc(),
+ ObjectType, false, SS,
+ FirstQualifierInScope, false))
+ return NestedNameSpecifierLoc();
+
+ break;
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS
+ = cast_or_null<NamespaceDecl>(
+ getDerived().TransformDecl(
+ Q.getLocalBeginLoc(),
+ QNNS->getAsNamespace()));
+ SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc());
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias
+ = cast_or_null<NamespaceAliasDecl>(
+ getDerived().TransformDecl(Q.getLocalBeginLoc(),
+ QNNS->getAsNamespaceAlias()));
+ SS.Extend(SemaRef.Context, Alias, Q.getLocalBeginLoc(),
+ Q.getLocalEndLoc());
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ // There is no meaningful transformation that one could perform on the
+ // global scope.
+ SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc());
+ break;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
+ FirstQualifierInScope, SS);
+
+ if (!TL)
+ return NestedNameSpecifierLoc();
+
+ if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
+ (SemaRef.getLangOptions().CPlusPlus0x &&
+ TL.getType()->isEnumeralType())) {
+ assert(!TL.getType().hasLocalQualifiers() &&
+ "Can't get cv-qualifiers here");
+ SS.Extend(SemaRef.Context, /*FIXME:*/SourceLocation(), TL,
+ Q.getLocalEndLoc());
+ break;
+ }
+
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
+ << TL.getType() << SS.getRange();
+ return NestedNameSpecifierLoc();
+ }
+ }
+
+ // The qualifier-in-scope only applies to the leftmost entity.
+ FirstQualifierInScope = 0;
+ }
+
+ // Don't rebuild the nested-name-specifier if we don't have to.
+ if (SS.getScopeRep() == NNS.getNestedNameSpecifier() &&
+ !getDerived().AlwaysRebuild())
+ return NNS;
+
+ // If we can re-use the source-location data from the original
+ // nested-name-specifier, do so.
+ if (SS.location_size() == NNS.getDataLength() &&
+ memcmp(SS.location_data(), NNS.getOpaqueData(), SS.location_size()) == 0)
+ return NestedNameSpecifierLoc(SS.getScopeRep(), NNS.getOpaqueData());
+
+ // Allocate new nested-name-specifier location information.
+ return SS.getWithLocInContext(SemaRef.Context);
+}
+
+template<typename Derived>
DeclarationNameInfo
TreeTransform<Derived>
::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo) {
@@ -3085,7 +3211,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSI,
QualType ObjectType,
NamedDecl *UnqualLookup,
NestedNameSpecifier *Prefix) {
- // TODO: in some cases, we might be some verification to do here.
+ // TODO: in some cases, we might have some verification to do here.
if (ObjectType.isNull())
return getDerived().TransformType(TSI);
@@ -3122,6 +3248,62 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSI,
return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
+template<typename Derived>
+TypeLoc
+TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
+ QualType ObjectType,
+ NamedDecl *UnqualLookup,
+ CXXScopeSpec &SS) {
+ // FIXME: Painfully copy-paste from the above!
+
+ // TODO: in some cases, we might have some verification to do here.
+ if (ObjectType.isNull()) {
+ TypeLocBuilder TLB;
+ TLB.reserve(TL.getFullDataSize());
+ QualType Result = getDerived().TransformType(TLB, TL);
+ if (Result.isNull())
+ return TypeLoc();
+
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
+ }
+
+ QualType T = TL.getType();
+ if (getDerived().AlreadyTransformed(T))
+ return TL;
+
+ TypeLocBuilder TLB;
+ QualType Result;
+
+ if (isa<TemplateSpecializationType>(T)) {
+ TemplateSpecializationTypeLoc SpecTL
+ = cast<TemplateSpecializationTypeLoc>(TL);
+
+ TemplateName Template =
+ getDerived().TransformTemplateName(SpecTL.getTypePtr()->getTemplateName(),
+ ObjectType, UnqualLookup);
+ if (Template.isNull())
+ return TypeLoc();
+
+ Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
+ Template);
+ } else if (isa<DependentTemplateSpecializationType>(T)) {
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = cast<DependentTemplateSpecializationTypeLoc>(TL);
+
+ Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
+ SpecTL,
+ SS.getScopeRep());
+ } else {
+ // Nothing special needs to be done for these.
+ Result = getDerived().TransformType(TLB, TL);
+ }
+
+ if (Result.isNull())
+ return TypeLoc();
+
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
+}
+
template <class TyLoc> static inline
QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
TyLoc NewT = TLB.push<TyLoc>(T.getType());
@@ -4337,7 +4519,8 @@ QualType TreeTransform<Derived>::
TemplateArgumentListInfo NewTemplateArgs;
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
-
+
+ // FIXME: Nested-name-specifier source location info!
typedef TemplateArgumentLocContainerIterator<
DependentTemplateSpecializationTypeLoc> ArgIterator;
if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
@@ -6426,21 +6609,22 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
return ExprError();
QualType ObjectType = ObjectTypePtr.get();
- NestedNameSpecifier *Qualifier = E->getQualifier();
- if (Qualifier) {
- Qualifier
- = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange(),
- ObjectType);
- if (!Qualifier)
+ NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc, ObjectType);
+ if (!QualifierLoc)
return ExprError();
}
+ CXXScopeSpec SS;
+ SS.Adopt(QualifierLoc);
PseudoDestructorTypeStorage Destroyed;
if (E->getDestroyedTypeInfo()) {
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
- ObjectType, 0, Qualifier);
+ ObjectType, 0,
+ QualifierLoc.getNestedNameSpecifier());
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
@@ -6451,12 +6635,6 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
E->getDestroyedTypeLoc());
} else {
// Look for a destructor known with the given name.
- CXXScopeSpec SS;
- if (Qualifier) {
- SS.setScopeRep(Qualifier);
- SS.setRange(E->getQualifierRange());
- }
-
ParsedType T = SemaRef.getDestructorName(E->getTildeLoc(),
*E->getDestroyedTypeIdentifier(),
E->getDestroyedTypeLoc(),
@@ -6481,8 +6659,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
return getDerived().RebuildCXXPseudoDestructorExpr(Base.get(),
E->getOperatorLoc(),
E->isArrow(),
- Qualifier,
- E->getQualifierRange(),
+ SS,
ScopeTypeInfo,
E->getColonColonLoc(),
E->getTildeLoc(),
@@ -6538,8 +6715,7 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
if (!Qualifier)
return ExprError();
- SS.setScopeRep(Qualifier);
- SS.setRange(Old->getQualifierRange());
+ SS.MakeTrivial(SemaRef.Context, Qualifier, Old->getQualifierRange());
}
if (Old->getNamingClass()) {
@@ -6611,10 +6787,9 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E) {
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
- if (!NNS)
+ NestedNameSpecifierLoc QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
+ if (!QualifierLoc)
return ExprError();
// TODO: If this is a conversion-function-id, verify that the
@@ -6628,14 +6803,13 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
if (!E->hasExplicitTemplateArgs()) {
if (!getDerived().AlwaysRebuild() &&
- NNS == E->getQualifier() &&
+ QualifierLoc == E->getQualifierLoc() &&
// Note: it is sufficient to compare the Name component of NameInfo:
// if name has not changed, DNLoc has not changed either.
NameInfo.getName() == E->getDeclName())
return SemaRef.Owned(E);
- return getDerived().RebuildDependentScopeDeclRefExpr(NNS,
- E->getQualifierRange(),
+ return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
NameInfo,
/*TemplateArgs*/ 0);
}
@@ -6646,8 +6820,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
TransArgs))
return ExprError();
- return getDerived().RebuildDependentScopeDeclRefExpr(NNS,
- E->getQualifierRange(),
+ return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
NameInfo,
&TransArgs);
}
@@ -7560,14 +7733,15 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
NamedDecl *FirstQualifierInScope) {
CXXScopeSpec SS;
// FIXME: The source location information is all wrong.
- SS.setRange(Range);
- SS.setScopeRep(Prefix);
- return static_cast<NestedNameSpecifier *>(
- SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(),
- Range.getEnd(), II,
- ObjectType,
- FirstQualifierInScope,
- false, false));
+ SS.MakeTrivial(SemaRef.Context, Prefix, Range);
+ if (SemaRef.BuildCXXNestedNameSpecifier(0, II, /*FIXME:*/Range.getBegin(),
+ /*FIXME:*/Range.getEnd(),
+ ObjectType, false,
+ SS, FirstQualifierInScope,
+ false))
+ return 0;
+
+ return SS.getScopeRep();
}
template<typename Derived>
@@ -7582,6 +7756,14 @@ template<typename Derived>
NestedNameSpecifier *
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
+ NamespaceAliasDecl *Alias) {
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, Alias);
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
bool TemplateKW,
QualType T) {
if (T->isDependentType() || T->isRecordType() ||
@@ -7612,8 +7794,7 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
CXXScopeSpec SS;
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
UnqualifiedId Name;
Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation());
Sema::TemplateTy Template;
@@ -7633,8 +7814,7 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
OverloadedOperatorKind Operator,
QualType ObjectType) {
CXXScopeSpec SS;
- SS.setRange(SourceRange(getDerived().getBaseLocation()));
- SS.setScopeRep(Qualifier);
+ SS.MakeTrivial(SemaRef.Context, Qualifier, SourceRange(getDerived().getBaseLocation()));
UnqualifiedId Name;
SourceLocation SymbolLocations[3]; // FIXME: Bogus location information.
Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(),
@@ -7740,18 +7920,11 @@ ExprResult
TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation OperatorLoc,
bool isArrow,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ CXXScopeSpec &SS,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed) {
- CXXScopeSpec SS;
- if (Qualifier) {
- SS.setRange(QualifierRange);
- SS.setScopeRep(Qualifier);
- }
-
QualType BaseType = Base->getType();
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 3d20a52..1e0a7c4 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -107,6 +107,19 @@ class TypeLocBuilder {
return DI;
}
+ /// \brief Copies the type-location information to the given AST context and
+ /// returns a \c TypeLoc referring into the AST context.
+ TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
+#ifndef NDEBUG
+ assert(T == LastTy && "type doesn't match last type pushed!");
+#endif
+
+ size_t FullDataSize = Capacity - Index;
+ void *Mem = Context.Allocate(FullDataSize);
+ memcpy(Mem, &Buffer[Index], FullDataSize);
+ return TypeLoc(T, Mem);
+ }
+
private:
TypeLoc pushImpl(QualType T, size_t LocalSize) {
#ifndef NDEBUG
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ce87b11..c3953ba 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -97,8 +97,9 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
diag::warn_pch_lax_vector_conversions);
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
- PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
PARSE_LANGOPT_IMPORTANT(ObjCExceptions, diag::warn_pch_objc_exceptions);
+ PARSE_LANGOPT_IMPORTANT(CXXExceptions, diag::warn_pch_cxx_exceptions);
+ PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
PARSE_LANGOPT_IMPORTANT(MSBitfields, diag::warn_pch_ms_bitfields);
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
@@ -243,14 +244,15 @@ FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
llvm::StringRef OriginalFileName,
- std::string &SuggestedPredefines) {
+ std::string &SuggestedPredefines,
+ FileManager &FileMgr) {
// We are in the context of an implicit include, so the predefines buffer will
// have a #include entry for the PCH file itself (as normalized by the
// preprocessor initialization). Find it and skip over it in the checking
// below.
llvm::SmallString<256> PCHInclude;
PCHInclude += "#include \"";
- PCHInclude += NormalizeDashIncludePath(OriginalFileName);
+ PCHInclude += NormalizeDashIncludePath(OriginalFileName, FileMgr);
PCHInclude += "\"\n";
std::pair<llvm::StringRef,llvm::StringRef> Split =
llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
@@ -960,7 +962,8 @@ bool ASTReader::CheckPredefinesBuffers() {
if (Listener)
return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
ActualOriginalFileName,
- SuggestedPredefines);
+ SuggestedPredefines,
+ FileMgr);
return false;
}
@@ -2799,8 +2802,9 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(LaxVectorConversions);
PARSE_LANGOPT(AltiVec);
PARSE_LANGOPT(Exceptions);
- PARSE_LANGOPT(SjLjExceptions);
PARSE_LANGOPT(ObjCExceptions);
+ PARSE_LANGOPT(CXXExceptions);
+ PARSE_LANGOPT(SjLjExceptions);
PARSE_LANGOPT(MSBitfields);
PARSE_LANGOPT(NeXTRuntime);
PARSE_LANGOPT(Freestanding);
@@ -4476,8 +4480,7 @@ void ASTReader::ReadDeclarationNameInfo(PerFileData &F,
void ASTReader::ReadQualifierInfo(PerFileData &F, QualifierInfo &Info,
const RecordData &Record, unsigned &Idx) {
- Info.NNS = ReadNestedNameSpecifier(Record, Idx);
- Info.NNSRange = ReadSourceRange(F, Record, Idx);
+ Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
unsigned NumTPLists = Record[Idx++];
Info.NumTemplParamLists = NumTPLists;
if (NumTPLists) {
@@ -4726,6 +4729,13 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
break;
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias
+ = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
+ break;
+ }
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *T = GetType(Record[Idx++]).getTypePtrOrNull();
@@ -4748,6 +4758,109 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
return NNS;
}
+NestedNameSpecifierLoc
+ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifier *NNS = 0, *Prev = 0;
+ llvm::SmallVector<char, 32> LocationData;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ // Nested-name-specifier
+ IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
+ NNS = NestedNameSpecifier::Create(*Context, Prev, II);
+
+ // Location information
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ unsigned RawStart = Range.getBegin().getRawEncoding();
+ unsigned RawEnd = Range.getEnd().getRawEncoding();
+ LocationData.append(reinterpret_cast<char*>(&RawStart),
+ reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
+ LocationData.append(reinterpret_cast<char*>(&RawEnd),
+ reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ // Nested-name-specifier
+ NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, NS);
+
+ // Location information
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ unsigned RawStart = Range.getBegin().getRawEncoding();
+ unsigned RawEnd = Range.getEnd().getRawEncoding();
+ LocationData.append(reinterpret_cast<char*>(&RawStart),
+ reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
+ LocationData.append(reinterpret_cast<char*>(&RawEnd),
+ reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ // Nested-name-specifier
+ NamespaceAliasDecl *Alias
+ = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
+
+ // Location information
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ unsigned RawStart = Range.getBegin().getRawEncoding();
+ unsigned RawEnd = Range.getEnd().getRawEncoding();
+ LocationData.append(reinterpret_cast<char*>(&RawStart),
+ reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
+ LocationData.append(reinterpret_cast<char*>(&RawEnd),
+ reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
+
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ // Nested-name-specifier
+ bool Template = Record[Idx++];
+ TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
+ if (!T)
+ return NestedNameSpecifierLoc();
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Template,
+ T->getType().getTypePtr());
+
+ // Location information.
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ unsigned RawLocation = ColonColonLoc.getRawEncoding();
+ void *OpaqueTypeData = T->getTypeLoc().getOpaqueData();
+ LocationData.append(reinterpret_cast<char*>(&OpaqueTypeData),
+ (reinterpret_cast<char*>(&OpaqueTypeData)
+ + sizeof(void *)));
+ LocationData.append(reinterpret_cast<char*>(&RawLocation),
+ (reinterpret_cast<char*>(&RawLocation) +
+ sizeof(unsigned)));
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ // Nested-name-specifier
+ NNS = NestedNameSpecifier::GlobalSpecifier(*Context);
+
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ unsigned RawLocation = ColonColonLoc.getRawEncoding();
+ LocationData.append(reinterpret_cast<char*>(&RawLocation),
+ (reinterpret_cast<char*>(&RawLocation) +
+ sizeof(unsigned)));
+ break;
+ }
+ }
+ Prev = NNS;
+ }
+
+ void *Mem = Context->Allocate(LocationData.size(), llvm::alignOf<void*>());
+ memcpy(Mem, LocationData.data(), LocationData.size());
+ return NestedNameSpecifierLoc(NNS, Mem);
+}
+
SourceRange
ASTReader::ReadSourceRange(PerFileData &F, const RecordData &Record,
unsigned &Idx) {
@@ -4932,4 +5045,3 @@ ASTReader::PerFileData::~PerFileData() {
delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable);
}
-
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index dec15dd..493ccba 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -744,17 +744,15 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
VisitNamedDecl(D);
D->NamespaceLoc = ReadSourceLocation(Record, Idx);
- D->setQualifierRange(ReadSourceRange(Record, Idx));
- D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
D->IdentLoc = ReadSourceLocation(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
D->Namespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
}
void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
VisitNamedDecl(D);
D->setUsingLocation(ReadSourceLocation(Record, Idx));
- D->setNestedNameRange(ReadSourceRange(Record, Idx));
- D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
D->FirstUsingShadow = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]));
D->setTypeName(Record[Idx++]);
@@ -777,27 +775,24 @@ void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
VisitNamedDecl(D);
D->UsingLoc = ReadSourceLocation(Record, Idx);
D->NamespaceLoc = ReadSourceLocation(Record, Idx);
- D->QualifierRange = ReadSourceRange(Record, Idx);
- D->Qualifier = Reader.ReadNestedNameSpecifier(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
D->NominatedNamespace = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
D->CommonAncestor = cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]));
}
void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
VisitValueDecl(D);
- D->setTargetNestedNameRange(ReadSourceRange(Record, Idx));
D->setUsingLoc(ReadSourceLocation(Record, Idx));
- D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
}
void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
VisitTypeDecl(D);
- D->TargetNestedNameRange = ReadSourceRange(Record, Idx);
D->UsingLocation = ReadSourceLocation(Record, Idx);
D->TypenameLocation = ReadSourceLocation(Record, Idx);
- D->TargetNestedNameSpecifier = Reader.ReadNestedNameSpecifier(Record, Idx);
+ D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
}
void ASTDeclReader::ReadCXXDefinitionData(
@@ -1432,30 +1427,33 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
break;
case DECL_NAMESPACE_ALIAS:
D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(), 0, SourceRange(), 0,
+ SourceLocation(), 0,
+ NestedNameSpecifierLoc(),
SourceLocation(), 0);
break;
case DECL_USING:
- D = UsingDecl::Create(*Context, 0, SourceRange(), SourceLocation(),
- 0, DeclarationNameInfo(), false);
+ D = UsingDecl::Create(*Context, 0, SourceLocation(),
+ NestedNameSpecifierLoc(), DeclarationNameInfo(),
+ false);
break;
case DECL_USING_SHADOW:
D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0);
break;
case DECL_USING_DIRECTIVE:
D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(), SourceRange(), 0,
+ SourceLocation(), NestedNameSpecifierLoc(),
SourceLocation(), 0, 0);
break;
case DECL_UNRESOLVED_USING_VALUE:
D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(),
- SourceRange(), 0,
+ NestedNameSpecifierLoc(),
DeclarationNameInfo());
break;
case DECL_UNRESOLVED_USING_TYPENAME:
D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(),
- SourceLocation(), SourceRange(),
- 0, SourceLocation(),
+ SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(),
DeclarationName());
break;
case DECL_CXX_RECORD:
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 4e91c98..42f0b1a 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1167,14 +1167,13 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
VisitExpr(E);
- E->setBase(Reader.ReadSubExpr());
- E->setArrow(Record[Idx++]);
- E->setOperatorLoc(ReadSourceLocation(Record, Idx));
- E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
- E->setQualifierRange(ReadSourceRange(Record, Idx));
- E->setScopeTypeInfo(GetTypeSourceInfo(Record, Idx));
- E->setColonColonLoc(ReadSourceLocation(Record, Idx));
- E->setTildeLoc(ReadSourceLocation(Record, Idx));
+ E->Base = Reader.ReadSubExpr();
+ E->IsArrow = Record[Idx++];
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ E->ScopeType = GetTypeSourceInfo(Record, Idx);
+ E->ColonColonLoc = ReadSourceLocation(Record, Idx);
+ E->TildeLoc = ReadSourceLocation(Record, Idx);
IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx);
if (II)
@@ -1220,10 +1219,9 @@ ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
if (Record[Idx++])
ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
Record[Idx++]);
-
+
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
- E->setQualifierRange(ReadSourceRange(Record, Idx));
- E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
}
void
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 8fcb535..383ca3d 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1023,8 +1023,9 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.LaxVectorConversions);
Record.push_back(LangOpts.AltiVec);
Record.push_back(LangOpts.Exceptions); // Support exception handling.
- Record.push_back(LangOpts.SjLjExceptions);
Record.push_back(LangOpts.ObjCExceptions);
+ Record.push_back(LangOpts.CXXExceptions);
+ Record.push_back(LangOpts.SjLjExceptions);
Record.push_back(LangOpts.MSBitfields); // MS-compatible structure layout
Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
@@ -3275,15 +3276,21 @@ void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
Record);
}
-void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record) {
+void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo,
+ RecordDataImpl &Record) {
if (TInfo == 0) {
AddTypeRef(QualType(), Record);
return;
}
- AddTypeRef(TInfo->getType(), Record);
+ AddTypeLoc(TInfo->getTypeLoc(), Record);
+}
+
+void ASTWriter::AddTypeLoc(TypeLoc TL, RecordDataImpl &Record) {
+ AddTypeRef(TL.getType(), Record);
+
TypeLocWriter TLW(*this, Record);
- for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ for (; !TL.isNull(); TL = TL.getNextTypeLoc())
TLW.Visit(TL);
}
@@ -3436,8 +3443,7 @@ void ASTWriter::AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
void ASTWriter::AddQualifierInfo(const QualifierInfo &Info,
RecordDataImpl &Record) {
- AddNestedNameSpecifier(Info.NNS, Record);
- AddSourceRange(Info.NNSRange, Record);
+ AddNestedNameSpecifierLoc(Info.QualifierLoc, Record);
Record.push_back(Info.NumTemplParamLists);
for (unsigned i=0, e=Info.NumTemplParamLists; i != e; ++i)
AddTemplateParameterList(Info.TemplParamLists[i], Record);
@@ -3469,6 +3475,10 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
AddDeclRef(NNS->getAsNamespace(), Record);
break;
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDeclRef(NNS->getAsNamespaceAlias(), Record);
+ break;
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
AddTypeRef(QualType(NNS->getAsType(), 0), Record);
@@ -3482,6 +3492,55 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
}
}
+void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ RecordDataImpl &Record) {
+ // Nested name specifiers usually aren't too long. I think that 8 would
+ // typically accomodate the vast majority.
+ llvm::SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
+
+ // Push each of the nested-name-specifiers's onto a stack for
+ // serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS.getPrefix();
+ }
+
+ Record.push_back(NestedNames.size());
+ while(!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier::SpecifierKind Kind
+ = NNS.getNestedNameSpecifier()->getKind();
+ Record.push_back(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), Record);
+ AddSourceRange(NNS.getLocalSourceRange(), Record);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
+ AddTypeLoc(NNS.getTypeLoc(), Record);
+ AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
+ break;
+
+ case NestedNameSpecifier::Global:
+ AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record);
+ break;
+ }
+ }
+}
+
void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) {
TemplateName::NameKind Kind = Name.getKind();
Record.push_back(Kind);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index ce07e138..12d1226 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -697,18 +697,16 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getNamespaceLoc(), Record);
- Writer.AddSourceRange(D->getQualifierRange(), Record);
- Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
Writer.AddSourceLocation(D->getTargetNameLoc(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclRef(D->getNamespace(), Record);
Code = serialization::DECL_NAMESPACE_ALIAS;
}
void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
VisitNamedDecl(D);
- Writer.AddSourceRange(D->getNestedNameRange(), Record);
Writer.AddSourceLocation(D->getUsingLocation(), Record);
- Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Writer.AddDeclRef(D->FirstUsingShadow, Record);
Record.push_back(D->isTypeName());
@@ -728,8 +726,7 @@ void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getUsingLoc(), Record);
Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
- Writer.AddSourceRange(D->getQualifierRange(), Record);
- Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclRef(D->getNominatedNamespace(), Record);
Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
Code = serialization::DECL_USING_DIRECTIVE;
@@ -737,9 +734,8 @@ void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
VisitValueDecl(D);
- Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
Writer.AddSourceLocation(D->getUsingLoc(), Record);
- Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Code = serialization::DECL_UNRESOLVED_USING_VALUE;
}
@@ -747,10 +743,9 @@ void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
VisitTypeDecl(D);
- Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
Writer.AddSourceLocation(D->getUsingLoc(), Record);
Writer.AddSourceLocation(D->getTypenameLoc(), Record);
- Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Code = serialization::DECL_UNRESOLVED_USING_TYPENAME;
}
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 8a5ffe9..af846a9 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1150,8 +1150,7 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
Writer.AddStmt(E->getBase());
Record.push_back(E->isArrow());
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
Writer.AddTypeSourceInfo(E->getScopeTypeInfo(), Record);
Writer.AddSourceLocation(E->getColonColonLoc(), Record);
Writer.AddSourceLocation(E->getTildeLoc(), Record);
@@ -1217,9 +1216,8 @@ ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
AddExplicitTemplateArgumentList(Args);
}
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
Writer.AddDeclarationNameInfo(E->NameInfo, Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF;
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 9194791..25e224e 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -22,21 +24,15 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
- public CheckerVisitor<ArrayBoundChecker> {
- BuiltinBug *BT;
+ public CheckerV2<check::Location> {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- ArrayBoundChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
+ void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
};
}
-void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ArrayBoundChecker());
-}
-
-void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
- bool isLoad) {
+void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
+ CheckerContext &C) const {
// Check for out of bound array element access.
const MemRegion *R = l.getAsRegion();
if (!R)
@@ -69,8 +65,8 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
return;
if (!BT)
- BT = new BuiltinBug("Out-of-bound array access",
- "Access out-of-bound array element (buffer overflow)");
+ BT.reset(new BuiltinBug("Out-of-bound array access",
+ "Access out-of-bound array element (buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
@@ -80,7 +76,7 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
RangedBugReport *report =
new RangedBugReport(*BT, BT->getDescription(), N);
- report->addRange(S->getSourceRange());
+ report->addRange(C.getStmt()->getSourceRange());
C.EmitReport(report);
return;
}
@@ -90,3 +86,7 @@ void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
assert(StInBound);
C.addTransition(StInBound);
}
+
+void ento::registerArrayBoundChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ArrayBoundChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 1b6c528..7aff201 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -16,14 +16,14 @@
#include "BasicObjCFoundationChecks.h"
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -69,22 +69,23 @@ static inline bool isNil(SVal X) {
//===----------------------------------------------------------------------===//
namespace {
- class NilArgChecker : public CheckerVisitor<NilArgChecker> {
- APIMisuse *BT;
- void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
+ class NilArgChecker : public CheckerV2<check::PreObjCMessage> {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+
+ void WarnNilArg(CheckerContext &C,
+ const ObjCMessage &msg, unsigned Arg) const;
+
public:
- NilArgChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
}
void NilArgChecker::WarnNilArg(CheckerContext &C,
const ObjCMessage &msg,
- unsigned int Arg)
+ unsigned int Arg) const
{
if (!BT)
- BT = new APIMisuse("nil argument");
+ BT.reset(new APIMisuse("nil argument"));
if (ExplodedNode *N = C.generateSink()) {
llvm::SmallString<128> sbuf;
@@ -98,9 +99,8 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
}
}
-void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg)
-{
+void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
if (!ReceiverType)
return;
@@ -140,14 +140,14 @@ void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
//===----------------------------------------------------------------------===//
namespace {
-class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
- APIMisuse* BT;
- IdentifierInfo* II;
+class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable IdentifierInfo* II;
public:
- CFNumberCreateChecker() : BT(0), II(0) {}
- ~CFNumberCreateChecker() {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ CFNumberCreateChecker() : II(0) {}
+
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+
private:
void EmitError(const TypedRegion* R, const Expr* Ex,
uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
@@ -247,9 +247,8 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
}
#endif
-void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE)
-{
+void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const Expr* Callee = CE->getCallee();
const GRState *state = C.getState();
SVal CallV = state->getSVal(Callee);
@@ -335,7 +334,7 @@ void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
<< " bits of the input integer will be lost.";
if (!BT)
- BT = new APIMisuse("Bad use of CFNumberCreate");
+ BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
@@ -348,19 +347,18 @@ void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
//===----------------------------------------------------------------------===//
namespace {
-class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
- APIMisuse *BT;
- IdentifierInfo *Retain, *Release;
+class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable IdentifierInfo *Retain, *Release;
public:
- CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
+ CFRetainReleaseChecker(): Retain(0), Release(0) {}
+ void checkPreStmt(const CallExpr* CE, CheckerContext& C) const;
};
} // end anonymous namespace
-void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
- const CallExpr* CE) {
+void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
+ CheckerContext& C) const {
// If the CallExpr doesn't have exactly 1 argument just give up checking.
if (CE->getNumArgs() != 1)
return;
@@ -377,7 +375,7 @@ void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
ASTContext &Ctx = C.getASTContext();
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
- BT = new APIMisuse("null passed to CFRetain/CFRelease");
+ BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
}
// Check if we called CFRetain/CFRelease.
@@ -431,28 +429,24 @@ void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
//===----------------------------------------------------------------------===//
namespace {
-class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
- Selector releaseS;
- Selector retainS;
- Selector autoreleaseS;
- Selector drainS;
- BugType *BT;
-public:
- ClassReleaseChecker()
- : BT(0) {}
+class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> {
+ mutable Selector releaseS;
+ mutable Selector retainS;
+ mutable Selector autoreleaseS;
+ mutable Selector drainS;
+ mutable llvm::OwningPtr<BugType> BT;
- static void *getTag() { static int x = 0; return &x; }
-
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+public:
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
}
-void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
if (!BT) {
- BT = new APIMisuse("message incorrectly sent to class instead of class "
- "instance");
+ BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
+ "instance"));
ASTContext &Ctx = C.getASTContext();
releaseS = GetNullarySelector("release", Ctx);
@@ -488,34 +482,18 @@ void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
// Check registration.
//===----------------------------------------------------------------------===//
-static void RegisterNilArgChecker(ExprEngine& Eng) {
- Eng.registerCheck(new NilArgChecker());
-}
-
void ento::registerNilArgChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterNilArgChecker);
-}
-
-static void RegisterCFNumberCreateChecker(ExprEngine& Eng) {
- Eng.registerCheck(new CFNumberCreateChecker());
+ mgr.registerChecker<NilArgChecker>();
}
void ento::registerCFNumberCreateChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCFNumberCreateChecker);
-}
-
-static void RegisterCFRetainReleaseChecker(ExprEngine& Eng) {
- Eng.registerCheck(new CFRetainReleaseChecker());
+ mgr.registerChecker<CFNumberCreateChecker>();
}
void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCFRetainReleaseChecker);
-}
-
-static void RegisterClassReleaseChecker(ExprEngine& Eng) {
- Eng.registerCheck(new ClassReleaseChecker());
+ mgr.registerChecker<CFRetainReleaseChecker>();
}
void ento::registerClassReleaseChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterClassReleaseChecker);
+ mgr.registerChecker<ClassReleaseChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index e172a52..e308396 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -1,9 +1,7 @@
-set(LLVM_TARGET_DEFINITIONS Checkers.td)
-tablegen(Checkers.inc
- -gen-clang-sa-checkers
- -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
-add_custom_target(ClangSACheckers
- DEPENDS Checkers.inc)
+clang_tablegen(Checkers.inc -gen-clang-sa-checkers
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../include
+ SOURCE Checkers.td
+ TARGET ClangSACheckers)
set(LLVM_USED_LIBS clangBasic clangAST)
@@ -29,8 +27,8 @@ add_clang_library(clangStaticAnalyzerCheckers
DebugCheckers.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
- ExprEngine.cpp
ExperimentalChecks.cpp
+ ExprEngine.cpp
FixedAddressChecker.cpp
IdempotentOperationChecker.cpp
LLVMConventionsChecker.cpp
@@ -48,7 +46,7 @@ add_clang_library(clangStaticAnalyzerCheckers
PthreadLockChecker.cpp
ReturnPointerRangeChecker.cpp
ReturnUndefChecker.cpp
- StackAddrLeakChecker.cpp
+ StackAddrEscapeChecker.cpp
StreamChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 03f9047..2566e3c 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -13,9 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/StringSwitch.h"
@@ -23,75 +24,86 @@ using namespace clang;
using namespace ento;
namespace {
-class CStringChecker : public CheckerVisitor<CStringChecker> {
- BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
+class CStringChecker : public CheckerV2< eval::Call,
+ check::PreStmt<DeclStmt>,
+ check::LiveSymbols,
+ check::DeadSymbols,
+ check::RegionChanges
+ > {
+ mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds, BT_BoundsWrite,
+ BT_Overlap, BT_NotCString;
public:
- CStringChecker()
- : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
- {}
static void *getTag() { static int tag; return &tag; }
- bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
- void MarkLiveSymbols(const GRState *state, SymbolReaper &SR);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SR);
- bool wantsRegionChangeUpdate(const GRState *state);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
+ void checkLiveSymbols(const GRState *state, SymbolReaper &SR) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ bool wantsRegionChangeUpdate(const GRState *state) const;
- const GRState *EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool*);
+ const GRState *checkRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) const;
- typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *);
+ typedef void (CStringChecker::*FnCheck)(CheckerContext &,
+ const CallExpr *) const;
- void evalMemcpy(CheckerContext &C, const CallExpr *CE);
- void evalMemmove(CheckerContext &C, const CallExpr *CE);
- void evalBcopy(CheckerContext &C, const CallExpr *CE);
+ void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
+ void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *Source, const Expr *Dest,
- bool Restricted = false);
+ bool Restricted = false) const;
- void evalMemcmp(CheckerContext &C, const CallExpr *CE);
+ void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
- void evalstrLength(CheckerContext &C, const CallExpr *CE);
+ void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
+ void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
+ void evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
+ bool IsStrnlen = false) const;
- void evalStrcpy(CheckerContext &C, const CallExpr *CE);
- void evalStpcpy(CheckerContext &C, const CallExpr *CE);
- void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd);
+ void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
+ bool isStrncpy) const;
// Utility methods
std::pair<const GRState*, const GRState*>
- assumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty);
-
- const GRState *setCStringLength(const GRState *state, const MemRegion *MR,
- SVal strLength);
- SVal getCStringLengthForRegion(CheckerContext &C, const GRState *&state,
- const Expr *Ex, const MemRegion *MR);
+ static assumeZero(CheckerContext &C,
+ const GRState *state, SVal V, QualType Ty);
+
+ static const GRState *setCStringLength(const GRState *state,
+ const MemRegion *MR, SVal strLength);
+ static SVal getCStringLengthForRegion(CheckerContext &C,
+ const GRState *&state,
+ const Expr *Ex, const MemRegion *MR);
SVal getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf);
+ const Expr *Ex, SVal Buf) const;
- const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state,
- const Expr *Ex, SVal V);
+ static const GRState *InvalidateBuffer(CheckerContext &C,
+ const GRState *state,
+ const Expr *Ex, SVal V);
- bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
- const MemRegion *MR);
+ static bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+ const MemRegion *MR);
// Re-usable checks
const GRState *checkNonNull(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l);
+ const Expr *S, SVal l) const;
const GRState *CheckLocation(CheckerContext &C, const GRState *state,
const Expr *S, SVal l,
- bool IsDestination = false);
+ bool IsDestination = false) const;
const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf = NULL,
- bool FirstIsDestination = false);
+ bool FirstIsDestination = false) const;
const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *First,
- const Expr *Second);
+ const Expr *Second) const;
void emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second);
+ const Stmt *First, const Stmt *Second) const;
};
class CStringLength {
@@ -110,14 +122,6 @@ namespace ento {
}
}
-static void RegisterCStringChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CStringChecker());
-}
-
-void ento::registerCStringChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCStringChecker);
-}
-
//===----------------------------------------------------------------------===//
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//
@@ -136,7 +140,7 @@ CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V,
const GRState *CStringChecker::checkNonNull(CheckerContext &C,
const GRState *state,
- const Expr *S, SVal l) {
+ const Expr *S, SVal l) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -150,11 +154,11 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
return NULL;
if (!BT_Null)
- BT_Null = new BuiltinBug("API",
- "Null pointer argument in call to byte string function");
+ BT_Null.reset(new BuiltinBug("API",
+ "Null pointer argument in call to byte string function"));
// Generate a report for this bug.
- BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null);
+ BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get());
EnhancedBugReport *report = new EnhancedBugReport(*BT,
BT->getDescription(), N);
@@ -173,7 +177,7 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
const GRState *CStringChecker::CheckLocation(CheckerContext &C,
const GRState *state,
const Expr *S, SVal l,
- bool IsDestination) {
+ bool IsDestination) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -209,16 +213,16 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
BuiltinBug *BT;
if (IsDestination) {
if (!BT_BoundsWrite) {
- BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
- "Byte string function overflows destination buffer");
+ BT_BoundsWrite.reset(new BuiltinBug("Out-of-bound array access",
+ "Byte string function overflows destination buffer"));
}
- BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
+ BT = static_cast<BuiltinBug*>(BT_BoundsWrite.get());
} else {
if (!BT_Bounds) {
- BT_Bounds = new BuiltinBug("Out-of-bound array access",
- "Byte string function accesses out-of-bound array element");
+ BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
+ "Byte string function accesses out-of-bound array element"));
}
- BT = static_cast<BuiltinBug*>(BT_Bounds);
+ BT = static_cast<BuiltinBug*>(BT_Bounds.get());
}
// FIXME: It would be nice to eventually make this diagnostic more clear,
@@ -243,7 +247,7 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
- bool FirstIsDestination) {
+ bool FirstIsDestination) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -306,7 +310,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
const GRState *state,
const Expr *Size,
const Expr *First,
- const Expr *Second) {
+ const Expr *Second) const {
// Do a simple check for overlap: if the two arguments are from the same
// buffer, see if the end of the first is greater than the start of the second
// or vice versa.
@@ -413,13 +417,13 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
}
void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second) {
+ const Stmt *First, const Stmt *Second) const {
ExplodedNode *N = C.generateSink(state);
if (!N)
return;
if (!BT_Overlap)
- BT_Overlap = new BugType("Unix API", "Improper arguments");
+ BT_Overlap.reset(new BugType("Unix API", "Improper arguments"));
// Generate a report for this bug.
RangedBugReport *report =
@@ -480,13 +484,14 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
- SVal strLength = svalBuilder.getMetadataSymbolVal(getTag(), MR, Ex, sizeTy, Count);
+ SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
+ MR, Ex, sizeTy, Count);
state = state->set<CStringLength>(MR, strLength);
return strLength;
}
SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf) {
+ const Expr *Ex, SVal Buf) const {
const MemRegion *MR = Buf.getAsRegion();
if (!MR) {
// If we can't get a region, see if it's something we /know/ isn't a
@@ -495,8 +500,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
+ BT_NotCString.reset(new BuiltinBug("API",
+ "Argument is not a null-terminated string."));
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -551,8 +556,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
// The caller should always be prepared to handle this case.
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
+ BT_NotCString.reset(new BuiltinBug("API",
+ "Argument is not a null-terminated string."));
llvm::SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -652,7 +657,7 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
const Expr *Size, const Expr *Dest,
- const Expr *Source, bool Restricted) {
+ const Expr *Source, bool Restricted) const {
// See if the size argument is zero.
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
@@ -685,7 +690,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
}
-void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
@@ -694,7 +699,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
@@ -703,12 +708,12 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
}
-void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
// void bcopy(const void *src, void *dst, size_t n);
evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
}
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// int memcmp(const void *s1, const void *s2, size_t n);
const Expr *Left = CE->getArg(0);
const Expr *Right = CE->getArg(1);
@@ -774,8 +779,20 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
}
}
-void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalstrLength(CheckerContext &C,
+ const CallExpr *CE) const {
// size_t strlen(const char *s);
+ evalstrLengthCommon(C, CE, /* IsStrnlen = */ false);
+}
+
+void CStringChecker::evalstrnLength(CheckerContext &C,
+ const CallExpr *CE) const {
+ // size_t strnlen(const char *s, size_t maxlen);
+ evalstrLengthCommon(C, CE, /* IsStrnlen = */ true);
+}
+
+void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
+ bool IsStrnlen) const {
const GRState *state = C.getState();
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg);
@@ -791,6 +808,32 @@ void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
if (strLength.isUndef())
return;
+ // If the check is for strnlen() then bind the return value to no more than
+ // the maxlen value.
+ if (IsStrnlen) {
+ const Expr *maxlenExpr = CE->getArg(1);
+ SVal maxlenVal = state->getSVal(maxlenExpr);
+
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+
+ QualType cmpTy = C.getSValBuilder().getContext().IntTy;
+ const GRState *stateTrue, *stateFalse;
+
+ // Check if the strLength is greater than or equal to the maxlen
+ llvm::tie(stateTrue, stateFalse) =
+ state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_GE,
+ *strLengthNL, *maxlenValNL,
+ cmpTy)));
+
+ // If the strLength is greater than or equal to the maxlen, set strLength
+ // to maxlen
+ if (stateTrue && !stateFalse) {
+ strLength = maxlenVal;
+ }
+ }
+
// If getCStringLength couldn't figure out the length, conjure a return
// value, so it can be used in constraints, at least.
if (strLength.isUnknown()) {
@@ -804,18 +847,23 @@ void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
}
}
-void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
+ // char *strcpy(char *restrict dst, const char *restrict src);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false);
+}
+
+void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
// char *strcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ false);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true);
}
-void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
+void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
// char *stpcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ true);
+ evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
- bool returnEnd) {
+ bool returnEnd, bool isStrncpy) const {
const GRState *state = C.getState();
// Check that the destination is non-null
@@ -840,6 +888,31 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (strLength.isUndef())
return;
+ if (isStrncpy) {
+ // Get the max number of characters to copy
+ const Expr *lenExpr = CE->getArg(2);
+ SVal lenVal = state->getSVal(lenExpr);
+
+ NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+
+ QualType cmpTy = C.getSValBuilder().getContext().IntTy;
+ const GRState *stateTrue, *stateFalse;
+
+ // Check if the max number to copy is less than the length of the src
+ llvm::tie(stateTrue, stateFalse) =
+ state->assume(cast<DefinedOrUnknownSVal>
+ (C.getSValBuilder().evalBinOpNN(state, BO_GT,
+ *strLengthNL, *lenValNL,
+ cmpTy)));
+
+ if (stateTrue) {
+ // Max number to copy is less than the length of the src, so the actual
+ // strLength copied is the max number arg.
+ strLength = lenVal;
+ }
+ }
+
SVal Result = (returnEnd ? UnknownVal() : DstVal);
// If the destination is a MemRegion, try to check for a buffer overflow and
@@ -889,7 +962,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// The driver method, and other Checker callbacks.
//===----------------------------------------------------------------------===//
-bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const GRState *state = C.getState();
@@ -912,8 +985,10 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
+ .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
.Case("strlen", &CStringChecker::evalstrLength)
+ .Case("strnlen", &CStringChecker::evalstrnLength)
.Case("bcopy", &CStringChecker::evalBcopy)
.Default(NULL);
@@ -926,7 +1001,7 @@ bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return true;
}
-void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Record string length for char a[] = "abc";
const GRState *state = C.getState();
@@ -962,15 +1037,15 @@ void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
C.addTransition(state);
}
-bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) {
+bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
-const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool *) {
+const GRState *
+CStringChecker::checkRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1017,7 +1092,8 @@ const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
return state->set<CStringLength>(Entries);
}
-void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
+void CStringChecker::checkLiveSymbols(const GRState *state,
+ SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
CStringLength::EntryMap Entries = state->get<CStringLength>();
@@ -1029,7 +1105,8 @@ void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
}
}
-void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
+void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
if (!SR.hasDeadSymbols())
return;
@@ -1051,3 +1128,7 @@ void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
state = state->set<CStringLength>(Entries);
C.generateNode(state);
}
+
+void ento::registerCStringChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CStringChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 518cf96..6a4506b 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -11,30 +11,25 @@
// whether the size of the symbolic region is a multiple of the size of T.
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/CharUnits.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
-#include "InternalChecks.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
namespace {
-class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
- BuiltinBug *BT;
+class CastSizeChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- CastSizeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+ void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}
-void *CastSizeChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
+void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
const Expr *E = CE->getSubExpr();
ASTContext &Ctx = C.getASTContext();
QualType ToTy = Ctx.getCanonicalType(CE->getType());
@@ -74,9 +69,9 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
if (regionSize % typeSize != 0) {
if (ExplodedNode *errorNode = C.generateSink()) {
if (!BT)
- BT = new BuiltinBug("Cast region with wrong size.",
+ BT.reset(new BuiltinBug("Cast region with wrong size.",
"Cast a region whose size is not a multiple of the"
- " destination type size.");
+ " destination type size."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
errorNode);
R->addRange(CE->getSourceRange());
@@ -86,6 +81,6 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
}
-void ento::RegisterCastSizeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastSizeChecker());
+void ento::registerCastSizeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CastSizeChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 8ec226a..04cc253 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -14,31 +14,25 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
-class CastToStructChecker
- : public CheckerVisitor<CastToStructChecker> {
- BuiltinBug *BT;
+class CastToStructChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- CastToStructChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+ void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}
-void *CastToStructChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
- const CastExpr *CE) {
+void CastToStructChecker::checkPreStmt(const CastExpr *CE,
+ CheckerContext &C) const {
const Expr *E = CE->getSubExpr();
ASTContext &Ctx = C.getASTContext();
QualType OrigTy = Ctx.getCanonicalType(E->getType());
@@ -64,10 +58,10 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
if (!OrigPointeeTy->isRecordType()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Cast from non-struct type to struct type",
+ BT.reset(new BuiltinBug("Cast from non-struct type to struct type",
"Casting a non-structure type to a structure type "
"and accessing a field can lead to memory access "
- "errors or data corruption.");
+ "errors or data corruption."));
RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
C.EmitReport(R);
@@ -75,10 +69,6 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
}
}
-static void RegisterCastToStructChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastToStructChecker());
-}
-
void ento::registerCastToStructChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterCastToStructChecker);
+ mgr.registerChecker<CastToStructChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 1dc7486..894b961 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -71,16 +71,16 @@ def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
HelpText<"Warn about private ivars that are never used">,
DescFile<"ObjCUnusedIVarsChecker.cpp">;
-}
+} // end "cocoa"
-def StackAddrLeakChecker : Checker<"StackAddrLeak">,
+def StackAddrEscapeChecker : Checker<"StackAddrEscape">,
InPackage<Core>,
- HelpText<"Check that addresses to stack memory are not leaked outside the function">,
- DescFile<"StackAddrLeakChecker.cpp">;
+ HelpText<"Check that addresses to stack memory do not escape the function">,
+ DescFile<"StackAddrEscapeChecker.cpp">;
def DeadStoresChecker : Checker<"DeadStores">,
InPackage<Core>,
- HelpText<"Check for stores to dead variables">,
+ HelpText<"Check for values stored to a variables that are never read afterwards">,
DescFile<"DeadStoresChecker.cpp">;
def UnixAPIChecker : Checker<"API">,
@@ -90,12 +90,12 @@ def UnixAPIChecker : Checker<"API">,
def MacOSXAPIChecker : Checker<"API">,
InPackage<MacOSX>,
- HelpText<"Check calls to various MacOSXAPIChecker">,
+ HelpText<"Check for proper uses of various Mac OS X APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
def CFNumberCreateChecker : Checker<"CFNumber">,
InPackage<MacOSX>,
- HelpText<"Check for CFNumberCreate">,
+ HelpText<"Check for proper uses of CFNumberCreate">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
@@ -137,7 +137,8 @@ def CStringChecker : Checker<"CString">,
def UnreachableCodeChecker : Checker<"UnreachableCode">,
InPackage<CoreExperimental>,
HelpText<"Check unreachable code">,
- DescFile<"UnreachableCodeChecker.cpp">;
+ DescFile<"UnreachableCodeChecker.cpp">,
+ Hidden; // Must be specified explicitly in order to run.
def IdempotentOperationChecker : Checker<"IdempotentOps">,
InPackage<CoreExperimental>,
@@ -174,6 +175,21 @@ def SecuritySyntaxChecker : Checker<"SecuritySyntactic">,
HelpText<"Perform quick security checks that require no data flow">,
DescFile<"CheckSecuritySyntaxOnly.cpp">;
+def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check for an out-of-bound pointer being returned to callers">,
+ DescFile<"ReturnPointerRangeChecker.cpp">;
+
+def ArrayBoundChecker : Checker<"ArrayBound">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check for an out-of-bound pointer being returned to callers">,
+ DescFile<"ArrayBoundChecker.cpp">;
+
+def CastSizeChecker : Checker<"CastSize">,
+ InPackage<CoreExperimental>,
+ HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
+ DescFile<"CastSizeChecker.cpp">;
+
def ObjCDeallocChecker : Checker<"Dealloc">,
InPackage<CocoaExperimental>,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 36e76d0..b6eef6d 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -12,9 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -37,38 +38,30 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
// | |
// bug<--foo()-- JAIL_ENTERED<--foo()--
-class ChrootChecker : public CheckerVisitor<ChrootChecker> {
- IdentifierInfo *II_chroot, *II_chdir;
+class ChrootChecker : public CheckerV2<eval::Call, check::PreStmt<CallExpr> > {
+ mutable IdentifierInfo *II_chroot, *II_chdir;
// This bug refers to possibly break out of a chroot() jail.
- BuiltinBug *BT_BreakJail;
+ mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail;
public:
- ChrootChecker() : II_chroot(0), II_chdir(0), BT_BreakJail(0) {}
+ ChrootChecker() : II_chroot(0), II_chdir(0) {}
static void *getTag() {
static int x;
return &x;
}
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- virtual void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
private:
- void Chroot(CheckerContext &C, const CallExpr *CE);
- void Chdir(CheckerContext &C, const CallExpr *CE);
+ void Chroot(CheckerContext &C, const CallExpr *CE) const;
+ void Chdir(CheckerContext &C, const CallExpr *CE) const;
};
} // end anonymous namespace
-static void RegisterChrootChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ChrootChecker());
-}
-
-void ento::registerChrootChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterChrootChecker);
-}
-
-bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -94,7 +87,7 @@ bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return false;
}
-void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
GRStateManager &Mgr = state->getStateManager();
@@ -104,7 +97,7 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
C.addTransition(state);
}
-void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
GRStateManager &Mgr = state->getStateManager();
@@ -131,7 +124,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
}
// Check the jail state before any function call except chroot and chdir().
-void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -155,9 +148,9 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.generateNode()) {
if (!BT_BreakJail)
- BT_BreakJail = new BuiltinBug("Break out of jail",
+ BT_BreakJail.reset(new BuiltinBug("Break out of jail",
"No call of chdir(\"/\") immediately "
- "after chroot");
+ "after chroot"));
BugReport *R = new BugReport(*BT_BreakJail,
BT_BreakJail->getDescription(), N);
C.EmitReport(R);
@@ -165,3 +158,7 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
return;
}
+
+void ento::registerChrootChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ChrootChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
index 94f200f..5c0c950 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
@@ -16,7 +16,9 @@
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
+#include "map"
using namespace clang;
using namespace ento;
@@ -28,6 +30,7 @@ class ClangSACheckerProvider : public CheckerProvider {
public:
virtual void registerCheckers(CheckerManager &checkerMgr,
CheckerOptInfo *checkOpts, unsigned numCheckOpts);
+ virtual void printHelp(llvm::raw_ostream &OS);
};
}
@@ -41,6 +44,7 @@ namespace {
struct StaticCheckerInfoRec {
const char *FullName;
void (*RegFunc)(CheckerManager &mgr);
+ const char *HelpText;
bool Hidden;
};
@@ -49,13 +53,16 @@ struct StaticCheckerInfoRec {
static const StaticCheckerInfoRec StaticCheckerInfo[] = {
#define GET_CHECKERS
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN) \
- { FULLNAME, register##CLASS, HIDDEN },
+ { FULLNAME, register##CLASS, HELPTEXT, HIDDEN },
#include "Checkers.inc"
- { 0, 0, 0}
+ { 0, 0, 0, 0}
#undef CHECKER
#undef GET_CHECKERS
};
+static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
+ / sizeof(StaticCheckerInfoRec) - 1;
+
namespace {
struct CheckNameOption {
@@ -104,9 +111,10 @@ static void collectCheckers(const CheckNameOption *checkName,
// Enable/disable all subgroups along with this one.
if (const short *subGroups = checkName->SubGroups) {
- for (; *subGroups != -1; ++subGroups)
- collectCheckers(&CheckNameTable[*subGroups], enable, checkers,
- collectHidden && checkName->Hidden);
+ for (; *subGroups != -1; ++subGroups) {
+ const CheckNameOption *sub = &CheckNameTable[*subGroups];
+ collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
+ }
}
}
@@ -135,3 +143,41 @@ void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
(*I)->RegFunc(checkerMgr);
}
}
+
+typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
+
+static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
+ // Find the maximum option length.
+ unsigned OptionFieldWidth = 0;
+ for (SortedCheckers::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I) {
+ // Limit the amount of padding we are willing to give up for alignment.
+ unsigned Length = strlen(I->second->FullName);
+ if (Length <= 30)
+ OptionFieldWidth = std::max(OptionFieldWidth, Length);
+ }
+
+ const unsigned InitialPad = 2;
+ for (SortedCheckers::iterator
+ I = checkers.begin(), E = checkers.end(); I != E; ++I) {
+ const std::string &Option = I->first;
+ int Pad = OptionFieldWidth - int(Option.size());
+ OS.indent(InitialPad) << Option;
+
+ // Break on long option names.
+ if (Pad < 0) {
+ OS << "\n";
+ Pad = OptionFieldWidth + InitialPad;
+ }
+ OS.indent(Pad + 1) << I->second->HelpText << '\n';
+ }
+}
+
+void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
+ // Sort checkers according to their full name.
+ SortedCheckers checkers;
+ for (unsigned i = 0; i != NumCheckers; ++i)
+ checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
+
+ printCheckerOption(OS, checkers);
+}
diff --git a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
index d9bb480..990ba1c0 100644
--- a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
@@ -24,14 +24,3 @@ void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
// within ExprEngine.
RegisterMallocChecker(Eng); // ArrayBoundChecker depends on this.
}
-
-void ento::RegisterExperimentalInternalChecks(ExprEngine &Eng) {
- // These are internal checks that should eventually migrate to
- // RegisterInternalChecks() once they have been further tested.
-
- // Note that this must be registered after ReturnStackAddresEngsChecker.
- RegisterReturnPointerRangeChecker(Eng);
-
- RegisterArrayBoundChecker(Eng);
- RegisterCastSizeChecker(Eng);
-}
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index ab8d564..c1b1e65 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -92,12 +92,13 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
}
if (CO->empty()) {
- // If there are no checkers, return early without doing any
- // more work.
- Dst.insert(Src);
+ // If there are no checkers, just delegate to the checker manager.
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, Src, S, *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
unsigned checkersEvaluated = 0;
@@ -108,7 +109,7 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
break;
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -144,6 +145,9 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
// Don't autotransition. The CheckerContext objects should do this
// automatically.
+
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, CheckersV1Dst, S, *this);
}
void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
@@ -152,10 +156,12 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
bool isPrevisit) {
if (Checkers.empty()) {
- Dst.insert(Src);
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg,
+ *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
@@ -163,7 +169,7 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -181,8 +187,8 @@ void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
PrevSet = CurrSet;
}
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst,
+ msg, *this);
}
void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
@@ -232,11 +238,25 @@ bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
DstTmp.clear();
}
- if (evaluated)
+ if (evaluated) {
Dst.insert(DstTmp);
- else
- Dst.insert(Pred);
+ return evaluated;
+ }
+
+ class DefaultEval : public GraphExpander {
+ bool &Evaluated;
+ public:
+ DefaultEval(bool &evaluated) : Evaluated(evaluated) { }
+ virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ Evaluated = false;
+ Dst.insert(Pred);
+ }
+ };
+ evaluated = true;
+ DefaultEval defaultEval(evaluated);
+ getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this,
+ &defaultEval);
return evaluated;
}
@@ -335,8 +355,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
-
- mgr.getCheckerManager()->registerCheckersToEngine(*this);
if (mgr.shouldEagerlyTrimExplodedGraph()) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
@@ -495,7 +513,7 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
return true;
}
- return false;
+ return getCheckerManager().wantsRegionChangeUpdate(state);
}
const GRState *
@@ -523,9 +541,9 @@ ExprEngine::processRegionChanges(const GRState *state,
CO = CO_Ref;
}
- // If there are no checkers, just return the state as is.
+ // If there are no checkers, just delegate to the checker manager.
if (CO->empty())
- return state;
+ return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
// If any checker declares the state infeasible (or if it starts that way),
@@ -548,7 +566,7 @@ ExprEngine::processRegionChanges(const GRState *state,
if (NewCO.get())
CO_Ref = NewCO.take();
- return state;
+ return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -556,6 +574,7 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
I != E; ++I) {
I->second->VisitEndAnalysis(G, BR, *this);
}
+ getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
void ExprEngine::processCFGElement(const CFGElement E,
@@ -603,6 +622,8 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
checker->MarkLiveSymbols(St, SymReaper);
}
+ getCheckerManager().runCheckersForLiveSymbols(St, SymReaper);
+
const StackFrameContext *SFC = LC->getCurrentStackFrame();
CleanedState = StateMgr.removeDeadBindings(St, SFC, SymReaper);
} else {
@@ -626,8 +647,9 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
CleanedState, SymReaper);
+ ExplodedNodeSet checkersV1Tmp;
if (Checkers.empty())
- Tmp.insert(Tmp2);
+ checkersV1Tmp.insert(Tmp2);
else {
ExplodedNodeSet Tmp3;
ExplodedNodeSet *SrcSet = &Tmp2;
@@ -635,7 +657,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
I != E; ++I) {
ExplodedNodeSet *DstSet = 0;
if (I+1 == E)
- DstSet = &Tmp;
+ DstSet = &checkersV1Tmp;
else {
DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
DstSet->clear();
@@ -651,6 +673,9 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
}
}
+ getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp,
+ SymReaper, currentStmt, *this);
+
if (!Builder->BuildSinks && !Builder->hasGeneratedNode)
Tmp.Add(EntryNode);
}
@@ -1419,8 +1444,10 @@ void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
void *tag = I->first;
Checker *checker = I->second;
- checker->evalEndPath(builder, tag, *this);
+ EndOfFunctionNodeBuilder B = builder.withCheckerTag(tag);
+ checker->evalEndPath(B, tag, *this);
}
+ getCheckerManager().runCheckersForEndPath(builder, *this);
}
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
@@ -1923,20 +1950,35 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
const GRState* state, SVal location,
const void *tag, bool isLoad) {
// Early checks for performance reason.
- if (location.isUnknown() || Checkers.empty()) {
+ if (location.isUnknown()) {
Dst.Add(Pred);
return;
}
- ExplodedNodeSet Src, Tmp;
+ if (Checkers.empty()) {
+ ExplodedNodeSet Src;
+ if (Builder->GetState(Pred) == state) {
+ Src.Add(Pred);
+ } else {
+ // Associate this new state with an ExplodedNode.
+ Src.Add(Builder->generateNode(S, state, Pred));
+ }
+ getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+ *this);
+ return;
+ }
+
+ ExplodedNodeSet Src;
Src.Add(Pred);
+ ExplodedNodeSet CheckersV1Dst;
+ ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -1957,6 +1999,9 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
+
+ getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location,
+ isLoad, S, *this);
}
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
@@ -3613,14 +3658,12 @@ void ExprEngine::ViewGraph(bool trim) {
const_cast<BugType*>(*I)->FlushReports(BR);
// Iterate through the reports and get their nodes.
- for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
- for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end();
- I2!=E2; ++I2) {
- const BugReportEquivClass& EQ = *I2;
- const BugReport &R = **EQ.begin();
- ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
- if (N) Src.push_back(N);
- }
+ for (BugReporter::EQClasses_iterator
+ EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
+ BugReportEquivClass& EQ = *EI;
+ const BugReport &R = **EQ.begin();
+ ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
+ if (N) Src.push_back(N);
}
ViewGraph(&Src[0], &Src[0]+Src.size());
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index fe628a2..d7b27b5 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -14,31 +14,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class FixedAddressChecker
- : public CheckerVisitor<FixedAddressChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- FixedAddressChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *FixedAddressChecker::getTag() {
- static int x;
- return &x;
-}
-
-void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Using a fixed address is not portable because that address will probably
// not be valid in all environments or platforms.
@@ -58,20 +53,16 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Use fixed address",
+ BT.reset(new BuiltinBug("Use fixed address",
"Using a fixed address is not portable because that "
"address will probably not be valid in all "
- "environments or platforms.");
+ "environments or platforms."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
C.EmitReport(R);
}
}
-static void RegisterFixedAddressChecker(ExprEngine &Eng) {
- Eng.registerCheck(new FixedAddressChecker());
-}
-
void ento::registerFixedAddressChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterFixedAddressChecker);
+ mgr.registerChecker<FixedAddressChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index f49b125..83d9668 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -45,11 +45,13 @@
#include "ClangSACheckers.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/AST/Stmt.h"
@@ -64,29 +66,29 @@ using namespace ento;
namespace {
class IdempotentOperationChecker
- : public CheckerVisitor<IdempotentOperationChecker> {
+ : public CheckerV2<check::PreStmt<BinaryOperator>,
+ check::PostStmt<BinaryOperator>,
+ check::EndAnalysis> {
public:
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
private:
// Our assumption about a particular operation.
enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
RHSis0 };
- void UpdateAssumption(Assumption &A, const Assumption &New);
+ static void UpdateAssumption(Assumption &A, const Assumption &New);
// False positive reduction methods
static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
static bool isUnused(const Expr *E, AnalysisContext *AC);
static bool isTruncationExtensionAssignment(const Expr *LHS,
const Expr *RHS);
- bool pathWasCompletelyAnalyzed(const CFG *cfg,
- const CFGBlock *CB,
- const CFGStmtMap *CBM,
- const CoreEngine &CE);
+ static bool pathWasCompletelyAnalyzed(AnalysisContext *AC,
+ const CFGBlock *CB,
+ const CoreEngine &CE);
static bool CanVary(const Expr *Ex,
AnalysisContext *AC);
static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
@@ -104,46 +106,12 @@ private:
};
typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
AssumptionMap;
- AssumptionMap hash;
-
- // A class that performs reachability queries for CFGBlocks. Several internal
- // checks in this checker require reachability information. The requests all
- // tend to have a common destination, so we lazily do a predecessor search
- // from the destination node and cache the results to prevent work
- // duplication.
- class CFGReachabilityAnalysis {
- typedef llvm::BitVector ReachableSet;
- typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
- ReachableSet analyzed;
- ReachableMap reachable;
- public:
- CFGReachabilityAnalysis(const CFG &cfg)
- : analyzed(cfg.getNumBlockIDs(), false) {}
-
- inline bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
- private:
- void MapReachability(const CFGBlock *Dst);
- };
- llvm::OwningPtr<CFGReachabilityAnalysis> CRA;
+ mutable AssumptionMap hash;
};
}
-void *IdempotentOperationChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-static void RegisterIdempotentOperationChecker(ExprEngine &Eng) {
- Eng.registerCheck(new IdempotentOperationChecker());
-}
-
-void ento::registerIdempotentOperationChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterIdempotentOperationChecker);
-}
-
-void IdempotentOperationChecker::PreVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
+void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Find or create an entry in the hash for this BinaryOperator instance.
// If we haven't done a lookup before, it will get default initialized to
// 'Possible'. At this stage we do not store the ExplodedNode, as it has not
@@ -359,9 +327,8 @@ void IdempotentOperationChecker::PreVisitBinaryOperator(
// At the post visit stage, the predecessor ExplodedNode will be the
// BinaryOperator that was just created. We use this hook to collect the
// ExplodedNode.
-void IdempotentOperationChecker::PostVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
+void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// Add the ExplodedNode we just visited
BinaryOperatorData &Data = hash[B];
@@ -376,9 +343,9 @@ void IdempotentOperationChecker::PostVisitBinaryOperator(
Data.explodedNodes.Add(C.getPredecessor());
}
-void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
+void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
- ExprEngine &Eng) {
+ ExprEngine &Eng) const {
BugType *BT = new BugType("Idempotent operation", "Dead code");
// Iterate over the hash to see if we have any paths with definite
// idempotent operations.
@@ -397,16 +364,11 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
// If the analyzer did not finish, check to see if we can still emit this
// warning
if (Eng.hasWorkRemaining()) {
- const CFGStmtMap *CBM = CFGStmtMap::Build(AC->getCFG(),
- &AC->getParentMap());
-
// If we can trace back
- if (!pathWasCompletelyAnalyzed(AC->getCFG(),
- CBM->getBlock(B), CBM,
+ if (!pathWasCompletelyAnalyzed(AC,
+ AC->getCFGStmtMap()->getBlock(B),
Eng.getCoreEngine()))
continue;
-
- delete CBM;
}
// Select the error message and SourceRanges to report.
@@ -464,6 +426,8 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
BR.EmitReport(report);
}
}
+
+ hash.clear();
}
// Updates the current assumption given the new assumption
@@ -564,13 +528,11 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment(
// Returns false if a path to this block was not completely analyzed, or true
// otherwise.
bool
-IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
+IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
const CFGBlock *CB,
- const CFGStmtMap *CBM,
const CoreEngine &CE) {
- if (!CRA.get())
- CRA.reset(new CFGReachabilityAnalysis(*cfg));
+ CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
// Test for reachability from any aborted blocks to this block
typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
@@ -621,14 +583,14 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
return CRA.isReachable(B, TargetBlock);
}
};
- VisitWL visitWL(CBM, CB, *CRA.get());
+ VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA);
// Were there any items in the worklist that could potentially reach
// this block?
if (CE.getWorkList()->visitItemsInWorkList(visitWL))
return false;
// Verify that this block is reachable from the entry block
- if (!CRA->isReachable(&cfg->getEntry(), CB))
+ if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB))
return false;
// If we get to this point, there is no connection to the entry block or an
@@ -766,57 +728,7 @@ bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
return false;
}
-bool IdempotentOperationChecker::CFGReachabilityAnalysis::isReachable(
- const CFGBlock *Src,
- const CFGBlock *Dst) {
- const unsigned DstBlockID = Dst->getBlockID();
- // If we haven't analyzed the destination node, run the analysis now
- if (!analyzed[DstBlockID]) {
- MapReachability(Dst);
- analyzed[DstBlockID] = true;
- }
-
- // Return the cached result
- return reachable[DstBlockID][Src->getBlockID()];
-}
-
-// Maps reachability to a common node by walking the predecessors of the
-// destination node.
-void IdempotentOperationChecker::CFGReachabilityAnalysis::MapReachability(
- const CFGBlock *Dst) {
-
- llvm::SmallVector<const CFGBlock *, 11> worklist;
- llvm::BitVector visited(analyzed.size());
-
- ReachableSet &DstReachability = reachable[Dst->getBlockID()];
- DstReachability.resize(analyzed.size(), false);
-
- // Start searching from the destination node, since we commonly will perform
- // multiple queries relating to a destination node.
- worklist.push_back(Dst);
- bool firstRun = true;
-
- while (!worklist.empty()) {
- const CFGBlock *block = worklist.back();
- worklist.pop_back();
-
- if (visited[block->getBlockID()])
- continue;
- visited[block->getBlockID()] = true;
-
- // Update reachability information for this node -> Dst
- if (!firstRun) {
- // Don't insert Dst -> Dst unless it was a predecessor of itself
- DstReachability[block->getBlockID()] = true;
- }
- else
- firstRun = false;
-
- // Add the predecessors to the worklist.
- for (CFGBlock::const_pred_iterator i = block->pred_begin(),
- e = block->pred_end(); i != e; ++i) {
- worklist.push_back(*i);
- }
- }
+void ento::registerIdempotentOperationChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IdempotentOperationChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/InternalChecks.h b/lib/StaticAnalyzer/Checkers/InternalChecks.h
index e855386..e7c38ee 100644
--- a/lib/StaticAnalyzer/Checkers/InternalChecks.h
+++ b/lib/StaticAnalyzer/Checkers/InternalChecks.h
@@ -23,16 +23,13 @@ class ExprEngine;
// Foundational checks that handle basic semantics.
void RegisterAdjustedReturnValueChecker(ExprEngine &Eng);
-void RegisterArrayBoundChecker(ExprEngine &Eng);
void RegisterArrayBoundCheckerV2(ExprEngine &Eng);
void RegisterAttrNonNullChecker(ExprEngine &Eng);
void RegisterBuiltinFunctionChecker(ExprEngine &Eng);
void RegisterCallAndMessageChecker(ExprEngine &Eng);
-void RegisterCastSizeChecker(ExprEngine &Eng);
void RegisterDereferenceChecker(ExprEngine &Eng);
void RegisterDivZeroChecker(ExprEngine &Eng);
void RegisterNoReturnFunctionChecker(ExprEngine &Eng);
-void RegisterReturnPointerRangeChecker(ExprEngine &Eng);
void RegisterReturnUndefChecker(ExprEngine &Eng);
void RegisterUndefBranchChecker(ExprEngine &Eng);
void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng);
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 358be12..d70c65a 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -16,11 +16,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
@@ -29,31 +30,26 @@ using namespace clang;
using namespace ento;
namespace {
-class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
+class MacOSXAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
enum SubChecks {
DispatchOnce = 0,
DispatchOnceF,
NumChecks
};
- BugType *BTypes[NumChecks];
+ mutable BugType *BTypes[NumChecks];
public:
MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
+ ~MacOSXAPIChecker() {
+ for (unsigned i=0; i != NumChecks; ++i)
+ delete BTypes[i];
+ }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} //end anonymous namespace
-static void RegisterMacOSXAPIChecker(ExprEngine &Eng) {
- Eng.registerCheck(new MacOSXAPIChecker());
-}
-
-void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterMacOSXAPIChecker);
-}
-
//===----------------------------------------------------------------------===//
// dispatch_once and dispatch_once_f
//===----------------------------------------------------------------------===//
@@ -121,7 +117,8 @@ namespace {
};
} // end anonymous namespace
-void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
// FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
@@ -144,3 +141,11 @@ void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
SC.run(C, CE, FI);
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MacOSXAPIChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 9d3a887..794740a 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -599,7 +599,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
RefState RS = I->second;
if (RS.isAllocated()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 9fb89d7..fed6a99 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -16,10 +16,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
@@ -28,39 +29,18 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
- : public CheckerVisitor<NSAutoreleasePoolChecker> {
+ : public CheckerV2<check::PreObjCMessage> {
- Selector releaseS;
+ mutable Selector releaseS;
public:
- NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
-
- static void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
};
} // end anonymous namespace
-
-static void RegisterNSAutoreleasePoolChecker(ExprEngine &Eng) {
- ASTContext &Ctx = Eng.getContext();
- if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
- Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
- Ctx)));
- }
-}
-
-void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterNSAutoreleasePoolChecker);
-}
-
-void
-NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
const Expr *receiver = msg.getInstanceReceiver();
if (!receiver)
@@ -78,7 +58,9 @@ NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
return;
if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
return;
-
+
+ if (releaseS.isNull())
+ releaseS = GetNullarySelector("release", C.getASTContext());
// Sending 'release' message?
if (msg.getSelector() != releaseS)
return;
@@ -90,3 +72,8 @@ NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
"Use -drain instead of -release when using NSAutoreleasePool "
"and garbage collection", R.getBegin(), &R, 1);
}
+
+void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
+ if (mgr.getLangOptions().getGCMode() != LangOptions::NonGC)
+ mgr.registerChecker<NSAutoreleasePoolChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 7d440ab..7746719 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -13,39 +13,29 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
-class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
- BuiltinBug *BT_null;
- BuiltinBug *BT_undef;
+class ObjCAtSyncChecker
+ : public CheckerV2< check::PreStmt<ObjCAtSynchronizedStmt> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT_null;
+ mutable llvm::OwningPtr<BuiltinBug> BT_undef;
+
public:
- ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S);
+ void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
};
} // end anonymous namespace
-static void RegisterObjCAtSyncChecker(ExprEngine &Eng) {
- // @synchronized is an Objective-C 2 feature.
- if (Eng.getContext().getLangOptions().ObjC2)
- Eng.registerCheck(new ObjCAtSyncChecker());
-}
-
-void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterObjCAtSyncChecker);
-}
-
-void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S) {
+void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
+ CheckerContext &C) const {
const Expr *Ex = S->getSynchExpr();
const GRState *state = C.getState();
@@ -55,8 +45,8 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
if (isa<UndefinedVal>(V)) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
- BT_undef = new BuiltinBug("Uninitialized value used as mutex "
- "for @synchronized");
+ BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
+ "for @synchronized"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
@@ -78,8 +68,8 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.generateNode(nullState)) {
if (!BT_null)
- BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
- "(no synchronization will occur)");
+ BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
+ "(no synchronization will occur)"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
@@ -98,3 +88,7 @@ void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
C.addTransition(notNullState);
}
+void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
+ if (mgr.getLangOptions().ObjC2)
+ mgr.registerChecker<ObjCAtSyncChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 4f247ea..5f32bb8 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -47,8 +47,9 @@
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
@@ -63,45 +64,23 @@ static bool isInitMessage(const ObjCMessage &msg);
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
-enum SelfFlagEnum {
- /// \brief No flag set.
- SelfFlag_None = 0x0,
- /// \brief Value came from 'self'.
- SelfFlag_Self = 0x1,
- /// \brief Value came from the result of an initializer (e.g. [super init]).
- SelfFlag_InitRes = 0x2
-};
-}
-
-namespace {
-class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
- /// \brief A call receiving a reference to 'self' invalidates the object that
- /// 'self' contains. This field keeps the "self flags" assigned to the 'self'
- /// object before the call and assign them to the new object that 'self'
- /// points to after the call.
- SelfFlagEnum preCallSelfFlags;
-
+class ObjCSelfInitChecker : public CheckerV2<
+ check::PostObjCMessage,
+ check::PostStmt<ObjCIvarRefExpr>,
+ check::PreStmt<ReturnStmt>,
+ check::PreStmt<CallExpr>,
+ check::PostStmt<CallExpr>,
+ check::Location > {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
- void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
- bool isLoad);
+ void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
};
} // end anonymous namespace
-static void RegisterObjCSelfInitChecker(ExprEngine &Eng) {
- if (Eng.getContext().getLangOptions().ObjC1)
- Eng.registerCheck(new ObjCSelfInitChecker());
-}
-
-void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterObjCSelfInitChecker);
-}
-
namespace {
class InitSelfBug : public BugType {
@@ -113,22 +92,40 @@ public:
} // end anonymous namespace
+namespace {
+enum SelfFlagEnum {
+ /// \brief No flag set.
+ SelfFlag_None = 0x0,
+ /// \brief Value came from 'self'.
+ SelfFlag_Self = 0x1,
+ /// \brief Value came from the result of an initializer (e.g. [super init]).
+ SelfFlag_InitRes = 0x2
+};
+}
+
typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
namespace { struct CalledInit {}; }
+namespace { struct PreCallSelfFlags {}; }
namespace clang {
namespace ento {
template<>
struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> {
- static void* GDMIndex() {
- static int index = 0;
- return &index;
- }
+ static void* GDMIndex() { static int index = 0; return &index; }
};
template <>
struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> {
static void *GDMIndex() { static int index = 0; return &index; }
};
+
+ /// \brief A call receiving a reference to 'self' invalidates the object that
+ /// 'self' contains. This keeps the "self flags" assigned to the 'self'
+ /// object before the call so we can assign them to the new object that 'self'
+ /// points to after the call.
+ template <>
+ struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+ };
}
}
@@ -188,8 +185,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
C.EmitReport(report);
}
-void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
// When encountering a message that does initialization (init rule),
// tag the return value so that we know later on that if self has this value
// then it is properly initialized.
@@ -219,8 +216,8 @@ void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
// fails.
}
-void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
- const ObjCIvarRefExpr *E) {
+void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -231,8 +228,8 @@ void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
"'[(super or self) init...]'");
}
-void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *S) {
+void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -259,40 +256,46 @@ void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
// Until we can use inter-procedural analysis, in such a call, transfer the
// SelfFlags to the result of the call.
-void ObjCSelfInitChecker::PreVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- preCallSelfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- preCallSelfFlags = getSelfFlags(argV, C);
+ unsigned selfFlags = getSelfFlags(argV, C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
}
}
}
-void ObjCSelfInitChecker::PostVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- addSelfFlag(state, state->getSVal(CE), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(CE), prevFlags, C);
return;
}
}
}
-void ObjCSelfInitChecker::visitLocation(CheckerContext &C, const Stmt *S,
- SVal location, bool isLoad) {
+void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
+ CheckerContext &C) const {
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
const GRState *state = C.getState();
@@ -354,3 +357,11 @@ static bool isInitializationMethod(const ObjCMethodDecl *MD) {
static bool isInitMessage(const ObjCMessage &msg) {
return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCSelfInitChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 741e48b..034a2aa 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -13,31 +13,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class PointerArithChecker
- : public CheckerVisitor<PointerArithChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- PointerArithChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *PointerArithChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
return;
@@ -57,10 +52,10 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Dangerous pointer arithmetic",
+ BT.reset(new BuiltinBug("Dangerous pointer arithmetic",
"Pointer arithmetic done on non-array variables "
"means reliance on memory layout, which is "
- "dangerous.");
+ "dangerous."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
@@ -68,10 +63,6 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
}
}
-static void RegisterPointerArithChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerArithChecker());
-}
-
void ento::registerPointerArithChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPointerArithChecker);
+ mgr.registerChecker<PointerArithChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index f28fe9a..bf85b95 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -14,31 +14,26 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class PointerSubChecker
- : public CheckerVisitor<PointerSubChecker> {
- BuiltinBug *BT;
+ : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+
public:
- PointerSubChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
}
-void *PointerSubChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
// When doing pointer subtraction, if the two pointers do not point to the
// same memory chunk, emit a warning.
if (B->getOpcode() != BO_Sub)
@@ -66,19 +61,15 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
if (ExplodedNode *N = C.generateNode()) {
if (!BT)
- BT = new BuiltinBug("Pointer subtraction",
+ BT.reset(new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
- "the same memory chunk may cause incorrect result.");
+ "the same memory chunk may cause incorrect result."));
RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.EmitReport(R);
}
}
-static void RegisterPointerSubChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerSubChecker());
-}
-
void ento::registerPointerSubChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPointerSubChecker);
+ mgr.registerChecker<PointerSubChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 34c095f..6c6901f 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -13,8 +13,9 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -24,21 +25,15 @@ using namespace ento;
namespace {
class PthreadLockChecker
- : public CheckerVisitor<PthreadLockChecker> {
- BugType *BT;
+ : public CheckerV2< check::PostStmt<CallExpr> > {
public:
- PthreadLockChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock);
+ SVal lock, bool isTryLock) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock);
+ SVal lock) const;
};
} // end anonymous namespace
@@ -49,22 +44,14 @@ namespace clang {
namespace ento {
template <> struct GRStateTrait<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+ static void* GDMIndex() { static int x = 0; return &x; }
};
} // end GR namespace
} // end clang namespace
-static void RegisterPthreadLockChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PthreadLockChecker());
-}
-
-void ento::registerPthreadLockChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterPthreadLockChecker);
-}
-
-void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionTextRegion *R =
@@ -96,7 +83,7 @@ void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock) {
+ SVal lock, bool isTryLock) const {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
@@ -132,7 +119,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
}
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock) {
+ SVal lock) const {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
@@ -150,3 +137,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
C.addTransition(C.generateNode(CE, unlockState));
}
+
+void ento::registerPthreadLockChecker(CheckerManager &mgr) {
+ mgr.registerChecker<PthreadLockChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 838a00f..2985156 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -22,25 +24,15 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
- public CheckerVisitor<ReturnPointerRangeChecker> {
- BuiltinBug *BT;
+ public CheckerV2< check::PreStmt<ReturnStmt> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- ReturnPointerRangeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+ void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
}
-void ento::RegisterReturnPointerRangeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ReturnPointerRangeChecker());
-}
-
-void *ReturnPointerRangeChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
+void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
+ CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *RetE = RS->getRetValue();
@@ -77,9 +69,9 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
if (!BT)
- BT = new BuiltinBug("Return of pointer value outside of expected range",
+ BT.reset(new BuiltinBug("Return of pointer value outside of expected range",
"Returned pointer value points outside the original object "
- "(potential buffer overflow)");
+ "(potential buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
@@ -93,3 +85,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
C.EmitReport(report);
}
}
+
+void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ReturnPointerRangeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 363f404..6a9a37d 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -1,4 +1,4 @@
-//=== StackAddrLeakChecker.cpp ------------------------------------*- C++ -*--//
+//=== StackAddrEscapeChecker.cpp ----------------------------------*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
@@ -13,9 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
@@ -23,34 +24,23 @@ using namespace clang;
using namespace ento;
namespace {
-class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
- BuiltinBug *BT_stackleak;
- BuiltinBug *BT_returnstack;
+class StackAddrEscapeChecker : public CheckerV2< check::PreStmt<ReturnStmt>,
+ check::EndPath > {
+ mutable llvm::OwningPtr<BuiltinBug> BT_stackleak;
+ mutable llvm::OwningPtr<BuiltinBug> BT_returnstack;
public:
- StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
- static void *getTag() {
- static int x;
- return &x;
- }
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
- void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
+ void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
private:
- void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
- SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
+ void EmitStackError(CheckerContext &C, const MemRegion *R,
+ const Expr *RetE) const;
+ static SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
+ SourceManager &SM);
};
}
-static void RegisterStackAddrLeakChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StackAddrLeakChecker());
-}
-
-void ento::registerStackAddrLeakChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterStackAddrLeakChecker);
-}
-
-SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
+SourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os,
const MemRegion *R,
SourceManager &SM) {
// Get the base region, stripping away fields and elements.
@@ -93,15 +83,16 @@ SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
return range;
}
-void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
- const Expr *RetE) {
+void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
+ const Expr *RetE) const {
ExplodedNode *N = C.generateSink();
if (!N)
return;
if (!BT_returnstack)
- BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
+ BT_returnstack.reset(
+ new BuiltinBug("Return of address to stack-allocated memory"));
// Generate a report for this bug.
llvm::SmallString<512> buf;
@@ -116,8 +107,8 @@ void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
C.EmitReport(report);
}
-void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
+void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
+ CheckerContext &C) const {
const Expr *RetE = RS->getRetValue();
if (!RetE)
@@ -135,8 +126,8 @@ void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
}
}
-void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
+void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
const GRState *state = B.getState();
@@ -180,16 +171,16 @@ void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
return;
// Generate an error node.
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (!N)
return;
if (!BT_stackleak)
- BT_stackleak =
+ BT_stackleak.reset(
new BuiltinBug("Stack address stored into global variable",
"Stack address was saved into a global variable. "
"This is dangerous because the address will become "
- "invalid after returning from the function");
+ "invalid after returning from the function"));
for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
// Generate a report for this bug.
@@ -208,3 +199,7 @@ void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
Eng.getBugReporter().EmitReport(report);
}
}
+
+void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<StackAddrEscapeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2655be2..d0626b8 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -12,9 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -55,52 +56,50 @@ struct StreamState {
}
};
-class StreamChecker : public CheckerVisitor<StreamChecker> {
- IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite,
+class StreamChecker : public CheckerV2<eval::Call,
+ check::DeadSymbols,
+ check::EndPath,
+ check::PreStmt<ReturnStmt> > {
+ mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
+ *II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
- BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
+ mutable llvm::OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence,
+ BT_doubleclose, BT_ResourceLeak;
public:
StreamChecker()
: II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
- II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
- BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0),
- BT_ResourceLeak(0) {}
+ II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0) {}
- static void *getTag() {
- static int x;
- return &x;
- }
-
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
- void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
private:
- void Fopen(CheckerContext &C, const CallExpr *CE);
- void Tmpfile(CheckerContext &C, const CallExpr *CE);
- void Fclose(CheckerContext &C, const CallExpr *CE);
- void Fread(CheckerContext &C, const CallExpr *CE);
- void Fwrite(CheckerContext &C, const CallExpr *CE);
- void Fseek(CheckerContext &C, const CallExpr *CE);
- void Ftell(CheckerContext &C, const CallExpr *CE);
- void Rewind(CheckerContext &C, const CallExpr *CE);
- void Fgetpos(CheckerContext &C, const CallExpr *CE);
- void Fsetpos(CheckerContext &C, const CallExpr *CE);
- void Clearerr(CheckerContext &C, const CallExpr *CE);
- void Feof(CheckerContext &C, const CallExpr *CE);
- void Ferror(CheckerContext &C, const CallExpr *CE);
- void Fileno(CheckerContext &C, const CallExpr *CE);
-
- void OpenFileAux(CheckerContext &C, const CallExpr *CE);
+ void Fopen(CheckerContext &C, const CallExpr *CE) const;
+ void Tmpfile(CheckerContext &C, const CallExpr *CE) const;
+ void Fclose(CheckerContext &C, const CallExpr *CE) const;
+ void Fread(CheckerContext &C, const CallExpr *CE) const;
+ void Fwrite(CheckerContext &C, const CallExpr *CE) const;
+ void Fseek(CheckerContext &C, const CallExpr *CE) const;
+ void Ftell(CheckerContext &C, const CallExpr *CE) const;
+ void Rewind(CheckerContext &C, const CallExpr *CE) const;
+ void Fgetpos(CheckerContext &C, const CallExpr *CE) const;
+ void Fsetpos(CheckerContext &C, const CallExpr *CE) const;
+ void Clearerr(CheckerContext &C, const CallExpr *CE) const;
+ void Feof(CheckerContext &C, const CallExpr *CE) const;
+ void Ferror(CheckerContext &C, const CallExpr *CE) const;
+ void Fileno(CheckerContext &C, const CallExpr *CE) const;
+
+ void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
const GRState *CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C);
+ CheckerContext &C) const;
const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
- CheckerContext &C);
+ CheckerContext &C) const;
};
} // end anonymous namespace
@@ -110,20 +109,12 @@ namespace ento {
template <>
struct GRStateTrait<StreamState>
: public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { return StreamChecker::getTag(); }
+ static void *GDMIndex() { static int x; return &x; }
};
}
}
-static void RegisterStreamChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StreamChecker());
-}
-
-void ento::registerStreamChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterStreamChecker);
-}
-
-bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -221,15 +212,15 @@ bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
return false;
}
-void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) const {
OpenFileAux(C, CE);
}
-void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
OpenFileAux(C, CE);
}
-void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -255,25 +246,25 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
}
}
-void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = CheckDoubleClose(CE, C.getState(), C);
if (state)
C.addTransition(state);
}
-void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
-void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
return;
}
-void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
return;
@@ -290,65 +281,65 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
if (ExplodedNode *N = C.generateNode(state)) {
if (!BT_illegalwhence)
- BT_illegalwhence = new BuiltinBug("Illegal whence argument",
+ BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument",
"The whence argument to fseek() should be "
- "SEEK_SET, SEEK_END, or SEEK_CUR.");
+ "SEEK_SET, SEEK_END, or SEEK_CUR."));
BugReport *R = new BugReport(*BT_illegalwhence,
BT_illegalwhence->getDescription(), N);
C.EmitReport(R);
}
}
-void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
-void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) {
+void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
return;
}
const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C) {
+ CheckerContext &C) const {
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
if (!DV)
return 0;
@@ -360,8 +351,8 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
if (!stateNotNull && stateNull) {
if (ExplodedNode *N = C.generateSink(stateNull)) {
if (!BT_nullfp)
- BT_nullfp = new BuiltinBug("NULL stream pointer",
- "Stream pointer might be NULL.");
+ BT_nullfp.reset(new BuiltinBug("NULL stream pointer",
+ "Stream pointer might be NULL."));
BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
C.EmitReport(R);
}
@@ -372,7 +363,7 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
const GRState *state,
- CheckerContext &C) {
+ CheckerContext &C) const {
SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
if (!Sym)
return state;
@@ -389,9 +380,9 @@ const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_doubleclose)
- BT_doubleclose = new BuiltinBug("Double fclose",
+ BT_doubleclose.reset(new BuiltinBug("Double fclose",
"Try to close a file Descriptor already"
- " closed. Cause undefined behaviour.");
+ " closed. Cause undefined behaviour."));
BugReport *R = new BugReport(*BT_doubleclose,
BT_doubleclose->getDescription(), N);
C.EmitReport(R);
@@ -403,7 +394,8 @@ const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
return state->set<StreamState>(Sym, StreamState::getClosed(CE));
}
-void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
+void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
@@ -416,8 +408,8 @@ void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
+ BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
C.EmitReport(R);
@@ -426,8 +418,8 @@ void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
}
}
-void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
+void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
const GRState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
SymMap M = state->get<StreamState>();
@@ -435,11 +427,11 @@ void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
StreamState SS = I->second;
if (SS.isOpened()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
+ BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
+ "Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
Eng.getBugReporter().EmitReport(R);
@@ -448,7 +440,7 @@ void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
}
}
-void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
const Expr *RetE = S->getRetValue();
if (!RetE)
return;
@@ -468,3 +460,7 @@ void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
C.addTransition(state);
}
+
+void ento::registerStreamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<StreamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index a53ebb5..be4fbf6 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -13,10 +13,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
@@ -26,7 +27,7 @@ using namespace ento;
using llvm::Optional;
namespace {
-class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
+class UnixAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
enum SubChecks {
OpenFn = 0,
PthreadOnceFn = 1,
@@ -34,27 +35,22 @@ class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
NumChecks
};
- BugType *BTypes[NumChecks];
+ mutable BugType *BTypes[NumChecks];
public:
- Optional<uint64_t> Val_O_CREAT;
+ mutable Optional<uint64_t> Val_O_CREAT;
public:
UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
+ ~UnixAPIChecker() {
+ for (unsigned i=0; i != NumChecks; ++i)
+ delete BTypes[i];
+ }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} //end anonymous namespace
-static void RegisterUnixAPIChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnixAPIChecker());
-}
-
-void ento::registerUnixAPIChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterUnixAPIChecker);
-}
-
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -69,7 +65,7 @@ static inline void LazyInitialize(BugType *&BT, const char *name) {
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT) {
// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
@@ -141,7 +137,7 @@ static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
// pthread_once
//===----------------------------------------------------------------------===//
-static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,
const CallExpr *CE, BugType *&BT) {
// This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
@@ -186,7 +182,7 @@ static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
// FIXME: Eventually this should be rolled into the MallocChecker, but this
// check is more basic and is valuable for widespread use.
-static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
+static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT) {
// Sanity check that malloc takes one argument.
@@ -234,16 +230,16 @@ static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+typedef void (*SubChecker)(CheckerContext &C, const UnixAPIChecker &UC,
const CallExpr *CE, BugType *&BT);
namespace {
class SubCheck {
SubChecker SC;
- UnixAPIChecker *UC;
+ const UnixAPIChecker *UC;
BugType **BT;
public:
- SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
- BT(&bt) {}
+ SubCheck(SubChecker sc, const UnixAPIChecker *uc, BugType *& bt)
+ : SC(sc), UC(uc), BT(&bt) {}
SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE) const {
@@ -253,7 +249,7 @@ namespace {
};
} // end anonymous namespace
-void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const GRState *state = C.getState();
@@ -280,3 +276,11 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
SC.run(C, CE);
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerUnixAPIChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UnixAPIChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 3038e29..1bc487a 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -14,15 +14,16 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
@@ -33,40 +34,27 @@ using namespace clang;
using namespace ento;
namespace {
-class UnreachableCodeChecker : public Checker {
+class UnreachableCodeChecker : public CheckerV2<check::EndAnalysis> {
public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- ExprEngine &Eng);
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
+ ExprEngine &Eng) const;
private:
+ typedef llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> CFGBlocksSet;
+
static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
- void FindUnreachableEntryPoints(const CFGBlock *CB);
+ static void FindUnreachableEntryPoints(const CFGBlock *CB,
+ CFGBlocksSet &reachable,
+ CFGBlocksSet &visited);
static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
static inline bool isEmptyCFGBlock(const CFGBlock *CB);
-
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
};
}
-void *UnreachableCodeChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-static void RegisterUnreachableCodeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnreachableCodeChecker());
-}
-
-void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterUnreachableCodeChecker);
-}
-
-void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
+void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
- ExprEngine &Eng) {
- // Bail out if we didn't cover all paths
+ ExprEngine &Eng) const {
+ CFGBlocksSet reachable, visited;
+
if (Eng.hasWorkRemaining())
return;
@@ -109,7 +97,7 @@ void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
// Find the entry points for this block
if (!visited.count(CB->getBlockID()))
- FindUnreachableEntryPoints(CB);
+ FindUnreachableEntryPoints(CB, reachable, visited);
// This block may have been pruned; check if we still want to report it
if (reachable.count(CB->getBlockID()))
@@ -155,7 +143,9 @@ void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
}
// Recursively finds the entry point(s) for this dead CFGBlock.
-void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
+void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
+ CFGBlocksSet &reachable,
+ CFGBlocksSet &visited) {
visited.insert(CB->getBlockID());
for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
@@ -166,7 +156,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
reachable.insert(CB->getBlockID());
if (!visited.count((*I)->getBlockID()))
// If we haven't previously visited the unreachable predecessor, recurse
- FindUnreachableEntryPoints(*I);
+ FindUnreachableEntryPoints(*I, reachable, visited);
}
}
}
@@ -226,3 +216,7 @@ bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
&& CB->size() == 0 // No statements
&& CB->getTerminator() == 0; // No terminator
}
+
+void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UnreachableCodeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 9a84045..672982a 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1202,16 +1202,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
-BugType::~BugType() {
- // Free up the equivalence class objects. Observe that we get a pointer to
- // the object first before incrementing the iterator, as destroying the
- // node before doing so means we will read from freed memory.
- for (iterator I = begin(), E = end(); I !=E; ) {
- BugReportEquivClass *EQ = &*I;
- ++I;
- delete EQ;
- }
-}
+BugType::~BugType() { }
+
void BugType::FlushReports(BugReporter &BR) {}
//===----------------------------------------------------------------------===//
@@ -1315,28 +1307,30 @@ void BugReporter::FlushReports() {
return;
// First flush the warnings for each BugType. This may end up creating new
- // warnings and new BugTypes. Because ImmutableSet is a functional data
- // structure, we do not need to worry about the iterators being invalidated.
+ // warnings and new BugTypes.
+ // FIXME: Only NSErrorChecker needs BugType's FlushReports.
+ // Turn NSErrorChecker into a proper checker and remove this.
+ llvm::SmallVector<const BugType*, 16> bugTypes;
for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
+ bugTypes.push_back(*I);
+ for (llvm::SmallVector<const BugType*, 16>::iterator
+ I = bugTypes.begin(), E = bugTypes.end(); I != E; ++I)
const_cast<BugType*>(*I)->FlushReports(*this);
- // Iterate through BugTypes a second time. BugTypes may have been updated
- // with new BugType objects and new warnings.
- for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) {
- BugType *BT = const_cast<BugType*>(*I);
-
- typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
- SetTy& EQClasses = BT->EQClasses;
-
- for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
- BugReportEquivClass& EQ = *EI;
- FlushReport(EQ);
- }
-
- // Delete the BugType object.
- delete BT;
+ typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
+ for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
+ BugReportEquivClass& EQ = *EI;
+ FlushReport(EQ);
}
+ // BugReporter owns and deletes only BugTypes created implicitly through
+ // EmitBasicReport.
+ // FIXME: There are leaks from checkers that assume that the BugTypes they
+ // create will be destroyed by the BugReporter.
+ for (llvm::StringMap<BugType*>::iterator
+ I = StrBugTypes.begin(), E = StrBugTypes.end(); I != E; ++I)
+ delete I->second;
+
// Remove all references to the BugType objects.
BugTypes = F.getEmptySet();
}
@@ -1632,11 +1626,11 @@ void BugReporter::EmitReport(BugReport* R) {
BugType& BT = R->getBugType();
Register(&BT);
void *InsertPos;
- BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos);
+ BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
if (!EQ) {
EQ = new BugReportEquivClass(R);
- BT.EQClasses.InsertNode(EQ, InsertPos);
+ EQClasses.InsertNode(EQ, InsertPos);
}
else
EQ->AddReport(R);
@@ -1887,10 +1881,24 @@ void BugReporter::EmitBasicReport(llvm::StringRef name,
llvm::StringRef str, SourceLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
- // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'.
- BugType *BT = new BugType(name, category);
+ // 'BT' is owned by BugReporter.
+ BugType *BT = getBugTypeForName(name, category);
FullSourceLoc L = getContext().getFullLoc(Loc);
RangedBugReport *R = new DiagBugReport(*BT, str, L);
for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
EmitReport(R);
}
+
+BugType *BugReporter::getBugTypeForName(llvm::StringRef name,
+ llvm::StringRef category) {
+ llvm::SmallString<136> fullDesc;
+ llvm::raw_svector_ostream(fullDesc) << name << ":" << category;
+ llvm::StringMapEntry<BugType *> &
+ entry = StrBugTypes.GetOrCreateValue(fullDesc);
+ BugType *BT = entry.getValue();
+ if (!BT) {
+ BT = new BugType(name, category);
+ entry.setValue(BT);
+ }
+ return BT;
+}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 1989b82..75d331a 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -13,11 +13,17 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/DeclBase.h"
using namespace clang;
using namespace ento;
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for AST traversing..
+//===----------------------------------------------------------------------===//
+
void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
assert(D);
@@ -33,53 +39,398 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
DeclCheckerInfo &info = DeclCheckers[i];
if (info.IsForDeclFn(D))
- checkers->push_back(std::make_pair(info.Checker, info.CheckFn));
+ checkers->push_back(info.CheckFn);
}
}
assert(checkers);
for (CachedDeclCheckers::iterator
- I = checkers->begin(), E = checkers->end(); I != E; ++I) {
- CheckerRef checker = I->first;
- CheckDeclFunc fn = I->second;
- fn(checker, D, mgr, BR);
- }
+ I = checkers->begin(), E = checkers->end(); I != E; ++I)
+ (*I)(D, mgr, BR);
}
void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
assert(D && D->hasBody());
- for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) {
- CheckerRef checker = BodyCheckers[i].first;
- CheckDeclFunc fn = BodyCheckers[i].second;
- fn(checker, D, mgr, BR);
+ for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i)
+ BodyCheckers[i](D, mgr, BR);
+}
+
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+template <typename CHECK_CTX>
+static void expandGraphWithCheckers(CHECK_CTX checkCtx,
+ ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src) {
+
+ typename CHECK_CTX::CheckersTy::const_iterator
+ I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
+ if (I == E) {
+ Dst.insert(Src);
+ return;
+ }
+
+ ExplodedNodeSet Tmp1, Tmp2;
+ const ExplodedNodeSet *PrevSet = &Src;
+
+ for (; I != E; ++I) {
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
+ CurrSet->clear();
+ }
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checkCtx.runChecker(*I, *CurrSet, *NI);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
+ }
+}
+
+namespace {
+ struct CheckStmtContext {
+ typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
+ bool IsPreVisit;
+ const CheckersTy &Checkers;
+ const Stmt *S;
+ ExprEngine &Eng;
+
+ CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+ CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+ CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
+ const Stmt *s, ExprEngine &eng)
+ : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckStmtFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ // FIXME: Remove respondsToCallback from CheckerContext;
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0, S);
+ checkFn(S, C);
+ }
+ };
+}
+
+/// \brief Run checkers for visiting Stmts.
+void CheckerManager::runCheckersForStmt(bool isPreVisit,
+ ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const Stmt *S,
+ ExprEngine &Eng) {
+ CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
+ S, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
+}
+
+namespace {
+ struct CheckObjCMessageContext {
+ typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
+ bool IsPreVisit;
+ const CheckersTy &Checkers;
+ const ObjCMessage &Msg;
+ ExprEngine &Eng;
+
+ CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+ CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+ CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
+ const ObjCMessage &msg, ExprEngine &eng)
+ : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0,
+ Msg.getOriginExpr());
+ checkFn(Msg, C);
+ }
+ };
+}
+
+/// \brief Run checkers for visiting obj-c messages.
+void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
+ ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const ObjCMessage &msg,
+ ExprEngine &Eng) {
+ CheckObjCMessageContext C(isPreVisit,
+ isPreVisit ? PreObjCMessageCheckers
+ : PostObjCMessageCheckers,
+ msg, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
+}
+
+namespace {
+ struct CheckLocationContext {
+ typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
+ const CheckersTy &Checkers;
+ SVal Loc;
+ bool IsLoad;
+ const Stmt *S;
+ ExprEngine &Eng;
+
+ CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+ CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+ CheckLocationContext(const CheckersTy &checkers,
+ SVal loc, bool isLoad, const Stmt *s, ExprEngine &eng)
+ : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckLocationFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsLoad ? ProgramPoint::PreLoadKind :
+ ProgramPoint::PreStoreKind, 0, S);
+ checkFn(Loc, IsLoad, C);
+ }
+ };
+}
+
+/// \brief Run checkers for load/store of a location.
+void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SVal location, bool isLoad,
+ const Stmt *S, ExprEngine &Eng) {
+ CheckLocationContext C(LocationCheckers, location, isLoad, S, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
+}
+
+void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
+ BugReporter &BR,
+ ExprEngine &Eng) {
+ for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i)
+ EndAnalysisCheckers[i](G, BR, Eng);
+}
+
+/// \brief Run checkers for end of path.
+void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) {
+ for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
+ CheckEndPathFunc fn = EndPathCheckers[i];
+ EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker);
+ fn(specialB, Eng);
+ }
+}
+
+/// \brief Run checkers for live symbols.
+void CheckerManager::runCheckersForLiveSymbols(const GRState *state,
+ SymbolReaper &SymReaper) {
+ for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
+ LiveSymbolsCheckers[i](state, SymReaper);
+}
+
+namespace {
+ struct CheckDeadSymbolsContext {
+ typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
+ const CheckersTy &Checkers;
+ SymbolReaper &SR;
+ const Stmt *S;
+ ExprEngine &Eng;
+
+ CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+ CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+ CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
+ const Stmt *s, ExprEngine &eng)
+ : Checkers(checkers), SR(sr), S(s), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
+ checkFn(SR, C);
+ }
+ };
+}
+
+/// \brief Run checkers for dead symbols.
+void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SymbolReaper &SymReaper,
+ const Stmt *S,
+ ExprEngine &Eng) {
+ CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
+}
+
+/// \brief True if at least one checker wants to check region changes.
+bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
+ for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
+ if (RegionChangesCheckers[i].WantUpdateFn(state))
+ return true;
+
+ return false;
+}
+
+/// \brief Run checkers for region changes.
+const GRState *
+CheckerManager::runCheckersForRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) {
+ for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
+ // If any checker declares the state infeasible (or if it starts that way),
+ // bail out.
+ if (!state)
+ return NULL;
+ state = RegionChangesCheckers[i].CheckFn(state, Begin, End);
}
+ return state;
}
-void CheckerManager::_registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
+/// \brief Run checkers for evaluating a call.
+/// Only one checker will evaluate the call.
+void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const CallExpr *CE,
+ ExprEngine &Eng,
+ GraphExpander *defaultEval) {
+ if (EvalCallCheckers.empty() && defaultEval == 0) {
+ Dst.insert(Src);
+ return;
+ }
+
+ for (ExplodedNodeSet::iterator
+ NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
+
+ ExplodedNode *Pred = *NI;
+ bool anyEvaluated = false;
+ for (std::vector<EvalCallFunc>::iterator
+ EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
+ EI != EE; ++EI) {
+ ExplodedNodeSet checkDst;
+ CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker,
+ ProgramPoint::PostStmtKind, 0, CE);
+ bool evaluated = (*EI)(CE, C);
+ assert(!(evaluated && anyEvaluated)
+ && "There are more than one checkers evaluating the call");
+ if (evaluated) {
+ anyEvaluated = true;
+ Dst.insert(checkDst);
+#ifdef NDEBUG
+ break; // on release don't check that no other checker also evals.
+#endif
+ }
+ }
+
+ if (!anyEvaluated) {
+ if (defaultEval)
+ defaultEval->expandGraph(Dst, Pred);
+ else
+ Dst.insert(Pred);
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for AST traversing.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
HandlesDeclFunc isForDeclFn) {
- DeclCheckerInfo info = { checker, checkfn, isForDeclFn };
+ DeclCheckerInfo info = { checkfn, isForDeclFn };
DeclCheckers.push_back(info);
}
-void CheckerManager::_registerForBody(CheckerRef checker,
- CheckDeclFunc checkfn) {
- BodyCheckers.push_back(std::make_pair(checker, checkfn));
+void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
+ BodyCheckers.push_back(checkfn);
}
-void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
- for (unsigned i = 0, e = Funcs.size(); i != e; ++i)
- Funcs[i](eng);
+//===----------------------------------------------------------------------===//
+// Internal registration functions for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
+ HandlesStmtFunc isForStmtFn) {
+ StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
+ StmtCheckers.push_back(info);
+}
+void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
+ HandlesStmtFunc isForStmtFn) {
+ StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
+ StmtCheckers.push_back(info);
}
-CheckerManager::~CheckerManager() {
- for (unsigned i = 0, e = Checkers.size(); i != e; ++i) {
- CheckerRef checker = Checkers[i].first;
- Dtor dtor = Checkers[i].second;
- dtor(checker);
+void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
+ PreObjCMessageCheckers.push_back(checkfn);
+}
+void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
+ PostObjCMessageCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
+ LocationCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
+ EndAnalysisCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
+ EndPathCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
+ LiveSymbolsCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
+ DeadSymbolsCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
+ WantsRegionChangeUpdateFunc wantUpdateFn) {
+ RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
+ RegionChangesCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
+ EvalCallCheckers.push_back(checkfn);
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation details.
+//===----------------------------------------------------------------------===//
+
+CheckerManager::CachedStmtCheckers *
+CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
+ assert(S);
+
+ CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
+ CachedStmtCheckers *checkers = 0;
+ CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
+ if (CCI != CachedStmtCheckersMap.end()) {
+ checkers = &(CCI->second);
+ } else {
+ // Find the checkers that should run for this Stmt and cache them.
+ checkers = &CachedStmtCheckersMap[key];
+ for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
+ StmtCheckerInfo &info = StmtCheckers[i];
+ if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
+ checkers->push_back(info.CheckFn);
+ }
}
+
+ assert(checkers);
+ return checkers;
+}
+
+CheckerManager::~CheckerManager() {
+ for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
+ CheckerDtors[i]();
}
// Anchor for the vtable.
CheckerProvider::~CheckerProvider() { }
+
+// Anchor for the vtable.
+GraphExpander::~GraphExpander() { }
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 070042a..08a2068 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -718,13 +718,14 @@ EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
}
ExplodedNode*
-EndOfFunctionNodeBuilder::generateNode(const GRState* State, const void *tag,
- ExplodedNode* P) {
+EndOfFunctionNodeBuilder::generateNode(const GRState* State,
+ ExplodedNode* P, const void *tag) {
hasGeneratedNode = true;
bool IsNew;
ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
- Pred->getLocationContext(), tag), State, &IsNew);
+ Pred->getLocationContext(), tag ? tag : Tag),
+ State, &IsNew);
Node->addPredecessor(P ? P : Pred, *Eng.G);
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index ecaff29..1bffa30 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -32,6 +32,11 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
switch (E->getStmtClass()) {
case Stmt::AddrLabelExprClass:
return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
+ case Stmt::OpaqueValueExprClass: {
+ const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E);
+ E = ope->getSourceExpr();
+ continue;
+ }
case Stmt::ParenExprClass:
// ParenExprs are no-ops.
E = cast<ParenExpr>(E)->getSubExpr();
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index dbfebcc..e3e7ee9 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -175,7 +175,8 @@ public:
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- checkerMgr.reset(registerCheckers(Opts, PP.getDiagnostics()));
+ checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
+ PP.getDiagnostics()));
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
@@ -339,9 +340,6 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
return;
ExprEngine Eng(mgr, TF.take());
- if (C.Opts.EnableExperimentalInternalChecks)
- RegisterExperimentalInternalChecks(Eng);
-
RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D);
if (C.Opts.EnableExperimentalChecks)
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index cd9ac1b..16014ba 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -16,5 +16,5 @@ add_dependencies(clangStaticAnalyzerFrontend
ClangAttrClasses
ClangAttrList
ClangDeclNodes
- ClangStmtNode
+ ClangStmtNodes
)
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 6625729..677e20c 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "../Checkers/ClangSACheckerProvider.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
#include "clang/Frontend/AnalyzerOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
@@ -25,8 +27,9 @@ using namespace clang;
using namespace ento;
CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
+ const LangOptions &langOpts,
Diagnostic &diags) {
- llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager());
+ llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
llvm::SmallVector<CheckerOptInfo, 8> checkerOpts;
for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
@@ -48,3 +51,16 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
return checkerMgr.take();
}
+
+void ento::printCheckerHelp(llvm::raw_ostream &OS) {
+ OS << "OVERVIEW: Clang Static Analyzer Checkers List\n";
+ OS << '\n';
+ OS << "USAGE: -analyzer-checker <check1,check2,...>\n";
+ OS << '\n';
+ OS << "CHECKERS:\n";
+
+ llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
+ provider->printHelp(OS);
+
+ // FIXME: Load CheckerProviders from plugins.
+}
OpenPOWER on IntegriCloud