diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-12-01 11:08:04 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-12-01 11:08:04 +0000 |
commit | 1569ce68681d909594d64f9b056d71f5dd7563bf (patch) | |
tree | 867cbbe32a66fd7d62dd9ce9df23a23fefdb8290 | |
parent | f5bd02d290ff15268853e0456c130a1afa15e907 (diff) | |
download | src-1569ce68681d909594d64f9b056d71f5dd7563bf.tar.gz src-1569ce68681d909594d64f9b056d71f5dd7563bf.zip |
Update clang to r90226.
Notes
Notes:
svn path=/vendor/clang/dist/; revision=199990
521 files changed, 17012 insertions, 9269 deletions
@@ -45,7 +45,7 @@ install-local:: for hdr in `find . -type f '!' '(' -name '*~' \ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ -o -name 'Makefile' -o -name '*.td' ')' -print \ - | grep -v CVS | grep -v .svn` ; do \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \ if test \! -d "$$instdir" ; then \ $(EchoCmd) Making install directory $$instdir ; \ @@ -58,7 +58,7 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \ cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \ - | grep -v CVS | grep -v .tmp` ; do \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \ done ; \ fi diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index f0a2194cb2c7..1ad7019aa00b 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -31,14 +31,14 @@ 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; }; 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; }; 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; }; - 1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */; }; + 1A4C41BF105B4C0B0047B5E7 /* CGClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */; }; 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */; }; 1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; }; 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; }; 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; }; - 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */; }; + 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */; }; 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRtti.cpp */; }; - 1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */; }; + 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */; }; 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; }; 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; }; 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; }; @@ -369,7 +369,7 @@ 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; }; - 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGClass.cpp; path = lib/CodeGen/CGClass.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = "<group>"; }; 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; @@ -378,9 +378,9 @@ 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = "<group>"; tabWidth = 2; }; - 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprCXX.cpp; path = lib/CodeGen/CGExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = "<group>"; tabWidth = 2; }; - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGTemporaries.cpp; path = lib/CodeGen/CGTemporaries.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; }; 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = "<group>"; }; @@ -1265,11 +1265,10 @@ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */, 35475B1F0E79973F0000BFE4 /* CGCall.cpp */, 35475B220E7997680000BFE4 /* CGCall.h */, + 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */, 1A5D5E570E5E81010023C059 /* CGCXX.cpp */, 1A649E1E0F9599DA005B965E /* CGCXX.h */, - 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */, - 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */, - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */, + 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */, 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */, 35A3E7010DD3874400757F74 /* CGDebugInfo.h */, DE4264FB0C113592005A861D /* CGDecl.cpp */, @@ -1287,6 +1286,7 @@ 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */, 1A6C01F6108128710072DEE4 /* CGRtti.cpp */, DE4772F90C10EAE5002239E8 /* CGStmt.cpp */, + 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */, 35475B230E7997680000BFE4 /* CGValue.h */, 1A81AA18108144F40094E50B /* CGVtable.cpp */, 1A81AA5D108278A20094E50B /* CGVtable.h */, @@ -1899,7 +1899,7 @@ 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */, 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */, 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */, - 1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */, + 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */, BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */, 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */, @@ -1922,10 +1922,10 @@ 9012911D1048068D0083456D /* ASTUnit.cpp in Sources */, 90129121104812F90083456D /* CIndex.cpp in Sources */, 90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */, - 1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */, + 1A4C41BF105B4C0B0047B5E7 /* CGClass.cpp in Sources */, 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */, 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */, - 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */, + 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */, 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */, 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */, 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f9d2f71b1f28..4f29e5d8a618 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -120,8 +120,7 @@ class ASTContext { QualType ObjCIdTypedefType; /// ObjCSelType - another pseudo built-in typedef type (set by Sema). - QualType ObjCSelType; - const RecordType *SelStructType; + QualType ObjCSelTypedefType; /// ObjCProtoType - another pseudo built-in typedef type (set by Sema). QualType ObjCProtoType; @@ -244,6 +243,7 @@ public: // pseudo-builtins QualType ObjCIdRedefinitionType; QualType ObjCClassRedefinitionType; + QualType ObjCSelRedefinitionType; /// \brief Source ranges for all of the comments in the source file, /// sorted in order of appearance in the translation unit. @@ -316,7 +316,7 @@ public: CanQualType OverloadTy; CanQualType DependentTy; CanQualType UndeducedAutoTy; - CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy; + CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, @@ -532,8 +532,7 @@ public: QualType Canon = QualType()); QualType getTemplateSpecializationType(TemplateName T, - const TemplateArgumentLoc *Args, - unsigned NumArgs, + const TemplateArgumentListInfo &Args, QualType Canon = QualType()); QualType getQualifiedNameType(NestedNameSpecifier *NNS, @@ -696,7 +695,7 @@ public: void setObjCIdType(QualType T); void setObjCSelType(QualType T); - QualType getObjCSelType() const { return ObjCSelType; } + QualType getObjCSelType() const { return ObjCSelTypedefType; } void setObjCProtoType(QualType QT); QualType getObjCProtoType() const { return ObjCProtoType; } @@ -734,6 +733,8 @@ public: return getExtQualType(T, Qs); } + DeclarationName getNameForTemplate(TemplateName Name); + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template); @@ -796,6 +797,20 @@ public: return getTypeInfo(T).first; } + /// getByteWidth - Return the size of a byte, in bits + uint64_t getByteSize() { + return getTypeSize(CharTy); + } + + /// getTypeSizeInBytes - Return the size of the specified type, in bytes. + /// This method does not work on incomplete types. + uint64_t getTypeSizeInBytes(QualType T) { + return getTypeSize(T) / getByteSize(); + } + uint64_t getTypeSizeInBytes(const Type *T) { + return getTypeSize(T) / getByteSize(); + } + /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. /// This method does not work on incomplete types. unsigned getTypeAlign(QualType T) { @@ -811,10 +826,7 @@ public: /// a data type. unsigned getPreferredTypeAlign(const Type *T); - /// getDeclAlignInBytes - Return the alignment of the specified decl - /// that should be returned by __alignof(). Note that bitfields do - /// not have a valid alignment, so this method will assert on them. - unsigned getDeclAlignInBytes(const Decl *D); + unsigned getDeclAlignInBytes(const Decl *D, bool RefAsPointee = false); /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field @@ -1023,8 +1035,7 @@ public: return T == ObjCClassTypedefType; } bool isObjCSelType(QualType T) const { - assert(SelStructType && "isObjCSelType used before 'SEL' type is built"); - return T->getAsStructureType() == SelStructType; + return T == ObjCSelTypedefType; } bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index b36ff1229376..2c7ab9d67e95 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -15,12 +15,12 @@ #define LLVM_CLANG_AST_ATTR_H #include "llvm/Support/Casting.h" -using llvm::dyn_cast; - +#include "llvm/ADT/StringRef.h" #include <cassert> #include <cstring> #include <string> #include <algorithm> +using llvm::dyn_cast; namespace clang { class ASTContext; @@ -49,6 +49,7 @@ public: AnalyzerNoReturn, // Clang-specific. Annotate, AsmLabel, // Represent GCC asm label extension. + BaseCheck, Blocks, CDecl, Cleanup, @@ -59,9 +60,11 @@ public: Deprecated, Destructor, FastCall, + Final, Format, FormatArg, GNUInline, + Hiding, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with Malloc, NoDebug, @@ -71,6 +74,7 @@ public: NoThrow, ObjCException, ObjCNSObject, + Override, CFReturnsRetained, // Clang/Checker-specific. NSReturnsRetained, // Clang/Checker-specific. Overloadable, // Clang-specific @@ -184,12 +188,24 @@ public: class AlignedAttr : public Attr { unsigned Alignment; public: - AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} + AlignedAttr(unsigned alignment) + : Attr(Aligned), Alignment(alignment) {} /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } + + /// getMaxAlignment - Get the maximum alignment of attributes on this list. + unsigned getMaxAlignment() const { + const AlignedAttr *Next = getNext<AlignedAttr>(); + if (Next) + return std::max(Next->getMaxAlignment(), Alignment); + else + return Alignment; + } - virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } + virtual Attr* clone(ASTContext &C) const { + return ::new (C) AlignedAttr(Alignment); + } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { @@ -201,7 +217,7 @@ public: class AnnotateAttr : public Attr { std::string Annotation; public: - AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {} + AnnotateAttr(llvm::StringRef ann) : Attr(Annotate), Annotation(ann) {} const std::string& getAnnotation() const { return Annotation; } @@ -217,7 +233,7 @@ public: class AsmLabelAttr : public Attr { std::string Label; public: - AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {} + AsmLabelAttr(llvm::StringRef L) : Attr(AsmLabel), Label(L) {} const std::string& getLabel() const { return Label; } @@ -235,7 +251,7 @@ DEF_SIMPLE_ATTR(AlwaysInline); class AliasAttr : public Attr { std::string Aliasee; public: - AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {} + AliasAttr(llvm::StringRef aliasee) : Attr(Alias), Aliasee(aliasee) {} const std::string& getAliasee() const { return Aliasee; } @@ -304,11 +320,12 @@ DEF_SIMPLE_ATTR(Malloc); DEF_SIMPLE_ATTR(NoReturn); DEF_SIMPLE_ATTR(AnalyzerNoReturn); DEF_SIMPLE_ATTR(Deprecated); +DEF_SIMPLE_ATTR(Final); class SectionAttr : public Attr { std::string Name; public: - SectionAttr(const std::string &N) : Attr(Section), Name(N) {} + SectionAttr(llvm::StringRef N) : Attr(Section), Name(N) {} const std::string& getName() const { return Name; } @@ -367,11 +384,11 @@ class FormatAttr : public Attr { std::string Type; int formatIdx, firstArg; public: - FormatAttr(const std::string &type, int idx, int first) : Attr(Format), + FormatAttr(llvm::StringRef type, int idx, int first) : Attr(Format), Type(type), formatIdx(idx), firstArg(first) {} const std::string& getType() const { return Type; } - void setType(const std::string &type) { Type = type; } + void setType(llvm::StringRef type) { Type = type; } int getFormatIdx() const { return formatIdx; } int getFirstArg() const { return firstArg; } @@ -544,6 +561,11 @@ public: DEF_SIMPLE_ATTR(CFReturnsRetained); DEF_SIMPLE_ATTR(NSReturnsRetained); +// C++0x member checking attributes. +DEF_SIMPLE_ATTR(BaseCheck); +DEF_SIMPLE_ATTR(Hiding); +DEF_SIMPLE_ATTR(Override); + #undef DEF_SIMPLE_ATTR } // end namespace clang diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ac79a91792d7..f7944771efce 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -54,6 +54,32 @@ public: TypeLoc getTypeLoc() const; }; +/// UnresolvedSet - A set of unresolved declarations. This is needed +/// in a lot of places, but isn't really worth breaking into its own +/// header right now. +class UnresolvedSet { + typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; + DeclsTy Decls; + +public: + void addDecl(NamedDecl *D) { + Decls.push_back(D); + } + + bool replace(const NamedDecl* Old, NamedDecl *New) { + for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) + if (*I == Old) + return (*I = New, true); + return false; + } + + unsigned size() const { return Decls.size(); } + + typedef DeclsTy::const_iterator iterator; + iterator begin() const { return Decls.begin(); } + iterator end() const { return Decls.end(); } +}; + /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { ASTContext &Ctx; @@ -172,6 +198,26 @@ public: /// \brief Determine whether this declaration has linkage. bool hasLinkage() const; + /// \brief Describes the different kinds of linkage + /// (C++ [basic.link], C99 6.2.2) that an entity may have. + enum Linkage { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage + }; + + /// \brief Determine what kind of linkage this entity has. + Linkage getLinkage() const; + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl(); diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 79f766356138..e1f948fdd550 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -503,12 +503,12 @@ private: /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when /// doing something to a specific decl. class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { - Decl *TheDecl; + const Decl *TheDecl; SourceLocation Loc; SourceManager &SM; const char *Message; public: - PrettyStackTraceDecl(Decl *theDecl, SourceLocation L, + PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index e5bf78cd10d2..990403e7dc2e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -376,13 +376,13 @@ class CXXRecordDecl : public RecordDecl { /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a /// CXXConversionDecl. - OverloadedFunctionDecl Conversions; + UnresolvedSet Conversions; /// VisibleConversions - Overload set containing the conversion functions /// of this C++ class and all those inherited conversion functions that /// are visible in this class. Each of the entries in this overload set is /// a CXXConversionDecl or a FunctionTemplateDecl. - OverloadedFunctionDecl VisibleConversions; + UnresolvedSet VisibleConversions; /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. @@ -400,7 +400,7 @@ class CXXRecordDecl : public RecordDecl { const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes); void collectConversionFunctions( - llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet); + llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const; protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -581,22 +581,34 @@ public: /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. - OverloadedFunctionDecl *getConversionFunctions() { + UnresolvedSet *getConversionFunctions() { assert((this->isDefinition() || cast<RecordType>(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } - const OverloadedFunctionDecl *getConversionFunctions() const { + const UnresolvedSet *getConversionFunctions() const { assert((this->isDefinition() || cast<RecordType>(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } + typedef UnresolvedSet::iterator conversion_iterator; + conversion_iterator conversion_begin() const { return Conversions.begin(); } + conversion_iterator conversion_end() const { return Conversions.end(); } + + /// Replaces a conversion function with a new declaration. + /// + /// Returns true if the old conversion was found. + bool replaceConversion(const NamedDecl* Old, NamedDecl *New) { + return Conversions.replace(Old, New); + } + /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. - OverloadedFunctionDecl *getVisibleConversionFunctions(); + const UnresolvedSet *getVisibleConversionFunctions(); + /// addVisibleConversionFunction - Add a new conversion function to the /// list of visible conversion functions. void addVisibleConversionFunction(CXXConversionDecl *ConvDecl); @@ -1502,9 +1514,9 @@ class UsingDirectiveDecl : public NamedDecl { SourceLocation IdentLoc; /// NominatedNamespace - Namespace nominated by using-directive. - NamespaceDecl *NominatedNamespace; + NamedDecl *NominatedNamespace; - /// Enclosing context containing both using-directive and nomintated + /// Enclosing context containing both using-directive and nominated /// namespace. DeclContext *CommonAncestor; @@ -1520,12 +1532,12 @@ class UsingDirectiveDecl : public NamedDecl { SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Nominated, + NamedDecl *Nominated, DeclContext *CommonAncestor) : NamedDecl(Decl::UsingDirective, DC, L, getName()), NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange), Qualifier(Qualifier), IdentLoc(IdentLoc), - NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0), + NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) { } @@ -1538,8 +1550,13 @@ public: /// name of the namespace. NestedNameSpecifier *getQualifier() const { return Qualifier; } + NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; } + const NamedDecl *getNominatedNamespaceAsWritten() const { + return NominatedNamespace; + } + /// getNominatedNamespace - Returns namespace nominated by using-directive. - NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; } + NamespaceDecl *getNominatedNamespace(); const NamespaceDecl *getNominatedNamespace() const { return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace(); @@ -1562,7 +1579,7 @@ public: SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Nominated, + NamedDecl *Nominated, DeclContext *CommonAncestor); static bool classof(const Decl *D) { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 14f666005cd6..3ecc4bb52b4c 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -955,8 +955,7 @@ public: TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, - TemplateArgumentLoc *ArgInfos, - unsigned NumArgInfos, + const TemplateArgumentListInfo &ArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl); /// Get the list of template parameters diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index a30f6e860dde..676bd2ca7336 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -25,6 +25,7 @@ namespace llvm { namespace clang { class CXXSpecialName; class CXXOperatorIdName; + class CXXLiteralOperatorIdName; class DeclarationNameExtra; class IdentifierInfo; class MultiKeywordSelector; @@ -48,6 +49,7 @@ public: CXXDestructorName, CXXConversionFunctionName, CXXOperatorName, + CXXLiteralOperatorName, CXXUsingDirective }; @@ -115,6 +117,12 @@ private: return 0; } + CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { + if (getNameKind() == CXXLiteralOperatorName) + return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask); + return 0; + } + // Construct a declaration name from the name of a C++ constructor, // destructor, or conversion function. DeclarationName(CXXSpecialName *Name) @@ -131,6 +139,12 @@ private: Ptr |= StoredDeclarationNameExtra; } + DeclarationName(CXXLiteralOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + /// Construct a declaration name from a raw pointer. DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } @@ -201,7 +215,7 @@ public: N.Ptr = reinterpret_cast<uintptr_t> (P); return N; } - + static DeclarationName getFromOpaqueInteger(uintptr_t P) { DeclarationName N; N.Ptr = P; @@ -218,6 +232,10 @@ public: /// kind of overloaded operator. OverloadedOperatorKind getCXXOverloadedOperator() const; + /// getCXXLiteralIdentifier - If this name is the name of a literal + /// operator, retrieve the identifier associated with it. + IdentifierInfo *getCXXLiteralIdentifier() const; + /// getObjCSelector - Get the Objective-C selector stored in this /// declaration name. Selector getObjCSelector() const; @@ -293,7 +311,7 @@ public: /// getIdentifier - Create a declaration name that is a simple /// identifier. - DeclarationName getIdentifier(IdentifierInfo *ID) { + DeclarationName getIdentifier(const IdentifierInfo *ID) { return DeclarationName(ID); } @@ -324,6 +342,10 @@ public: /// getCXXOperatorName - Get the name of the overloadable C++ /// operator corresponding to Op. DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); + + /// getCXXLiteralOperatorName - Get the name of the literal operator function + /// with II as the identifier. + DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II); }; /// Insertion operator for diagnostics. This allows sending DeclarationName's diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index dfc5b13f28d3..7cf9aabc6d6f 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -35,6 +35,7 @@ namespace clang { class CXXOperatorCallExpr; class CXXMemberCallExpr; class TemplateArgumentLoc; + class TemplateArgumentListInfo; /// Expr - This represents one expression. Note that Expr's are subclasses of /// Stmt. This allows an expression to be transparently used any place a Stmt @@ -366,6 +367,10 @@ struct ExplicitTemplateArgumentList { const TemplateArgumentLoc *getTemplateArgs() const { return reinterpret_cast<const TemplateArgumentLoc *> (this + 1); } + + void initializeFrom(const TemplateArgumentListInfo &List); + void copyInto(TemplateArgumentListInfo &List) const; + static std::size_t sizeFor(const TemplateArgumentListInfo &List); }; /// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function, @@ -423,31 +428,24 @@ class DeclRefExpr : public Expr { DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD); + const TemplateArgumentListInfo *TemplateArgs, + QualType T); protected: - // FIXME: Eventually, this constructor will go away and all subclasses - // will have to provide the type- and value-dependent flags. - DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : - Expr(SC, t), DecoratedD(d, 0), Loc(l) {} + /// \brief Computes the type- and value-dependence flags for this + /// declaration reference expression. + void computeDependence(); - DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD, - bool VD) : - Expr(SC, t, TD, VD), DecoratedD(d, 0), Loc(l) {} + DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : + Expr(SC, t, false, false), DecoratedD(d, 0), Loc(l) { + computeDependence(); + } public: - // FIXME: Eventually, this constructor will go away and all clients - // will have to provide the type- and value-dependent flags. DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : - Expr(DeclRefExprClass, t), DecoratedD(d, 0), Loc(l) {} - - DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : - Expr(DeclRefExprClass, t, TD, VD), DecoratedD(d, 0), Loc(l) {} + Expr(DeclRefExprClass, t, false, false), DecoratedD(d, 0), Loc(l) { + computeDependence(); + } /// \brief Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) @@ -458,19 +456,8 @@ public: SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - QualType T, bool TD, bool VD); - - static DeclRefExpr *Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - NamedDecl *D, - SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD); + QualType T, + const TemplateArgumentListInfo *TemplateArgs = 0); NamedDecl *getDecl() { return DecoratedD.getPointer(); } const NamedDecl *getDecl() const { return DecoratedD.getPointer(); } @@ -508,6 +495,13 @@ public: bool hasExplicitTemplateArgumentList() const { return DecoratedD.getInt() & HasExplicitTemplateArgumentListFlag; } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. @@ -546,8 +540,7 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == DeclRefExprClass || - T->getStmtClass() == CXXConditionDeclExprClass; + return T->getStmtClass() == DeclRefExprClass; } static bool classof(const DeclRefExpr *) { return true; } @@ -1313,9 +1306,7 @@ class MemberExpr : public Expr { MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, SourceLocation langle, - const TemplateArgumentLoc *targs, unsigned numtargs, - SourceLocation rangle, QualType ty); + const TemplateArgumentListInfo *targs, QualType ty); public: MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, @@ -1334,11 +1325,7 @@ public: NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, - unsigned numtargs, - SourceLocation rangle, + const TemplateArgumentListInfo *targs, QualType ty); void setBase(Expr *E) { Base = E; } @@ -1378,10 +1365,17 @@ public: /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f<int>. - bool hasExplicitTemplateArgumentList() { + bool hasExplicitTemplateArgumentList() const { return HasExplicitTemplateArgumentList; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } + /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { @@ -1579,7 +1573,11 @@ public: CK_FloatingToIntegral, /// CK_FloatingCast - Casting between floating types of different size. - CK_FloatingCast + CK_FloatingCast, + + /// CK_MemberPointerToBoolean - Member pointer to boolean + CK_MemberPointerToBoolean + }; private: diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 9e6fd4fd065b..23844ce5d967 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -17,6 +17,7 @@ #include "clang/Basic/TypeTraits.h" #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" namespace clang { @@ -24,6 +25,7 @@ namespace clang { class CXXDestructorDecl; class CXXMethodDecl; class CXXTemporary; + class TemplateArgumentListInfo; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -669,40 +671,6 @@ public: virtual child_iterator child_end(); }; -/// CXXConditionDeclExpr - Condition declaration of a if/switch/while/for -/// statement, e.g: "if (int x = f()) {...}". -/// The main difference with DeclRefExpr is that CXXConditionDeclExpr owns the -/// decl that it references. -/// -class CXXConditionDeclExpr : public DeclRefExpr { -public: - CXXConditionDeclExpr(SourceLocation startLoc, - SourceLocation eqLoc, VarDecl *var) - : DeclRefExpr(CXXConditionDeclExprClass, var, - var->getType().getNonReferenceType(), startLoc, - var->getType()->isDependentType(), - /*FIXME:integral constant?*/ - var->getType()->isDependentType()) {} - - SourceLocation getStartLoc() const { return getLocation(); } - - VarDecl *getVarDecl() { return cast<VarDecl>(getDecl()); } - const VarDecl *getVarDecl() const { return cast<VarDecl>(getDecl()); } - - virtual SourceRange getSourceRange() const { - return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd()); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXConditionDeclExprClass; - } - static bool classof(const CXXConditionDeclExpr *) { return true; } - - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; - /// CXXNewExpr - A new expression for memory allocation and constructor calls, /// e.g: "new CXXNewExpr(foo)". class CXXNewExpr : public Expr { @@ -975,52 +943,6 @@ public: virtual child_iterator child_end(); }; -/// \brief Represents the name of a function that has not been -/// resolved to any declaration. -/// -/// Unresolved function names occur when a function name is -/// encountered prior to an open parentheses ('(') in a C++ function -/// call, and the function name itself did not resolve to a -/// declaration. These function names can only be resolved when they -/// form the postfix-expression of a function call, so that -/// argument-dependent lookup finds declarations corresponding to -/// these functions. - -/// @code -/// template<typename T> void f(T x) { -/// g(x); // g is an unresolved function name (that is also a dependent name) -/// } -/// @endcode -class UnresolvedFunctionNameExpr : public Expr { - /// The name that was present in the source - DeclarationName Name; - - /// The location of this name in the source code - SourceLocation Loc; - -public: - UnresolvedFunctionNameExpr(DeclarationName N, QualType T, SourceLocation L) - : Expr(UnresolvedFunctionNameExprClass, T, false, false), Name(N), Loc(L) { } - - /// \brief Retrieves the name that occurred in the source code. - DeclarationName getName() const { return Name; } - - /// getLocation - Retrieves the location in the source code where - /// the name occurred. - SourceLocation getLocation() const { return Loc; } - - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == UnresolvedFunctionNameExprClass; - } - static bool classof(const UnresolvedFunctionNameExpr *) { return true; } - - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; - /// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the /// implementation of TR1/C++0x type trait templates. /// Example: @@ -1063,21 +985,177 @@ public: virtual child_iterator child_end(); }; +/// \brief A reference to a name which we were able to look up during +/// parsing but could not resolve to a specific declaration. This +/// arises in several ways: +/// * we might be waiting for argument-dependent lookup +/// * the name might resolve to an overloaded function +/// and eventually: +/// * the lookup might have included a function template +/// These never include UnresolvedUsingValueDecls, which are always +/// class members and therefore appear only in +/// UnresolvedMemberLookupExprs. +class UnresolvedLookupExpr : public Expr { + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. + UnresolvedSet Results; + + /// The name declared. + DeclarationName Name; + + /// The qualifier given, if any. + NestedNameSpecifier *Qualifier; + + /// The source range of the nested name specifier. + SourceRange QualifierRange; + + /// The location of the name. + SourceLocation NameLoc; + + /// True if these lookup results should be extended by + /// argument-dependent lookup if this is the operand of a function + /// call. + bool RequiresADL; + + /// True if these lookup results are overloaded. This is pretty + /// trivially rederivable if we urgently need to kill this field. + bool Overloaded; + + /// True if the name looked up had explicit template arguments. + /// This requires all the results to be function templates. + bool HasExplicitTemplateArgs; + + UnresolvedLookupExpr(QualType T, bool Dependent, + NestedNameSpecifier *Qualifier, SourceRange QRange, + DeclarationName Name, SourceLocation NameLoc, + bool RequiresADL, bool Overloaded, bool HasTemplateArgs) + : Expr(UnresolvedLookupExprClass, T, Dependent, Dependent), + Name(Name), Qualifier(Qualifier), QualifierRange(QRange), + NameLoc(NameLoc), RequiresADL(RequiresADL), Overloaded(Overloaded), + HasExplicitTemplateArgs(HasTemplateArgs) + {} + +public: + static UnresolvedLookupExpr *Create(ASTContext &C, + bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool ADL, bool Overloaded) { + return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + Dependent, Qualifier, QualifierRange, + Name, NameLoc, ADL, Overloaded, false); + } + + static UnresolvedLookupExpr *Create(ASTContext &C, + bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool ADL, + const TemplateArgumentListInfo &Args); + + /// Computes whether an unresolved lookup on the given declarations + /// and optional template arguments is type- and value-dependent. + static bool ComputeDependence(NamedDecl * const *Begin, + NamedDecl * const *End, + const TemplateArgumentListInfo *Args); + + void addDecl(NamedDecl *Decl) { + Results.addDecl(Decl); + } + + typedef UnresolvedSet::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + /// True if this declaration should be extended by + /// argument-dependent lookup. + bool requiresADL() const { return RequiresADL; } + + /// True if this lookup is overloaded. + bool isOverloaded() const { return Overloaded; } + + /// Fetches the name looked up. + DeclarationName getName() const { return Name; } + + /// Gets the location of the name. + SourceLocation getNameLoc() const { return NameLoc; } + + /// Fetches the nested-name qualifier, if one was given. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// Fetches the range of the nested-name qualifier. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } + + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. + + /// Gets a reference to the explicit template argument list. + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1); + } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs().LAngleLoc; + } + + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs().RAngleLoc; + } + + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } + + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } + + virtual SourceRange getSourceRange() const { + SourceRange Range(NameLoc); + if (Qualifier) Range.setBegin(QualifierRange.getBegin()); + if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); + return Range; + } + + virtual StmtIterator child_begin(); + virtual StmtIterator child_end(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass; + } + static bool classof(const UnresolvedLookupExpr *) { return true; } +}; + /// \brief A qualified reference to a name whose declaration cannot /// yet be resolved. /// -/// UnresolvedDeclRefExpr is similar to eclRefExpr in that +/// DependentScopeDeclRefExpr is similar to DeclRefExpr in that /// it expresses a reference to a declaration such as /// X<T>::value. The difference, however, is that an -/// UnresolvedDeclRefExpr node is used only within C++ templates when +/// DependentScopeDeclRefExpr node is used only within C++ templates when /// the qualification (e.g., X<T>::) refers to a dependent type. In /// this case, X<T>::value cannot resolve to a declaration because the /// declaration will differ from on instantiation of X<T> to the -/// next. Therefore, UnresolvedDeclRefExpr keeps track of the +/// next. Therefore, DependentScopeDeclRefExpr keeps track of the /// qualifier (X<T>::) and the name of the entity being referenced /// ("value"). Such expressions will instantiate to a DeclRefExpr once the /// declaration can be found. -class UnresolvedDeclRefExpr : public Expr { +class DependentScopeDeclRefExpr : public Expr { /// The name of the entity we will be referencing. DeclarationName Name; @@ -1090,19 +1168,30 @@ class UnresolvedDeclRefExpr : public Expr { /// \brief The nested-name-specifier that qualifies this unresolved /// declaration name. - NestedNameSpecifier *NNS; + NestedNameSpecifier *Qualifier; - /// \brief Whether this expr is an address of (&) operand. - /// FIXME: Stash this bit into NNS! - bool IsAddressOfOperand; + /// \brief Whether the name includes explicit template arguments. + bool HasExplicitTemplateArgs; + + DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool HasExplicitTemplateArgs) + : Expr(DependentScopeDeclRefExprClass, T, true, true), + Name(Name), Loc(NameLoc), + QualifierRange(QualifierRange), Qualifier(Qualifier), + HasExplicitTemplateArgs(HasExplicitTemplateArgs) + {} public: - UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, - SourceRange R, NestedNameSpecifier *NNS, - bool IsAddressOfOperand) - : Expr(UnresolvedDeclRefExprClass, T, true, true), - Name(N), Loc(L), QualifierRange(R), NNS(NNS), - IsAddressOfOperand(IsAddressOfOperand) { } + static DependentScopeDeclRefExpr *Create(ASTContext &C, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs = 0); /// \brief Retrieve the name that this expression refers to. DeclarationName getDeclName() const { return Name; } @@ -1115,116 +1204,57 @@ public: /// \brief Retrieve the nested-name-specifier that qualifies this /// declaration. - NestedNameSpecifier *getQualifier() const { return NNS; } - - /// \brief Retrieve whether this is an address of (&) operand. - - bool isAddressOfOperand() const { return IsAddressOfOperand; } - virtual SourceRange getSourceRange() const { - return SourceRange(QualifierRange.getBegin(), getLocation()); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == UnresolvedDeclRefExprClass; - } - static bool classof(const UnresolvedDeclRefExpr *) { return true; } - - virtual StmtIterator child_begin(); - virtual StmtIterator child_end(); -}; - -/// \brief An expression that refers to a C++ template-id, such as -/// @c isa<FunctionDecl>. -class TemplateIdRefExpr : public Expr { - /// \brief If this template-id was qualified-id, e.g., @c std::sort<int>, - /// this nested name specifier contains the @c std::. - NestedNameSpecifier *Qualifier; - - /// \brief If this template-id was a qualified-id, e.g., @c std::sort<int>, - /// this covers the source code range of the @c std::. - SourceRange QualifierRange; - - /// \brief The actual template to which this template-id refers. - TemplateName Template; - - /// \brief The source location of the template name. - SourceLocation TemplateNameLoc; - - /// \brief The source location of the left angle bracket ('<'); - SourceLocation LAngleLoc; - - /// \brief The source location of the right angle bracket ('>'); - SourceLocation RAngleLoc; - - /// \brief The number of template arguments in TemplateArgs. - unsigned NumTemplateArgs; - - TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); - - virtual void DoDestroy(ASTContext &Context); - -public: - static TemplateIdRefExpr * - Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, SourceLocation RAngleLoc); - - /// \brief Retrieve the nested name specifier used to qualify the name of - /// this template-id, e.g., the "std::sort" in @c std::sort<int>, or NULL - /// if this template-id was an unqualified-id. NestedNameSpecifier *getQualifier() const { return Qualifier; } - /// \brief Retrieve the source range describing the nested name specifier - /// used to qualified the name of this template-id, if the name was qualified. - SourceRange getQualifierRange() const { return QualifierRange; } + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } - /// \brief Retrieve the name of the template referenced, e.g., "sort" in - /// @c std::sort<int>; - TemplateName getTemplateName() const { return Template; } + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. - /// \brief Retrieve the location of the name of the template referenced, e.g., - /// the location of "sort" in @c std::sort<int>. - SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; } + /// Gets a reference to the explicit template argument list. + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1); + } - /// \brief Retrieve the location of the left angle bracket following the - /// template name ('<'). - SourceLocation getLAngleLoc() const { return LAngleLoc; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs().LAngleLoc; + } - /// \brief Retrieve the template arguments provided as part of this - /// template-id. - const TemplateArgumentLoc *getTemplateArgs() const { - return reinterpret_cast<const TemplateArgumentLoc *>(this + 1); + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs().RAngleLoc; } - /// \brief Retrieve the number of template arguments provided as part of this - /// template-id. - unsigned getNumTemplateArgs() const { return NumTemplateArgs; } + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } - /// \brief Retrieve the location of the right angle bracket following the - /// template arguments ('>'). - SourceLocation getRAngleLoc() const { return RAngleLoc; } + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } virtual SourceRange getSourceRange() const { - return SourceRange(Qualifier? QualifierRange.getBegin() : TemplateNameLoc, - RAngleLoc); + SourceRange Range(QualifierRange.getBegin(), getLocation()); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + return Range; } - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); - static bool classof(const Stmt *T) { - return T->getStmtClass() == TemplateIdRefExprClass; + return T->getStmtClass() == DependentScopeDeclRefExprClass; } - static bool classof(const TemplateIdRefExpr *) { return true; } + static bool classof(const DependentScopeDeclRefExpr *) { return true; } + + virtual StmtIterator child_begin(); + virtual StmtIterator child_end(); }; class CXXExprWithTemporaries : public Expr { @@ -1377,10 +1407,10 @@ public: virtual child_iterator child_end(); }; -/// \brief Represents a C++ member access expression where the actual member -/// referenced could not be resolved, e.g., because the base expression or the -/// member name was dependent. -class CXXUnresolvedMemberExpr : public Expr { +/// \brief Represents a C++ member access expression where the actual +/// member referenced could not be resolved because the base +/// expression or the member name was dependent. +class CXXDependentScopeMemberExpr : public Expr { /// \brief The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Stmt *Base; @@ -1408,7 +1438,7 @@ class CXXUnresolvedMemberExpr : public Expr { /// /// FIXME: This member, along with the Qualifier and QualifierRange, could /// be stuck into a structure that is optionally allocated at the end of - /// the CXXUnresolvedMemberExpr, to save space in the common case. + /// the CXXDependentScopeMemberExpr, to save space in the common case. NamedDecl *FirstQualifierFoundInScope; /// \brief The member to which this member expression refers, which @@ -1431,11 +1461,11 @@ class CXXUnresolvedMemberExpr : public Expr { /// \brief Retrieve the explicit template argument list that followed the /// member template name, if any. const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { - return const_cast<CXXUnresolvedMemberExpr *>(this) + return const_cast<CXXDependentScopeMemberExpr *>(this) ->getExplicitTemplateArgumentList(); } - CXXUnresolvedMemberExpr(ASTContext &C, + CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1443,14 +1473,10 @@ class CXXUnresolvedMemberExpr : public Expr { NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo *TemplateArgs); public: - CXXUnresolvedMemberExpr(ASTContext &C, + CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1458,14 +1484,14 @@ public: NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc) - : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { } - static CXXUnresolvedMemberExpr * + static CXXDependentScopeMemberExpr * Create(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, @@ -1474,11 +1500,7 @@ public: NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo *TemplateArgs); /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. @@ -1529,10 +1551,17 @@ public: /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f<int>. - bool hasExplicitTemplateArgumentList() { + bool hasExplicitTemplateArgumentList() const { return HasExplicitTemplateArgumentList; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } + /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { @@ -1579,9 +1608,182 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXUnresolvedMemberExprClass; + return T->getStmtClass() == CXXDependentScopeMemberExprClass; + } + static bool classof(const CXXDependentScopeMemberExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// \brief Represents a C++ member access expression for which lookup +/// produced a set of overloaded functions. These are replaced with +/// MemberExprs in the final AST. +class UnresolvedMemberExpr : public Expr { + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. + UnresolvedSet Results; + + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. + Stmt *Base; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether the lookup results contain an unresolved using + /// declaration. + bool HasUnresolvedUsing : 1; + + /// \brief Whether this member expression has explicitly-specified template + /// arguments. + bool HasExplicitTemplateArgs : 1; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifier *Qualifier; + + /// \brief The source range covering the nested name specifier. + SourceRange QualifierRange; + + /// \brief The member to which this member expression refers, which + /// can be a name or an overloaded operator. + DeclarationName MemberName; + + /// \brief The location of the member name. + SourceLocation MemberLoc; + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + ExplicitTemplateArgumentList *getExplicitTemplateArgs() { + assert(HasExplicitTemplateArgs); + return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const { + return const_cast<UnresolvedMemberExpr*>(this)->getExplicitTemplateArgs(); + } + + UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + +public: + static UnresolvedMemberExpr * + Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + + /// Adds a declaration to the unresolved set. By assumption, all of + /// these happen at initialization time and properties like + /// 'Dependent' and 'HasUnresolvedUsing' take them into account. + void addDecl(NamedDecl *Decl) { + Results.addDecl(Decl); + } + + typedef UnresolvedSet::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + unsigned getNumDecls() const { return Results.size(); } + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *E) { Base = E; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Retrieve the source range covering the nested-name-specifier + /// that qualifies the member name. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMemberName() const { return MemberName; } + void setMemberName(DeclarationName N) { MemberName = N; } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgs() const { + return HasExplicitTemplateArgs; + } + + /// \brief Copies the template arguments into the given structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs()->copyInto(List); + } + + /// \brief Retrieve the location of the left angle bracket following + /// the member name ('<'). + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + return getExplicitTemplateArgs()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as + /// part of this template-id. + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket + /// following the template arguments ('>'). + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs()->RAngleLoc; + } + + virtual SourceRange getSourceRange() const { + SourceRange Range = Base->getSourceRange(); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberLoc); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedMemberExprClass; } - static bool classof(const CXXUnresolvedMemberExpr *) { return true; } + static bool classof(const UnresolvedMemberExpr *) { return true; } // Iterators virtual child_iterator child_begin(); diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 9b1c640a40b2..5d2973ea9dab 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -47,6 +47,59 @@ class ASTRecordLayout { // FieldCount - Number of fields. unsigned FieldCount; +public: + /// PrimaryBaseInfo - Contains info about a primary base. + struct PrimaryBaseInfo { + PrimaryBaseInfo() {} + + PrimaryBaseInfo(const CXXRecordDecl *Base, bool IsVirtual) + : Value(Base, IsVirtual) {} + + /// Value - Points to the primary base. The single-bit value + /// will be non-zero when the primary base is virtual. + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Value; + + /// getBase - Returns the primary base. + const CXXRecordDecl *getBase() const { return Value.getPointer(); } + + /// isVirtual - Returns whether the primary base is virtual or not. + bool isVirtual() const { return Value.getInt(); } + + friend bool operator==(const PrimaryBaseInfo &X, const PrimaryBaseInfo &Y) { + return X.Value == Y.Value; + } + }; + + /// primary_base_info_iterator - An iterator for iterating the primary base + /// class chain. + class primary_base_info_iterator { + /// Current - The current base class info. + PrimaryBaseInfo Current; + + public: + primary_base_info_iterator() {} + primary_base_info_iterator(PrimaryBaseInfo Info) : Current(Info) {} + + const PrimaryBaseInfo &operator*() const { return Current; } + + primary_base_info_iterator& operator++() { + const CXXRecordDecl *RD = Current.getBase(); + Current = RD->getASTContext().getASTRecordLayout(RD).getPrimaryBaseInfo(); + return *this; + } + + friend bool operator==(const primary_base_info_iterator &X, + const primary_base_info_iterator &Y) { + return X.Current == Y.Current; + } + friend bool operator!=(const primary_base_info_iterator &X, + const primary_base_info_iterator &Y) { + return !(X == Y); + } + }; + +private: + /// CXXRecordLayoutInfo - Contains C++ specific layout information. struct CXXRecordLayoutInfo { /// NonVirtualSize - The non-virtual size (in bits) of an object, which is /// the size of the object without virtual bases. @@ -56,11 +109,9 @@ class ASTRecordLayout { /// which is the alignment of the object without virtual bases. uint64_t NonVirtualAlign; - /// PrimaryBase - The primary base for our vtable. - const CXXRecordDecl *PrimaryBase; - /// PrimaryBase - Wether or not the primary base was a virtual base. - bool PrimaryBaseWasVirtual; - + /// PrimaryBase - The primary base info for this record. + PrimaryBaseInfo PrimaryBase; + /// BaseOffsets - Contains a map from base classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets; @@ -68,6 +119,13 @@ class ASTRecordLayout { /// VBaseOffsets - Contains a map from vbase classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets; + + /// KeyFunction - The key function, according to the Itanium C++ ABI, + /// section 5.2.3: + /// + /// ...the first non-pure virtual function that is not inline at the point + /// of class definition. + const CXXMethodDecl *KeyFunction; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -92,11 +150,12 @@ class ASTRecordLayout { ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize, const uint64_t *fieldoffsets, unsigned fieldcount, uint64_t nonvirtualsize, unsigned nonvirtualalign, - const CXXRecordDecl *PB, bool PBVirtual, + const PrimaryBaseInfo &PrimaryBase, const std::pair<const CXXRecordDecl *, uint64_t> *bases, unsigned numbases, const std::pair<const CXXRecordDecl *, uint64_t> *vbases, - unsigned numvbases) + unsigned numvbases, + const CXXMethodDecl *KeyFunction) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { if (FieldCount > 0) { @@ -105,14 +164,14 @@ class ASTRecordLayout { FieldOffsets[i] = fieldoffsets[i]; } - CXXInfo->PrimaryBase = PB; - CXXInfo->PrimaryBaseWasVirtual = PBVirtual; + CXXInfo->PrimaryBase = PrimaryBase; CXXInfo->NonVirtualSize = nonvirtualsize; CXXInfo->NonVirtualAlign = nonvirtualalign; for (unsigned i = 0; i != numbases; ++i) CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; for (unsigned i = 0; i != numvbases; ++i) CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; + CXXInfo->KeyFunction = KeyFunction; } ~ASTRecordLayout() { @@ -162,17 +221,21 @@ public: return CXXInfo->NonVirtualAlign; } - /// getPrimaryBase - Get the primary base. - const CXXRecordDecl *getPrimaryBase() const { + /// getPrimaryBaseInfo - Get the primary base info. + const PrimaryBaseInfo &getPrimaryBaseInfo() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); return CXXInfo->PrimaryBase; } - /// getPrimaryBaseWasVirtual - Indicates if the primary base was virtual. - bool getPrimaryBaseWasVirtual() const { - assert(CXXInfo && "Record layout does not have C++ specific info!"); - return CXXInfo->PrimaryBaseWasVirtual; + // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. + const CXXRecordDecl *getPrimaryBase() const { + return getPrimaryBaseInfo().getBase(); + } + + // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. + bool getPrimaryBaseWasVirtual() const { + return getPrimaryBaseInfo().isVirtual(); } /// getBaseClassOffset - Get the offset, in bits, for the given base class. @@ -190,6 +253,25 @@ public: return CXXInfo->VBaseOffsets[VBase]; } + + /// getKeyFunction - Get the key function. + const CXXMethodDecl *getKeyFunction() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->KeyFunction; + } + + primary_base_info_iterator primary_base_begin() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return primary_base_info_iterator(getPrimaryBaseInfo()); + } + + primary_base_info_iterator primary_base_end() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return primary_base_info_iterator(); + } }; } // end namespace clang diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index 867932332d09..01f4b29a61f4 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_REDECLARABLE_H #include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" #include <iterator> namespace clang { @@ -92,6 +93,11 @@ public: } /// \brief Returns the most recent (re)declaration of this declaration. + decl_type *getMostRecentDeclaration() { + return getFirstDeclaration()->RedeclLink.getNext(); + } + + /// \brief Returns the most recent (re)declaration of this declaration. const decl_type *getMostRecentDeclaration() const { return getFirstDeclaration()->RedeclLink.getNext(); } @@ -102,8 +108,11 @@ public: decl_type *First; if (PrevDecl) { - // Point to previous. - RedeclLink = PreviousDeclLink(PrevDecl); + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + RedeclLink = PreviousDeclLink(llvm::cast<decl_type>( + PrevDecl->getMostRecentDeclaration())); First = PrevDecl->getFirstDeclaration(); assert(First->RedeclLink.NextIsLatest() && "Expected first"); } else { diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 411f215e912e..d6f6a834d9c1 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -171,6 +171,14 @@ public: } virtual ~Stmt() {} +#ifndef NDEBUG + /// \brief True if this statement's refcount is in a valid state. + /// Should be used only in assertions. + bool isRetained() const { + return (RefCount >= 1); + } +#endif + /// \brief Destroy the current statement and its children. void Destroy(ASTContext &Ctx) { assert(RefCount >= 1); @@ -203,7 +211,7 @@ public: // global temp stats (until we have a per-module visitor) static void addStmtClass(const StmtClass s); - static bool CollectingStats(bool enable=false); + static bool CollectingStats(bool Enable = false); static void PrintStats(); /// dump - This does a local dump of the specified AST fragment. It dumps the @@ -604,22 +612,36 @@ public: class IfStmt : public Stmt { enum { COND, THEN, ELSE, END_EXPR }; Stmt* SubExprs[END_EXPR]; + + /// \brief If non-NULL, the declaration in the "if" statement. + VarDecl *Var; + SourceLocation IfLoc; SourceLocation ElseLoc; + public: - IfStmt(SourceLocation IL, Expr *cond, Stmt *then, + IfStmt(SourceLocation IL, VarDecl *Var, Expr *cond, Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0) - : Stmt(IfStmtClass) { + : Stmt(IfStmtClass), Var(Var), IfLoc(IL), ElseLoc(EL) { SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[THEN] = then; SubExprs[ELSE] = elsev; - IfLoc = IL; - ElseLoc = EL; } /// \brief Build an empty if/then/else statement explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "if" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// if (int x = foo()) { + /// printf("x is %d", x); + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } const Stmt *getThen() const { return SubExprs[THEN]; } @@ -658,6 +680,7 @@ public: class SwitchStmt : public Stmt { enum { COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; + VarDecl *Var; // This points to a linked list of case and default statements. SwitchCase *FirstCase; SourceLocation SwitchLoc; @@ -666,14 +689,28 @@ protected: virtual void DoDestroy(ASTContext &Ctx); public: - SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); - SubExprs[BODY] = NULL; - } + SwitchStmt(VarDecl *Var, Expr *cond) + : Stmt(SwitchStmtClass), Var(Var), FirstCase(0) + { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = NULL; + } /// \brief Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} const Stmt *getBody() const { return SubExprs[BODY]; } const SwitchCase *getSwitchCaseList() const { return FirstCase; } @@ -721,10 +758,13 @@ public: /// class WhileStmt : public Stmt { enum { COND, BODY, END_EXPR }; + VarDecl *Var; Stmt* SubExprs[END_EXPR]; SourceLocation WhileLoc; public: - WhileStmt(Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) { + WhileStmt(VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) + : Stmt(WhileStmtClass), Var(Var) + { SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[BODY] = body; WhileLoc = WL; @@ -733,6 +773,17 @@ public: /// \brief Build an empty while statement. explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "while" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// while (int x = random()) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } @@ -812,26 +863,38 @@ public: class ForStmt : public Stmt { enum { INIT, COND, INC, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + VarDecl *CondVar; SourceLocation ForLoc; SourceLocation LParenLoc, RParenLoc; public: - ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL, - SourceLocation LP, SourceLocation RP) - : Stmt(ForStmtClass) { + ForStmt(Stmt *Init, Expr *Cond, VarDecl *CondVar, Expr *Inc, Stmt *Body, + SourceLocation FL, SourceLocation LP, SourceLocation RP) + : Stmt(ForStmtClass), CondVar(CondVar), ForLoc(FL), LParenLoc(LP), + RParenLoc(RP) + { SubExprs[INIT] = Init; SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); SubExprs[BODY] = Body; - ForLoc = FL; - LParenLoc = LP; - RParenLoc = RP; } /// \brief Build an empty for statement. explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } Stmt *getInit() { return SubExprs[INIT]; } + + /// \brief Retrieve the variable declared in this "for" statement, if any. + /// + /// In the following example, "y" is the condition variable. + /// \code + /// for (int x = random(); int y = mangle(x); ++x) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return CondVar; } + void setConditionVariable(VarDecl *V) { CondVar = V; } + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); } Stmt *getBody() { return SubExprs[BODY]; } diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 28fe348c4591..64eea2429c5d 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -42,9 +42,9 @@ public: } SourceLocation getCatchLoc() const { return CatchLoc; } - VarDecl *getExceptionDecl() { return ExceptionDecl; } - QualType getCaughtType(); - Stmt *getHandlerBlock() { return HandlerBlock; } + VarDecl *getExceptionDecl() const { return ExceptionDecl; } + QualType getCaughtType() const; + Stmt *getHandlerBlock() const { return HandlerBlock; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXCatchStmtClass; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 034029a16971..7102336180cf 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -121,20 +121,19 @@ EXPR(CXXThisExpr , Expr) EXPR(CXXThrowExpr , Expr) EXPR(CXXDefaultArgExpr , Expr) EXPR(CXXZeroInitValueExpr , Expr) -EXPR(CXXConditionDeclExpr , DeclRefExpr) EXPR(CXXNewExpr , Expr) EXPR(CXXDeleteExpr , Expr) EXPR(CXXPseudoDestructorExpr, Expr) -EXPR(UnresolvedFunctionNameExpr , Expr) +EXPR(UnresolvedLookupExpr , Expr) EXPR(UnaryTypeTraitExpr , Expr) -EXPR(UnresolvedDeclRefExpr , Expr) -EXPR(TemplateIdRefExpr , Expr) +EXPR(DependentScopeDeclRefExpr , Expr) EXPR(CXXConstructExpr , Expr) EXPR(CXXBindTemporaryExpr , Expr) EXPR(CXXExprWithTemporaries , Expr) EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) EXPR(CXXUnresolvedConstructExpr, Expr) -EXPR(CXXUnresolvedMemberExpr, Expr) +EXPR(CXXDependentScopeMemberExpr, Expr) +EXPR(UnresolvedMemberExpr , Expr) // Obj-C Expressions. EXPR(ObjCStringLiteral , Expr) diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 6db095872b0e..b46b3dc5d2d2 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" #include "clang/AST/Type.h" #include "clang/AST/TemplateName.h" @@ -437,6 +438,41 @@ public: } }; +/// A convenient class for passing around template argument +/// information. Designed to be passed by reference. +class TemplateArgumentListInfo { + llvm::SmallVector<TemplateArgumentLoc, 8> Arguments; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + +public: + TemplateArgumentListInfo() {} + + TemplateArgumentListInfo(SourceLocation LAngleLoc, + SourceLocation RAngleLoc) + : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; } + void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; } + + unsigned size() const { return Arguments.size(); } + + const TemplateArgumentLoc *getArgumentArray() const { + return Arguments.data(); + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return Arguments[I]; + } + + void addArgument(const TemplateArgumentLoc &Loc) { + Arguments.push_back(Loc); + } +}; + } #endif diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index c28bafe9a30f..349487f8794b 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -82,6 +82,7 @@ namespace clang { class StmtIteratorBase; class TemplateArgument; class TemplateArgumentLoc; + class TemplateArgumentListInfo; class QualifiedNameType; struct PrintingPolicy; @@ -859,6 +860,7 @@ public: bool isObjCQualifiedClassType() const; // Class<foo> bool isObjCIdType() const; // id bool isObjCClassType() const; // Class + bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t @@ -1000,7 +1002,8 @@ public: UndeducedAuto, // In C++0x, this represents the type of an auto variable // that has not been deduced yet. ObjCId, // This represents the ObjC 'id' type. - ObjCClass // This represents the ObjC 'Class' type. + ObjCClass, // This represents the ObjC 'Class' type. + ObjCSel // This represents the ObjC 'SEL' type. }; private: Kind TypeKind; @@ -1457,21 +1460,27 @@ public: /// DependentSizedArrayType - This type represents an array type in /// C++ whose size is a value-dependent expression. For example: -/// @code +/// +/// \code /// template<typename T, int Size> /// class array { /// T data[Size]; /// }; -/// @endcode +/// \endcode +/// /// For these types, we won't actually know what the array bound is /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { ASTContext &Context; - /// SizeExpr - An assignment expression that will instantiate to the + /// \brief An assignment expression that will instantiate to the /// size of the array. + /// + /// The expression itself might be NULL, in which case the array + /// type will have its size deduced from an initializer. Stmt *SizeExpr; + /// Brackets - The left and right array brackets. SourceRange Brackets; @@ -2272,6 +2281,8 @@ public: static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); + static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &); + /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. static std::string PrintTemplateArgumentList(const TemplateArgument *Args, @@ -2282,6 +2293,9 @@ public: unsigned NumArgs, const PrintingPolicy &Policy); + static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &, + const PrintingPolicy &Policy); + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } @@ -2534,6 +2548,7 @@ public: return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && !Protocols.size(); } + /// isObjCQualifiedIdType - true for "id <p>". bool isObjCQualifiedIdType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && @@ -2881,8 +2896,13 @@ inline bool Type::isObjCClassType() const { return OPT->isObjCClassType(); return false; } +inline bool Type::isObjCSelType() const { + if (const PointerType *OPT = getAs<PointerType>()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} inline bool Type::isObjCBuiltinType() const { - return isObjCIdType() || isObjCClassType(); + return isObjCIdType() || isObjCClassType() || isObjCSelType(); } inline bool Type::isTemplateTypeParmType() const { return isa<TemplateTypeParmType>(CanonicalType); diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 867494396020..0077a8505170 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -23,6 +23,7 @@ namespace clang { class Stmt; class DeclRefExpr; class SourceManager; +class AnalysisContext; struct LiveVariables_ValueTypes { @@ -39,8 +40,9 @@ struct LiveVariables_ValueTypes { struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { ObserverTy* Observer; ValTy AlwaysLive; + AnalysisContext *AC; - AnalysisDataTy() : Observer(NULL) {} + AnalysisDataTy() : Observer(NULL), AC(NULL) {} }; //===-----------------------------------------------------===// @@ -66,7 +68,7 @@ class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, public: typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; - LiveVariables(ASTContext& Ctx, CFG& cfg); + LiveVariables(AnalysisContext &AC); /// IsLive - Return true if a variable is live at beginning of a /// specified block. diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h index efc66776d7ca..cad702cbdb2e 100644 --- a/include/clang/Analysis/PathDiagnostic.h +++ b/include/clang/Analysis/PathDiagnostic.h @@ -14,31 +14,24 @@ #ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H #define LLVM_CLANG_PATH_DIAGNOSTIC_H -#include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" - -#include <vector> #include <deque> +#include <iterator> #include <string> -#include <algorithm> +#include <vector> namespace clang { - -class Stmt; + class Decl; -class Preprocessor; - +class SourceManager; +class Stmt; + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// class PathDiagnostic; - -class Stmt; -class Decl; -class Preprocessor; class PathDiagnosticClient : public DiagnosticClient { public: diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 9b58f745f0a5..8b1a329c0335 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -19,6 +19,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" namespace clang { @@ -38,17 +39,26 @@ class AnalysisContext { CFG *cfg; LiveVariables *liveness; ParentMap *PM; - + llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; + llvm::BumpPtrAllocator A; public: - AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {} + AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0), + ReferencedBlockVars(0) {} + ~AnalysisContext(); + ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() { return D; } Stmt *getBody(); CFG *getCFG(); ParentMap &getParentMap(); LiveVariables *getLiveVariables(); + typedef const VarDecl * const * referenced_decls_iterator; + + std::pair<referenced_decls_iterator, referenced_decls_iterator> + getReferencedBlockVars(const BlockDecl *BD); + /// Return the ImplicitParamDecl* associated with 'self' if this /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. const ImplicitParamDecl *getSelfDecl() const; diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index f4297350ec70..58c80185435d 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -309,32 +309,33 @@ public: void EmitReport(BugReport *R); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange R) { EmitBasicReport(BugName, BugStr, Loc, &R, 1); } - void EmitBasicReport(const char* BugName, const char* Category, - const char* BugStr, SourceLocation Loc, SourceRange R) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category, + llvm::StringRef BugStr, SourceLocation Loc, + SourceRange R) { EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); } @@ -432,7 +433,7 @@ class DiagBugReport : public RangedBugReport { std::list<std::string> Strs; FullSourceLoc L; public: - DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) : RangedBugReport(D, desc, 0), L(l) {} virtual ~DiagBugReport() {} diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h index 8303dee49afa..4f1523a5440d 100644 --- a/include/clang/Analysis/PathSensitive/BugType.h +++ b/include/clang/Analysis/PathSensitive/BugType.h @@ -34,13 +34,13 @@ private: friend class BugReporter; bool SuppressonSink; public: - BugType(const char *name, const char* cat) + BugType(llvm::StringRef name, llvm::StringRef cat) : Name(name), Category(cat), SuppressonSink(false) {} virtual ~BugType(); // FIXME: Should these be made strings as well? - const std::string& getName() const { return Name; } - const std::string& getCategory() const { return Category; } + llvm::StringRef getName() const { return Name; } + llvm::StringRef getCategory() const { return Category; } /// isSuppressOnSink - Returns true if bug reports associated with this bug /// type should be suppressed if the end node of the report is post-dominated @@ -60,33 +60,15 @@ public: }; class BuiltinBug : public BugType { - GRExprEngine *Eng; -protected: const std::string desc; public: BuiltinBug(const char *name, const char *description) - : BugType(name, "Logic error"), Eng(0), desc(description) {} + : BugType(name, "Logic error"), desc(description) {} BuiltinBug(const char *name) - : BugType(name, "Logic error"), Eng(0), desc(name) {} + : BugType(name, "Logic error"), desc(name) {} - BuiltinBug(GRExprEngine *eng, const char* n, const char* d) - : BugType(n, "Logic error"), Eng(eng), desc(d) {} - - BuiltinBug(GRExprEngine *eng, const char* n) - : BugType(n, "Logic error"), Eng(eng), desc(n) {} - - const std::string &getDescription() const { return desc; } - - virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {} - - void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, *Eng); } - - virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) {} - - template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E); + llvm::StringRef getDescription() const { return desc; } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index b7ed20fab250..91a4b6d1b1eb 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -40,24 +40,35 @@ class CheckerContext { SaveAndRestore<ProgramPoint::Kind> OldPointKind; SaveOr OldHasGen; const GRState *state; - + const Stmt *statement; + const unsigned size; + bool DoneEvaluating; // FIXME: This is not a permanent API change. public: CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, GRExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, - const GRState *st = 0) + const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), OldSink(B.BuildSinks), OldTag(B.Tag, tag), OldPointKind(B.PointKind, K), OldHasGen(B.HasGeneratedNode), - state(st) {} + state(st), statement(stmt), size(Dst.size()), + DoneEvaluating(false) {} - ~CheckerContext() { - if (!B.BuildSinks && !B.HasGeneratedNode) - Dst.Add(Pred); + ~CheckerContext(); + + // FIXME: This were added to support CallAndMessageChecker to indicating + // to GRExprEngine to "stop evaluating" a message expression under certain + // cases. This is *not* meant to be a permanent API change, and was added + // to aid in the transition of removing logic for checks from GRExprEngine. + void setDoneEvaluating() { + DoneEvaluating = true; } - + bool isDoneEvaluating() const { + return DoneEvaluating; + } + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } @@ -83,27 +94,70 @@ public: return getBugReporter().getSourceManager(); } - ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { - return GenerateNode(S, getState(), markAsSink); + ValueManager &getValueManager() { + return Eng.getValueManager(); } - ExplodedNode *GenerateNode(const Stmt* S, const GRState *state, - bool markAsSink = false) { - ExplodedNode *node = B.generateNode(S, state, Pred); + ExplodedNode *GenerateNode(bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); + if (N && autoTransition) + Dst.Add(N); + return N; + } + + ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, + bool autoTransition = true) { + assert(state); + ExplodedNode *N = GenerateNodeImpl(stmt, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - if (markAsSink && node) - node->markAsSink(); + ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - return node; + ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { + return GenerateNodeImpl(stmt, state ? state : getState(), true); + } + + ExplodedNode *GenerateSink(const GRState *state = 0) { + assert(statement && "Only transitions with statements currently supported"); + return GenerateNodeImpl(statement, state ? state : getState(), true); } void addTransition(ExplodedNode *node) { Dst.Add(node); } + + void addTransition(const GRState *state) { + assert(state); + if (state != getState() || + (state && state != B.GetState(Pred))) + GenerateNode(state, true); + else + Dst.Add(Pred); + } void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } + +private: + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, Pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } + }; class Checker { @@ -111,18 +165,19 @@ private: friend class GRExprEngine; // FIXME: Remove the 'tag' option. - void GR_Visit(ExplodedNodeSet &Dst, + bool GR_Visit(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, void *tag, bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, S); if (isPrevisit) _PreVisit(C, S); else _PostVisit(C, S); + return C.isDoneEvaluating(); } // FIXME: Remove the 'tag' option. @@ -134,7 +189,7 @@ private: bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, StoreE); assert(isPrevisit && "Only previsit supported for now."); PreVisitBind(C, AssignE, StoreE, location, val); } @@ -149,7 +204,7 @@ private: void *tag, bool isLoad) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, state); + ProgramPoint::PreStoreKind, S, state); VisitLocation(C, S, location); } @@ -157,12 +212,12 @@ private: GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, Pred->getState()); + ProgramPoint::PostPurgeDeadSymbolsKind, S); EvalDeadSymbols(C, S, SymReaper); } public: - virtual ~Checker() {} + virtual ~Checker(); virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} @@ -172,6 +227,10 @@ public: SymbolReaper &SymReaper) {} virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) {} + + virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, + GRExprEngine &Eng, + Stmt *Condition, void *tag) {} }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def index 090a5d397549..4144d1a0a734 100644 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.def +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def @@ -11,7 +11,14 @@ // //===---------------------------------------------------------------------===// -#ifdef PREVISIT +#ifndef PREVISIT +#define PREVISIT(NODE) +#endif + +#ifndef POSTVISIT +#define POSTVISIT(NODE) +#endif + PREVISIT(ArraySubscriptExpr) PREVISIT(BinaryOperator) PREVISIT(CallExpr) @@ -19,11 +26,10 @@ PREVISIT(CastExpr) PREVISIT(DeclStmt) PREVISIT(ObjCMessageExpr) PREVISIT(ReturnStmt) -#undef PREVISIT -#endif -#ifdef POSTVISIT POSTVISIT(CallExpr) -#undef POSTVISIT -#endif +POSTVISIT(BlockExpr) +POSTVISIT(BinaryOperator) +#undef PREVISIT +#undef POSTVISIT diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h deleted file mode 100644 index 13437eb2ac03..000000000000 --- a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h +++ /dev/null @@ -1,33 +0,0 @@ -//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that -// checks for assigning undefined values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_UNDEFASSIGNMENTCHECKER -#define LLVM_CLANG_UNDEFASSIGNMENTCHECKER - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" - -namespace clang { -class UndefinedAssignmentChecker - : public CheckerVisitor<UndefinedAssignmentChecker> { - BugType *BT; -public: - UndefinedAssignmentChecker() : BT(0) {} - static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); -}; -} -#endif - diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index a7bbdf939f87..76cab1ddc127 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -352,10 +352,16 @@ public: typedef ImplTy::iterator iterator; typedef ImplTy::const_iterator const_iterator; - inline unsigned size() const { return Impl.size(); } - inline bool empty() const { return Impl.empty(); } - - inline void clear() { Impl.clear(); } + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } inline iterator begin() { return Impl.begin(); } inline iterator end() { return Impl.end(); } diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index 02e0b0275e4e..b78cc6adfc4a 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -215,7 +215,7 @@ public: void setAuditor(GRAuditor* A) { Auditor = A; } const GRState* GetState(ExplodedNode* Pred) const { - if ((ExplodedNode*) Pred == getBasePredecessor()) + if (Pred == getBasePredecessor()) return CleanedState; else return Pred->getState(); @@ -405,6 +405,8 @@ class GREndPathNodeBuilder { GRCoreEngine& Eng; CFGBlock& B; ExplodedNode* Pred; + +public: bool HasGeneratedNode; public: diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 1b6d0bdf9c10..a7302c0602ec 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -88,55 +88,6 @@ class GRExprEngine : public GRSubEngine { GRBugReporter BR; public: - typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes; - typedef llvm::DenseMap<ExplodedNode*, Expr*> UndefArgsTy; - - /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' definitely being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetExplicit; - - /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' possibly being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetImplicit; - - /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' definitely being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; - - /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' possibly being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; - - /// UndefBranches - Nodes in the ExplodedGraph that result from - /// taking a branch based on an undefined value. - ErrorNodes UndefBranches; - - /// UndefStores - Sinks in the ExplodedGraph that result from - /// making a store to an undefined lvalue. - ErrorNodes UndefStores; - - /// NoReturnCalls - Sinks in the ExplodedGraph that result from - // calling a function with the attribute "noreturn". - ErrorNodes NoReturnCalls; - - /// UndefResults - Nodes in the ExplodedGraph where the operands are defined - /// by the result is not. Excludes divide-by-zero errors. - ErrorNodes UndefResults; - - /// UndefReceiver - Nodes in the ExplodedGraph resulting from message - /// ObjC message expressions where the receiver is undefined (uninitialized). - ErrorNodes UndefReceivers; - - /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from - /// message expressions where a pass-by-value argument has an undefined - /// value. - UndefArgsTy MsgExprUndefArgs; - -public: GRExprEngine(AnalysisManager &mgr); ~GRExprEngine(); @@ -178,8 +129,6 @@ public: ExplodedGraph& getGraph() { return G; } const ExplodedGraph& getGraph() const { return G; } - void RegisterInternalChecks(); - template <typename CHECKER> void registerCheck(CHECKER *check) { unsigned entry = Checkers.size(); @@ -195,58 +144,6 @@ public: return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag())); } - bool isNoReturnCall(const ExplodedNode* N) const { - return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0; - } - - typedef ErrorNodes::iterator undef_branch_iterator; - undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } - undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } - - typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { - return NilReceiverStructRetExplicit.begin(); - } - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { - return NilReceiverStructRetExplicit.end(); - } - - typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_begin() { - return NilReceiverLargerThanVoidPtrRetExplicit.begin(); - } - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_end() { - return NilReceiverLargerThanVoidPtrRetExplicit.end(); - } - - typedef ErrorNodes::iterator undef_result_iterator; - undef_result_iterator undef_results_begin() { return UndefResults.begin(); } - undef_result_iterator undef_results_end() { return UndefResults.end(); } - - typedef UndefArgsTy::iterator undef_arg_iterator; - undef_arg_iterator msg_expr_undef_arg_begin() { - return MsgExprUndefArgs.begin(); - } - undef_arg_iterator msg_expr_undef_arg_end() { - return MsgExprUndefArgs.end(); - } - - typedef ErrorNodes::iterator undef_receivers_iterator; - - undef_receivers_iterator undef_receivers_begin() { - return UndefReceivers.begin(); - } - - undef_receivers_iterator undef_receivers_end() { - return UndefReceivers.end(); - } - void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); void AddCheck(GRSimpleAPICheck* A); @@ -312,7 +209,7 @@ public: protected: /// CheckerVisit - Dispatcher for performing checker-specific logic /// at specific statements. - void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + bool CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, @@ -345,6 +242,9 @@ protected: AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, @@ -361,33 +261,38 @@ protected: unsigned ParamIdx = 0); /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, + ExplodedNodeSet& Dst); - void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue); + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitObjCForCollectionStmt - Transfer function logic for /// ObjCForCollectionStmt. diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index ef0c36c44d9f..d8bc2411750f 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -33,7 +33,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include <functional> @@ -264,8 +263,21 @@ public: const llvm::APSInt *getSymVal(SymbolRef sym); bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; template <typename CB> CB scanReachableSymbols(SVal val) const; + template <typename CB> CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template <typename CB> CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). @@ -726,7 +738,21 @@ CB GRState::scanReachableSymbols(SVal val) const { scanReachableSymbols(val, cb); return cb; } + +template <typename CB> +CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} +template <typename CB> +CB GRState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 06d0d976df01..ed964978a44a 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -35,6 +35,7 @@ namespace clang { class MemRegionManager; class MemSpaceRegion; class LocationContext; +class VarRegion; //===----------------------------------------------------------------------===// // Base region classes. @@ -42,13 +43,16 @@ class LocationContext; /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; public: enum Kind { MemSpaceRegionKind, SymbolicRegionKind, AllocaRegionKind, // Typed regions. BEG_TYPED_REGIONS, - CodeTextRegionKind, + FunctionTextRegionKind, + BlockTextRegionKind, + BlockDataRegionKind, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, // Decl Regions. @@ -237,45 +241,123 @@ public: } }; -/// CodeTextRegion - A region that represents code texts of a function. It wraps -/// two kinds of code texts: real function and symbolic function. Real function -/// is a function declared in the program. Symbolic function is a function -/// pointer that we don't know which function it points to. -class CodeTextRegion : public TypedRegion { - const FunctionDecl *FD; +class CodeTextRegion : public TypedRegion { +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} public: - - CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg) - : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {} - QualType getValueType(ASTContext &C) const { // Do not get the object type of a CodeTextRegion. assert(0); return QualType(); } + + bool isBoundable() const { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const FunctionDecl *FD; +public: + FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} + QualType getLocationType(ASTContext &C) const { return C.getPointerType(FD->getType()); } - + const FunctionDecl *getDecl() const { return FD; } - - bool isBoundable() const { return false; } - + virtual void dumpToStream(llvm::raw_ostream& os) const; - + void Profile(llvm::FoldingSetNodeID& ID) const; - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, const MemRegion*); - + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + const BlockDecl *BD; + CanQualType locTy; +public: + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), locTy(lTy) {} + + QualType getLocationType(ASTContext &C) const { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const MemRegion*); + static bool classof(const MemRegion* R) { - return R->getKind() == CodeTextRegionKind; + return R->getKind() == BlockTextRegionKind; } }; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +/// BlockDataRegion - A region that represents code texts of blocks (closures). +class BlockDataRegion : public SubRegion { + const BlockTextRegion *BC; + const LocationContext *LC; + void *ReferencedVars; +public: + BlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc, + const MemRegion *sreg) + : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} + + const BlockTextRegion *getCodeRegion() const { return BC; } + + typedef const MemRegion * const * referenced_vars_iterator; + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockTextRegion *BC, + const LocationContext *LC, const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); +}; /// SymbolicRegion - A special, "non-concrete" region. Unlike other region /// clases, SymbolicRegion represents a region that serves as an alias for @@ -577,9 +659,11 @@ public: : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), unknown(0), code(0) {} - ~MemRegionManager() {} + ~MemRegionManager(); ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } /// getStackRegion - Retrieve the memory region associated with the /// current stack frame. @@ -656,7 +740,10 @@ public: ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD); + FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy); + BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc); template <typename RegionTy, typename A1> RegionTy* getRegion(const A1 a1); @@ -667,6 +754,10 @@ public: template <typename RegionTy, typename A1, typename A2> RegionTy* getRegion(const A1 a1, const A2 a2); + template <typename RegionTy, typename A1, typename A2> + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + bool isGlobalsRegion(const MemRegion* R) { assert(R); return R == globals; @@ -745,6 +836,25 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { return R; } + +template <typename RegionTy, typename A1, typename A2> +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} //===----------------------------------------------------------------------===// // Traits for constructing regions. @@ -801,18 +911,21 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> { } }; -template<> struct MemRegionManagerTrait<CodeTextRegion> { +template<> struct MemRegionManagerTrait<FunctionTextRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, const FunctionDecl*) { return MRMgr.getCodeRegion(); } +}; +template<> struct MemRegionManagerTrait<BlockTextRegion> { + typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - SymbolRef, QualType) { + const BlockDecl*, CanQualType) { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index 8d162a681c44..ef4e069ce8e8 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -114,6 +114,9 @@ public: const TypedRegion *R); DefinedSVal getFunctionPointer(const FunctionDecl *FD); + + DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, + const LocationContext *LC); NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 2af95808b281..bbf42ee8c7fe 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -250,8 +250,8 @@ BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") -BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "") -BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "") +BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLic", "") +BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLic", "") BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index e2f11041dce2..3f7d114dda60 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -57,6 +57,9 @@ def err_drv_invalid_mfloat_abi : Error< "invalid float ABI '%0'">; def err_drv_I_dash_not_supported : Error< "'%0' not supported, please use -iquote instead">; +def err_drv_unknown_argument : Error<"unknown argument: '%0'">; +def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; +def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index e9b351ffe995..cbc287c58c89 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -17,6 +17,8 @@ def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; def err_fe_invalid_code_complete_file : Error<"cannot locate code-completion file %0">, DefaultFatal; +def err_fe_stdout_binary : Error<"unable to change standard output to binary">, + DefaultFatal; def err_fe_dependency_file_requires_MT : Error< "-dependency-file requires at least one -MT option">; def err_fe_incompatible_options : Error< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 93c655b50500..c1c833cf5c66 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -78,16 +78,19 @@ def : DiagGroup<"synth">; // Preprocessor warnings. def : DiagGroup<"builtin-macro-redefined">; -// Just silence warnings about common forms of -Wstrict-aliasing for now. +// Just silence warnings about -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; def : DiagGroup<"strict-aliasing=1">; def : DiagGroup<"strict-aliasing=2">; def : DiagGroup<"strict-aliasing">; -// Just silence warnings about common forms of -Wstrict-aliasing for now. +// Just silence warnings about -Wstrict-overflow for now. def : DiagGroup<"strict-overflow=0">; def : DiagGroup<"strict-overflow=1">; def : DiagGroup<"strict-overflow=2">; +def : DiagGroup<"strict-overflow=3">; +def : DiagGroup<"strict-overflow=4">; +def : DiagGroup<"strict-overflow=5">; def : DiagGroup<"strict-overflow">; def InvalidOffsetof : DiagGroup<"invalid-offsetof">; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 7f3f4ea1fca0..39123d9b371a 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -170,6 +170,8 @@ def ext_pp_counter : Extension< def err_pp_invalid_directive : Error<"invalid preprocessing directive">; def err_pp_hash_error : Error<"#error%0">; def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def err_pp_error_opening_file : Error< + "error opening file '%0'">, DefaultFatal; def err_pp_empty_filename : Error<"empty filename">; def err_pp_include_too_deep : Error<"#include nested too deeply">; def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 3a8c5bf8f1b8..43107044720e 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -44,7 +44,8 @@ def ext_c99_variable_decl_in_for_loop : Extension< def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">; def ext_enumerator_list_comma : Extension< - "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific feature">; + "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific " + "feature">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">; @@ -75,6 +76,7 @@ def err_expected_ident_lbrace : Error<"expected identifier or '{'">; def err_expected_lbrace : Error<"expected '{'">; def err_expected_lparen : Error<"expected '('">; def err_expected_rparen : Error<"expected ')'">; +def err_expected_lsquare : Error<"expected '['">; def err_expected_rsquare : Error<"expected ']'">; def err_expected_rbrace : Error<"expected '}'">; def err_expected_greater : Error<"expected '>'">; @@ -240,11 +242,18 @@ def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading def err_operator_missing_type_specifier : Error< "missing type specifier after 'operator'">; +def err_operator_string_not_empty : Error< + "string literal after 'operator' must be '\"\"'">; // Classes. def err_anon_type_definition : Error< "declaration of anonymous %0 must be a definition">; +def err_cxx0x_attribute_forbids_arguments : Error< + "C++0x attribute '%0' cannot have an argument list">; +def err_cxx0x_attribute_requires_arguments : Error< + "C++0x attribute '%0' must have an argument list">; +def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; /// C++ Templates def err_expected_template : Error<"expected template">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a864d8ab9e72..a0e03fed1600 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -443,8 +443,9 @@ def err_implicit_object_parameter_init : Error< def note_field_decl : Note<"member is declared here">; def note_previous_class_decl : Note< "%0 declared here">; -def note_ctor_synthesized_at : Note< - "implicit default constructor for %0 first required here">; +def note_member_synthesized_at : Note< + "implicit default %select{constructor|copy constructor|" + "copy assignment operator|destructor}0 for %1 first required here">; def err_missing_default_ctor : Error< "%select{|implicit default }0constructor for %1 must explicitly initialize " "the %select{base class|member}2 %3 which does not have a default " @@ -552,6 +553,15 @@ def err_auto_not_allowed : Error< def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; +// C++0x attributes +def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; + +// C++0x [[final]] +def err_final_function_overridden : Error< + "declaration of %0 overrides a 'final' function">; +def err_final_base : Error< + "derivation from 'final' %0">; + // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< "Objective-C declarations may only appear in global scope">; @@ -638,8 +648,16 @@ def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|parameter or Objective-C method |" - "function, method or block}1 types">; + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}1 types">; +def err_attribute_wrong_decl_type : Error< + "%0 attribute only applies to %select{function|union|" + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}1 types">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; @@ -865,7 +883,7 @@ def err_addr_ovl_ambiguous : Error< def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def note_template_param_here : Note<"template parameter is declared here">; -def note_template_export_unsupported : Note< +def warn_template_export_unsupported : Warning< "exported templates are unsupported">; def err_template_outside_namespace_or_class_scope : Error< "templates can only be declared in namespace or class scope">; @@ -902,7 +920,15 @@ def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; - +def err_template_parameter_default_in_function_template : Error< + "a template parameter of a function template cannot have a default argument " + "in C++98">; +def err_template_parameter_default_template_member : Error< + "cannot add a default template argument to the definition of a member of a " + "class template">; +def err_template_parameter_default_friend_template : Error< + "default template argument not permitted on a friend template">; + def err_template_variable : Error<"variable %0 declared as a template">; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; @@ -1037,6 +1063,11 @@ def err_template_param_list_matches_nontemplate : Error< def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; +def warn_template_spec_extra_headers : Warning< + "extraneous template parameter list in template specialization">; +def note_explicit_template_spec_does_not_need_header : Note< + "'template<>' header not required for explicitly-specialized class %0 " + "declared here">; def err_template_qualified_declarator_no_match : Error< "nested name specifier '%0' for declaration does not refer into a class, " "class template or class template partial specialization">; @@ -1197,6 +1228,10 @@ def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; def err_template_kw_refers_to_function_template : Error< "%0 following the 'template' keyword refers to a function template">; +def err_template_kw_refers_to_class_template : Error< + "'%0%1' instantiated to a class template, not a function template">; +def note_referenced_class_template : Error< + "class template declared here">; // C++0x Variadic Templates def err_template_param_pack_default_arg : Error< @@ -2050,6 +2085,8 @@ def err_base_init_direct_and_virtual : Error< "inherited virtual base class">; def err_not_direct_base_or_virtual : Error< "type %0 is not a direct or virtual base of '%1'">; +def err_not_direct_base_or_virtual_multi : Error< + "type %0 is not a direct or virtual base of '%1'">; def err_in_class_initializer_non_integral_type : Error< "in-class initializer has non-integral, non-enumeration type %0">; @@ -2275,6 +2312,15 @@ def err_typecheck_statement_requires_integer : Error< "statement requires expression of integer type (%0 invalid)">; def err_multiple_default_labels_defined : Error< "multiple default labels in one switch">; +def err_switch_multiple_conversions : Error< + "multiple conversions from switch condition type %0 to an integral or " + "enumeration type">; +def note_switch_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1">; +def err_switch_explicit_conversion : Error< + "switch condition type %0 requires explicit conversion to %1">; +def err_switch_incomplete_class_type : Error< + "switch condition has incomplete class type %0">; def warn_empty_if_body : Warning< "if statement has empty body">, InGroup<EmptyBody>; def err_va_start_used_in_non_variadic_function : Error< diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index e06dfbb2cf1b..53939500e72a 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -496,6 +496,7 @@ public: #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ CXXOperator##Name, #include "clang/Basic/OperatorKinds.def" + CXXLiteralOperator, CXXUsingDirective, NUM_EXTRA_KINDS }; @@ -503,10 +504,10 @@ public: /// ExtraKindOrNumArgs - Either the kind of C++ special name or /// operator-id (if the value is one of the CXX* enumerators of /// ExtraKind), in which case the DeclarationNameExtra is also a - /// CXXSpecialName (for CXXConstructor, CXXDestructor, or - /// CXXConversionFunction) or CXXOperatorIdName, it may be also - /// name common to C++ using-directives (CXXUsingDirective), otherwise - /// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// CXXSpecialName, (for CXXConstructor, CXXDestructor, or + /// CXXConversionFunction) CXXOperatorIdName, or CXXLiteralOperatorName, + /// it may be also name common to C++ using-directives (CXXUsingDirective), + /// otherwise it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of /// arguments in the Objective-C selector, in which case the /// DeclarationNameExtra is also a MultiKeywordSelector. unsigned ExtraKindOrNumArgs; diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 99c100d55e7e..a16a27103b67 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_LANGOPTIONS_H #define LLVM_CLANG_LANGOPTIONS_H +#include <string> + namespace clang { /// LangOptions - This class keeps track of the various options that can be @@ -101,15 +103,10 @@ private: // on making enums signed. Set/Query this // value using accessors. - /// The user provided name for the "main file", if non-null. This is - /// useful in situations where the input file name does not match - /// the original input file, for example with -save-temps. - const char *MainFileName; - public: unsigned InstantiationDepth; // Maximum template instantiation depth. - const char *ObjCConstantStringClass; + std::string ObjCConstantStringClass; enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPReq }; @@ -124,7 +121,6 @@ public: GNUMode = ImplicitInt = Digraphs = 0; HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0; - ObjCConstantStringClass = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = 0; Exceptions = Freestanding = NoBuiltin = 0; @@ -164,8 +160,6 @@ public: CharIsSigned = 1; ShortWChar = 0; - - MainFileName = 0; } GCMode getGCMode() const { return (GCMode) GC; } @@ -178,9 +172,6 @@ public: StackProtector = static_cast<unsigned>(m); } - const char *getMainFileName() const { return MainFileName; } - void setMainFileName(const char *Name) { MainFileName = Name; } - VisibilityMode getVisibilityMode() const { return (VisibilityMode) SymbolVisibility; } diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 6b60f2eec097..9b50e8df02b9 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include "llvm/System/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 695f51d2c4c9..49eaafec7db7 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -80,7 +80,7 @@ public: }; protected: IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, - WIntType, Char16Type, Char32Type, Int64Type; + WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType; public: IntType getSizeType() const { return SizeType; } IntType getIntMaxType() const { return IntMaxType; } @@ -94,6 +94,7 @@ public: IntType getChar16Type() const { return Char16Type; } IntType getChar32Type() const { return Char32Type; } IntType getInt64Type() const { return Int64Type; } + IntType getSigAtomicType() const { return SigAtomicType; } /// getTypeWidth - Return the width (in bits) of the specified integer type diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 239712c08caf..99422332a788 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -17,6 +17,9 @@ #ifndef TOK #define TOK(X) #endif +#ifndef PUNCTUATOR +#define PUNCTUATOR(X,Y) TOK(X) +#endif #ifndef KEYWORD #define KEYWORD(X,Y) TOK(kw_ ## X) #endif @@ -113,64 +116,63 @@ TOK(wide_string_literal) // L"foo" TOK(angle_string_literal)// <foo> // C99 6.4.6: Punctuators. -TOK(l_square) // [ -TOK(r_square) // ] -TOK(l_paren) // ( -TOK(r_paren) // ) -TOK(l_brace) // { -TOK(r_brace) // } -TOK(period) // . -TOK(ellipsis) // ... -TOK(amp) // & -TOK(ampamp) // && -TOK(ampequal) // &= -TOK(star) // * -TOK(starequal) // *= -TOK(plus) // + -TOK(plusplus) // ++ -TOK(plusequal) // += -TOK(minus) // - -TOK(arrow) // -> -TOK(minusminus) // -- -TOK(minusequal) // -= -TOK(tilde) // ~ -TOK(exclaim) // ! -TOK(exclaimequal) // != -TOK(slash) // / -TOK(slashequal) // /= -TOK(percent) // % -TOK(percentequal) // %= -TOK(less) // < -TOK(lessless) // << -TOK(lessequal) // <= -TOK(lesslessequal) // <<= -TOK(greater) // > -TOK(greatergreater) // >> -TOK(greaterequal) // >= -TOK(greatergreaterequal) // >>= -TOK(caret) // ^ -TOK(caretequal) // ^= -TOK(pipe) // | -TOK(pipepipe) // || -TOK(pipeequal) // |= -TOK(question) // ? -TOK(colon) // : -TOK(semi) // ; -TOK(equal) // = -TOK(equalequal) // == -TOK(comma) // , -TOK(hash) // # -TOK(hashhash) // ## -TOK(hashat) // #@ +PUNCTUATOR(l_square, "[") +PUNCTUATOR(r_square, "]") +PUNCTUATOR(l_paren, "(") +PUNCTUATOR(r_paren, ")") +PUNCTUATOR(l_brace, "{") +PUNCTUATOR(r_brace, "}") +PUNCTUATOR(period, ".") +PUNCTUATOR(ellipsis, "...") +PUNCTUATOR(amp, "&") +PUNCTUATOR(ampamp, "&&") +PUNCTUATOR(ampequal, "&=") +PUNCTUATOR(star, "*") +PUNCTUATOR(starequal, "*=") +PUNCTUATOR(plus, "+") +PUNCTUATOR(plusplus, "++") +PUNCTUATOR(plusequal, "+=") +PUNCTUATOR(minus, "-") +PUNCTUATOR(arrow, "->") +PUNCTUATOR(minusminus, "--") +PUNCTUATOR(minusequal, "-=") +PUNCTUATOR(tilde, "~") +PUNCTUATOR(exclaim, "!") +PUNCTUATOR(exclaimequal, "!=") +PUNCTUATOR(slash, "/") +PUNCTUATOR(slashequal, "/=") +PUNCTUATOR(percent, "%") +PUNCTUATOR(percentequal, "%=") +PUNCTUATOR(less, "<") +PUNCTUATOR(lessless, "<<") +PUNCTUATOR(lessequal, "<=") +PUNCTUATOR(lesslessequal, "<<=") +PUNCTUATOR(greater, ">") +PUNCTUATOR(greatergreater, ">>") +PUNCTUATOR(greaterequal, ">=") +PUNCTUATOR(greatergreaterequal, ">>=") +PUNCTUATOR(caret, "^") +PUNCTUATOR(caretequal, "^=") +PUNCTUATOR(pipe, "|") +PUNCTUATOR(pipepipe, "||") +PUNCTUATOR(pipeequal, "|=") +PUNCTUATOR(question, "?") +PUNCTUATOR(colon, ":") +PUNCTUATOR(semi, ";") +PUNCTUATOR(equal, "=") +PUNCTUATOR(equalequal, "==") +PUNCTUATOR(comma, ",") +PUNCTUATOR(hash, "#") +PUNCTUATOR(hashhash, "##") +PUNCTUATOR(hashat, "#@") // C++ Support -TOK(periodstar) // .* -TOK(arrowstar) // ->* -TOK(coloncolon) // :: +PUNCTUATOR(periodstar, ".*") +PUNCTUATOR(arrowstar, "->*") +PUNCTUATOR(coloncolon, "::") // Objective C support. -TOK(at) // @ - +PUNCTUATOR(at, "@") // C99 6.4.1: Keywords. These turn into kw_* tokens. // Flags allowed: @@ -415,4 +417,5 @@ ANNOTATION(template_id) // annotation for a C++ template-id that names a #undef PPKEYWORD #undef ALIAS #undef KEYWORD +#undef PUNCTUATOR #undef TOK diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h index 02679cd99895..c8fb37b9ddc0 100644 --- a/include/clang/CodeGen/CodeGenOptions.h +++ b/include/clang/CodeGen/CodeGenOptions.h @@ -29,7 +29,9 @@ public: OnlyAlwaysInlining // Only run the always inlining pass. }; + unsigned AsmVerbose : 1; /// -dA, -fverbose-asm. unsigned DebugInfo : 1; /// Should generate deubg info (-g). + unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled. unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in /// getting .bc files that correspond to the /// internal state before optimizations are @@ -38,35 +40,63 @@ public: unsigned MergeAllConstants : 1; /// Merge identical constants. unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. + unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. - unsigned SimplifyLibCalls : 1; /// Should standard library calls be treated - /// specially. + unsigned SoftFloat : 1; /// -soft-float. unsigned TimePasses : 1; /// Set when -ftime-report is enabled. unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization /// selection. unsigned UnrollLoops : 1; /// Control whether loops are unrolled. + unsigned UnwindTables : 1; /// Emit unwind tables. unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. - /// Inlining - The kind of inlining to perform. + /// The code model to use (-mcmodel). + std::string CodeModel; + + /// Enable additional debugging information. + std::string DebugPass; + + /// The ABI to use for passing floating point arguments. + std::string FloatABI; + + /// The float precision limit to use, if non-empty. + std::string LimitFloatPrecision; + + /// The kind of inlining to perform. InliningMethod Inlining; + /// The user provided name for the "main file", if non-empty. This is useful + /// in situations where the input file name does not match the original input + /// file, for example with -save-temps. + std::string MainFileName; + + /// The name of the relocation model to use. + std::string RelocationModel; + public: CodeGenOptions() { + AsmVerbose = 0; + DebugInfo = 0; + DisableFPElim = 0; + DisableLLVMOpts = 0; + DisableRedZone = 0; + MergeAllConstants = 1; + NoCommon = 0; + NoImplicitFloat = 0; + NoZeroInitializedInBSS = 0; OptimizationLevel = 0; OptimizeSize = 0; - DebugInfo = 0; + UnrollLoops = 0; + SoftFloat = 0; + TimePasses = 0; UnitAtATime = 1; - SimplifyLibCalls = UnrollLoops = 0; + UnwindTables = 0; VerifyModule = 1; - TimePasses = 0; - NoCommon = 0; + Inlining = NoInlining; - DisableRedZone = 0; - NoImplicitFloat = 0; - MergeAllConstants = 1; - DisableLLVMOpts = 0; + RelocationModel = "pic"; } }; diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index 5263108d1a6d..ab1abff7409b 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -25,8 +25,67 @@ namespace llvm { namespace clang { namespace driver { class Arg; + class ArgList; class Option; + /// arg_iterator - Iterates through arguments stored inside an ArgList. + class arg_iterator { + /// The current argument. + llvm::SmallVectorImpl<Arg*>::const_iterator Current; + + /// The argument list we are iterating over. + const ArgList &Args; + + /// Optional filters on the arguments which will be match. Most clients + /// should never want to iterate over arguments without filters, so we won't + /// bother to factor this into two separate iterator implementations. + // + // FIXME: Make efficient; the idea is to provide efficient iteration over + // all arguments which match a particular id and then just provide an + // iterator combinator which takes multiple iterators which can be + // efficiently compared and returns them in order. + OptSpecifier Id0, Id1, Id2; + + void SkipToNextArg(); + + public: + typedef const Arg* value_type; + typedef const Arg* reference; + typedef const Arg* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + arg_iterator(llvm::SmallVectorImpl<Arg*>::const_iterator it, + const ArgList &_Args, OptSpecifier _Id0 = 0U, + OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U) + : Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) { + SkipToNextArg(); + } + + operator const Arg*() { return *Current; } + reference operator*() const { return *Current; } + pointer operator->() const { return *Current; } + + arg_iterator &operator++() { + ++Current; + SkipToNextArg(); + return *this; + } + + arg_iterator operator++(int) { + arg_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(arg_iterator LHS, arg_iterator RHS) { + return LHS.Current == RHS.Current; + } + friend bool operator!=(arg_iterator LHS, arg_iterator RHS) { + return !(LHS == RHS); + } + }; + /// ArgList - Ordered collection of driver arguments. /// /// The ArgList class manages a list of Arg instances as well as @@ -62,6 +121,10 @@ namespace driver { unsigned size() const { return Args.size(); } + /// @} + /// @name Arg Iteration + /// @{ + iterator begin() { return Args.begin(); } iterator end() { return Args.end(); } @@ -74,6 +137,18 @@ namespace driver { const_reverse_iterator rbegin() const { return Args.rbegin(); } const_reverse_iterator rend() const { return Args.rend(); } + arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U, + OptSpecifier Id2 = 0U) const { + return arg_iterator(Args.begin(), *this, Id0, Id1, Id2); + } + arg_iterator filtered_end() const { + return arg_iterator(Args.end(), *this); + } + + /// @} + /// @name Arg Access + /// @{ + /// hasArg - Does the arg list contain any option matching \arg Id. /// /// \arg Claim Whether the argument should be claimed, if it exists. @@ -115,17 +190,13 @@ namespace driver { void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const; /// AddAllArgs - Render all arguments matching the given ids. - void AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const; void AddAllArgs(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const; - void AddAllArgs(ArgStringList &Output, OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2) const; + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; /// AddAllArgValues - Render the argument values of all arguments /// matching the given ids. - void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const; void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const; + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; /// AddAllArgsTranslated - Render all the arguments matching the /// given ids, but forced to separate args and using the provided diff --git a/include/clang/Driver/CC1Options.h b/include/clang/Driver/CC1Options.h index 057022ce38c1..4a8bbe5feb77 100644 --- a/include/clang/Driver/CC1Options.h +++ b/include/clang/Driver/CC1Options.h @@ -17,8 +17,6 @@ namespace driver { namespace cc1options { enum ID { OPT_INVALID = 0, // This is not an option ID. - OPT_INPUT, // Reserved ID for input option. - OPT_UNKNOWN, // Reserved ID for unknown option. #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) OPT_##ID, #include "clang/Driver/CC1Options.inc" diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index ef8d8478282d..b34fe0340a55 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -14,13 +14,400 @@ // Include the common option parsing interfaces. include "OptParser.td" +//===----------------------------------------------------------------------===// // Target Options +//===----------------------------------------------------------------------===// def target_abi : Separate<"-target-abi">, HelpText<"Target a particular ABI type">; -def target_cpu : Separate<"-mcpu">, - HelpText<"Target a specific cpu type (-mcpu=help for details)">; -def target_features : Separate<"-target-feature">, +def mcpu : Separate<"-mcpu">, + HelpText<"Target a specific cpu type ('-mcpu help' for details)">; +def target_feature : Separate<"-target-feature">, HelpText<"Target specific attributes">; -def target_triple : Separate<"-triple">, +def triple : Separate<"-triple">, HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; +def triple_EQ : Joined<"-triple=">, Alias<triple>; + +//===----------------------------------------------------------------------===// +// Analyzer Options +//===----------------------------------------------------------------------===// + +def analysis_CFGDump : Flag<"-cfg-dump">, + HelpText<"Display Control-Flow Graphs">; +def analysis_CFGView : Flag<"-cfg-view">, + HelpText<"View Control-Flow Graphs using GraphViz">; +def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">, + HelpText<"Print results of live variable analysis">; +def analysis_SecuritySyntacticChecks : Flag<"-warn-security-syntactic">, + HelpText<"Perform quick security checks that require no data flow">; +def analysis_WarnDeadStores : Flag<"-warn-dead-stores">, + HelpText<"Warn about stores to dead variables">; +def analysis_WarnUninitVals : Flag<"-warn-uninit-values">, + HelpText<"Warn about uses of uninitialized variables">; +def analysis_WarnObjCMethSigs : Flag<"-warn-objc-methodsigs">, + HelpText<"Warn about Objective-C method signatures with type incompatibilities">; +def analysis_WarnObjCDealloc : Flag<"-warn-objc-missing-dealloc">, + HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">; +def analysis_WarnObjCUnusedIvars : Flag<"-warn-objc-unused-ivars">, + HelpText<"Warn about private ivars that are never used">; +def analysis_CheckerCFRef : Flag<"-checker-cfref">, + HelpText<"Run the [Core] Foundation reference count checker">; +def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, + HelpText<"Warn about unintended use of sizeof() on pointer expressions">; +def analysis_InlineCall : Flag<"-inline-call">, + HelpText<"Experimental transfer function inling callees when its definition is available.">; + +def analyzer_store : Separate<"-analyzer-store">, + HelpText<"Source Code Analysis - Abstract Memory Store Models">; +def analyzer_store_EQ : Joined<"-analyzer-store=">, Alias<analyzer_store>; + +def analyzer_constraints : Separate<"-analyzer-constraints">, + HelpText<"Source Code Analysis - Symbolic Constraint Engines">; +def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">, + Alias<analyzer_constraints>; + +def analyzer_output : Separate<"-analyzer-output">, + HelpText<"Source Code Analysis - Output Options">; +def analyzer_output_EQ : Joined<"-analyzer-output=">, + Alias<analyzer_output>; + +def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, + HelpText<"Force the static analyzer to analyze functions defined in header files">; +def analyzer_display_progress : Flag<"-analyzer-display-progress">, + HelpText<"Emit verbose output about the analyzer's progress">; +def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">, + HelpText<"Use experimental path-sensitive checks">; +def analyzer_experimental_internal_checks : + Flag<"-analyzer-experimental-internal-checks">, + HelpText<"Use new default path-sensitive checks currently in testing">; +def analyze_function : Separate<"-analyze-function">, + HelpText<"Run analysis on specific function">; +def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>; +def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">, + HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; +def analyzer_no_purge_dead : Flag<"-analyzer-no-purge-dead">, + HelpText<"Don't remove dead symbols, bindings, and constraints before processing a statement">; +def trim_egraph : Flag<"-trim-egraph">, + HelpText<"Only show error-related paths in the analysis graph">; +def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, + HelpText<"Display exploded graph using GraphViz">; +def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, + HelpText<"Display exploded graph using Ubigraph">; + +//===----------------------------------------------------------------------===// +// CodeGen Options +//===----------------------------------------------------------------------===// + +def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, + HelpText<"Don't run LLVM optimization passes">; +def disable_red_zone : Flag<"-disable-red-zone">, + HelpText<"Do not emit code that uses the red zone.">; +def g : Flag<"-g">, HelpText<"Generate source level debug information">; +def fno_common : Flag<"-fno-common">, + HelpText<"Compile common globals like normal definitions">; +def no_implicit_float : Flag<"-no-implicit-float">, + HelpText<"Don't generate implicit floating point instructions (x86-only)">; +def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, + HelpText<"Disallow merging of constants.">; +def masm_verbose : Flag<"-masm-verbose">, + HelpText<"Generate verbose assembly output">; +def mcode_model : Separate<"-mcode-model">, + HelpText<"The code model to use">; +def mdebug_pass : Separate<"-mdebug-pass">, + HelpText<"Enable additional debug output">; +def mdisable_fp_elim : Flag<"-mdisable-fp-elim">, + HelpText<"Disable frame pointer elimination optimization">; +def mfloat_abi : Flag<"-mfloat-abi">, + HelpText<"The float ABI to use">; +def mlimit_float_precision : Separate<"-mlimit-float-precision">, + HelpText<"Limit float precision to the given value">; +def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, + HelpText<"Do not put zero initialized data in the BSS">; +def msoft_float : Separate<"-msoft-float">, + HelpText<"Use software floating point">; +def mrelocation_model : Separate<"-mrelocation-model">, + HelpText<"The relocation model to use">; +def munwind_tables : Flag<"-munwind-tables">, + HelpText<"Generate unwinding tables for all functions">; +def O : Joined<"-O">, HelpText<"Optimization level">; +def Os : Flag<"-Os">, HelpText<"Optimize for size">; + +//===----------------------------------------------------------------------===// +// Dependency Output Options +//===----------------------------------------------------------------------===// + +def dependency_file : Separate<"-dependency-file">, + HelpText<"Filename (or -) to write dependency output to">; +def sys_header_deps : Flag<"-sys-header-deps">, + HelpText<"Include system headers in dependency output">; +def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; +def MP : Flag<"-MP">, + HelpText<"Create phony target for each dependency (other than main file)">; + +//===----------------------------------------------------------------------===// +// Diagnostic Options +//===----------------------------------------------------------------------===// + +def dump_build_information : Separate<"-dump-build-information">, + MetaVarName<"filename">, + HelpText<"output a dump of some build information to a file">; +def fno_show_column : Flag<"-fno-show-column">, + HelpText<"Do not include column number on diagnostics">; +def fno_show_source_location : Flag<"-fno-show-source-location">, + HelpText<"Do not include source location information with diagnostics">; +def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, + HelpText<"Do not include source line and caret with diagnostics">; +def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, + HelpText<"Do not include fixit information in diagnostics">; +def w : Flag<"-w">, HelpText<"Suppress all warnings">; +def pedantic : Flag<"-pedantic">; +def pedantic_errors : Flag<"-pedantic-errors">; + +// This gets all -W options, including -Werror, -W[no-]system-headers, etc. The +// driver has stripped off -Wa,foo etc. The driver has also translated -W to +// -Wextra, so we don't need to worry about it. +def W : Joined<"-W">; + +def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, + HelpText<"Print source range spans in numeric form">; +def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, + HelpText<"Print diagnostic name with mappable diagnostics">; +def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"N">, + HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; +def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, + HelpText<"Use colors in diagnostics">; +def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">, + HelpText<"Silence ObjC rewriting warnings">; +def verify : Flag<"-verify">, + HelpText<"Verify emitted diagnostics and warnings">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +def code_completion_at : Separate<"-code-completion-at">, + MetaVarName<"file:line:column">, + HelpText<"Dump code-completion information at a location">; +def code_completion_at_EQ : Joined<"-code-completion-at=">, + Alias<code_completion_at>; +def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer">, + HelpText<"Don't the \"debug\" code-completion print">; +def code_completion_macros : Flag<"-code-completion-macros">, + HelpText<"Include macros in code-completion results">; +def disable_free : Flag<"-disable-free">, + HelpText<"Disable freeing of memory on exit">; +def empty_input_only : Flag<"-empty-input-only">, + HelpText<"Force running on an empty input file">; +def x : Separate<"-x">, HelpText<"Input language type">; +def cxx_inheritance_view : Separate<"-cxx-inheritance-view">, + MetaVarName<"class name">, + HelpText<"View C++ inheritance for a specified class">; +def fixit_at : Separate<"-fixit-at">, MetaVarName<"source-location">, + HelpText<"Perform Fix-It modifications at the given source location">; +def o : Separate<"-o">, MetaVarName<"path">, HelpText<"Specify output file">; +def plugin : Separate<"-plugin">, + HelpText<"Use the named plugin action (use \"help\" to list available options)">; + +def Action_Group : OptionGroup<"<action group>">; +let Group = Action_Group in { + +def Eonly : Flag<"-Eonly">, + HelpText<"Just run preprocessor, no output (for timings)">; +def E : Flag<"-E">, + HelpText<"Run preprocessor, emit preprocessed file">; +def dump_raw_tokens : Flag<"-dump-raw-tokens">, + HelpText<"Lex file in raw mode and dump raw tokens">; +def analyze : Flag<"-analyze">, + HelpText<"Run static analysis engine">; +def dump_tokens : Flag<"-dump-tokens">, + HelpText<"Run preprocessor, dump internal rep of tokens">; +def parse_noop : Flag<"-parse-noop">, + HelpText<"Run parser with noop callbacks (for timings)">; +def fsyntax_only : Flag<"-fsyntax-only">, + HelpText<"Run parser and perform semantic analysis">; +def fixit : Flag<"-fixit">, + HelpText<"Apply fix-it advice to the input source">; +def parse_print_callbacks : Flag<"-parse-print-callbacks">, + HelpText<"Run parser and print each callback invoked">; +def emit_html : Flag<"-emit-html">, + HelpText<"Output input source as HTML">; +def ast_print : Flag<"-ast-print">, + HelpText<"Build ASTs and then pretty-print them">; +def ast_print_xml : Flag<"-ast-print-xml">, + HelpText<"Build ASTs and then print them in XML format">; +def ast_dump : Flag<"-ast-dump">, + HelpText<"Build ASTs and then debug dump them">; +def ast_view : Flag<"-ast-view">, + HelpText<"Build ASTs and view them with GraphViz">; +def print_decl_contexts : Flag<"-print-decl-contexts">, + HelpText<"Print DeclContexts and their Decls">; +def dump_record_layouts : Flag<"-dump-record-layouts">, + HelpText<"Dump record layout information">; +def emit_pth : Flag<"-emit-pth">, + HelpText<"Generate pre-tokenized header file">; +def emit_pch : Flag<"-emit-pch">, + HelpText<"Generate pre-compiled header file">; +def S : Flag<"-S">, + HelpText<"Emit native assembly code">; +def emit_llvm : Flag<"-emit-llvm">, + HelpText<"Build ASTs then convert to LLVM, emit .ll file">; +def emit_llvm_bc : Flag<"-emit-llvm-bc">, + HelpText<"Build ASTs then convert to LLVM, emit .bc file">; +def emit_llvm_only : Flag<"-emit-llvm-only">, + HelpText<"Build ASTs and convert to LLVM, discarding output">; +def rewrite_test : Flag<"-rewrite-test">, + HelpText<"Rewriter playground">; +def rewrite_objc : Flag<"-rewrite-objc">, + HelpText<"Rewrite ObjC into C (code rewriter example)">; +def rewrite_macros : Flag<"-rewrite-macros">, + HelpText<"Expand macros without full preprocessing">; +def rewrite_blocks : Flag<"-rewrite-blocks">, + HelpText<"Rewrite Blocks to C">; + +} + +def relocatable_pch : Flag<"-relocatable-pch">, + HelpText<"Whether to build a relocatable precompiled header">; +def print_stats : Flag<"-print-stats">, + HelpText<"Print performance metrics and statistics">; +def ftime_report : Flag<"-ftime-report">, + HelpText<"Print the amount of time each phase of compilation takes">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +def fno_builtin : Flag<"-fno-builtin">, + HelpText<"Disable implicit builtin knowledge of functions">; +def faltivec : Flag<"-faltivec">, + HelpText<"Enable AltiVec vector initializer syntax">; +def faccess_control : Flag<"-faccess-control">, + HelpText<"Enable C++ access control">; +def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, + HelpText<"Allow '$' in identifiers">; +def femit_all_decls : Flag<"-femit-all-decls">, + HelpText<"Emit all declarations, even if unused">; +def fblocks : Flag<"-fblocks">, + HelpText<"enable the 'blocks' language feature">; +def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; +def fexceptions : Flag<"-fexceptions">, + HelpText<"Enable support for exception handling">; +def ffreestanding : Flag<"-ffreestanding">, + HelpText<"Assert that the compilation takes place in a freestanding environment">; +def fgnu_runtime : Flag<"-fgnu-runtime">, + HelpText<"Generate output compatible with the standard GNU Objective-C runtime">; +def std_EQ : Joined<"-std=">, + HelpText<"Language standard to compile for">; +def fms_extensions : Flag<"-fms-extensions">, + HelpText<"Accept some non-standard constructs used in Microsoft header files ">; +def main_file_name : Separate<"-main-file-name">, + HelpText<"Main file name to use for debug info">; +def fno_elide_constructors : Flag<"-fno-elide-constructors">, + HelpText<"Disable C++ copy constructor elision">; +def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, + HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">; +def fno_math_errno : Flag<"-fno-math-errno">, + HelpText<"Don't require math functions to respect errno">; +def fno_signed_char : Flag<"-fno-signed-char">, + HelpText<"Char is unsigned">; +def fno_operator_names : Flag<"-fno-operator-names">, + HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; +def fconstant_string_class : Separate<"-fconstant-string-class">, + MetaVarName<"class name">, + HelpText<"Specify the class to use for constant Objective-C string objects.">; +def fobjc_gc : Flag<"-fobjc-gc">, + HelpText<"Enable Objective-C garbage collection">; +def fobjc_gc_only : Flag<"-fobjc-gc-only">, + HelpText<"Use GC exclusively for Objective-C related memory management">; +def print_ivar_layout : Flag<"-print-ivar-layout">, + HelpText<"Enable Objective-C Ivar layout bitmap print trace">; +def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, + HelpText<"enable objective-c's nonfragile abi">; +def ftrapv : Flag<"-ftrapv">, + HelpText<"Trap on integer overflow">; +def pic_level : Separate<"-pic-level">, + HelpText<"-Value for __PIC__">; +def pthread : Flag<"-pthread">, + HelpText<"Support POSIX threads in generated code">; +def fpascal_strings : Flag<"-fpascal-strings">, + HelpText<"Recognize and construct Pascal-style string literals">; +def fno_rtti : Flag<"-fno-rtti">, + HelpText<"Disable generation of rtti information">; +def fshort_wchar : Flag<"-fshort-wchar">, + HelpText<"Force wchar_t to be a short unsigned int">; +def static_define : Flag<"-static-define">, + HelpText<"Should __STATIC__ be defined">; +def stack_protector : Separate<"-stack-protector">, + HelpText<"Enable stack protectors">; +def fvisibility : Separate<"-fvisibility">, + HelpText<"Default symbol visibility">; +def ftemplate_depth : Separate<"-ftemplate-depth">, + HelpText<"Maximum depth of recursive template instantiation">; +def trigraphs : Flag<"-trigraphs">, + HelpText<"Process trigraph sequences">; +def fwritable_strings : Flag<"-fwritable-strings">, + HelpText<"Store string literals as writable data">; + +//===----------------------------------------------------------------------===// +// Header Search Options +//===----------------------------------------------------------------------===// + +def nostdinc : Flag<"-nostdinc">, + HelpText<"Disable standard #include directories">; +def nobuiltininc : Flag<"-nobuiltininc">, + HelpText<"Disable builtin #include directories">; +def F : JoinedOrSeparate<"-F">, MetaVarName<"directory">, + HelpText<"Add directory to framework include search path">; +def I : JoinedOrSeparate<"-I">, MetaVarName<"directory">, + HelpText<"Add directory to include search path">; +def idirafter : Separate<"-idirafter">, MetaVarName<"directory">, + HelpText<"Add directory to AFTER include search path">; +def iquote : Separate<"-iquote">, MetaVarName<"directory">, + HelpText<"Add directory to QUOTE include search path">; +def isystem : Separate<"-isystem">, MetaVarName<"directory">, + HelpText<"Add directory to SYSTEM include search path">; +def iprefix : Separate<"-iprefix">, MetaVarName<"prefix">, + HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">; +def iwithprefix : Separate<"-iwithprefix">, MetaVarName<"dir">, + HelpText<"Set directory to SYSTEM include search path with prefix">; +def iwithprefixbefore : Separate<"-iwithprefixbefore">, MetaVarName<"dir">, + HelpText<"Set directory to include search path with prefix">; +def isysroot : Separate<"-isysroot">, MetaVarName<"dir">, + HelpText<"Set the system root directory (usually /)">; +def v : Flag<"-v">, HelpText<"Enable verbose output">; + +//===----------------------------------------------------------------------===// +// Preprocessor Options +//===----------------------------------------------------------------------===// + +def D : JoinedOrSeparate<"-D">, MetaVarName<"macro">, + HelpText<"Predefine the specified macro">; +def include_ : Separate<"-include">, MetaVarName<"file">, EnumName<"include">, + HelpText<"Include file before parsing">; +def imacros : Separate<"-imacros">, MetaVarName<"file">, + HelpText<"Include macros from file before parsing">; +def include_pch : Separate<"-include-pch">, MetaVarName<"file">, + HelpText<"Include precompiled header file">; +def include_pth : Separate<"-include-pth">, MetaVarName<"file">, + HelpText<"Include file before parsing">; +def token_cache : Separate<"-token-cache">, MetaVarName<"path">, + HelpText<"Use specified token cache file">; +def U : JoinedOrSeparate<"-U">, MetaVarName<"macro">, + HelpText<"Undefine the specified macro">; +def undef : Flag<"-undef">, MetaVarName<"macro">, + HelpText<"undef all system defines">; + +//===----------------------------------------------------------------------===// +// Preprocessed Output Options +//===----------------------------------------------------------------------===// + +def P : Flag<"-P">, + HelpText<"Disable linemarker output in -E mode">; +def C : Flag<"-C">, + HelpText<"Enable comment output in -E mode">; +def CC : Flag<"-CC">, + HelpText<"Enable comment output in -E mode, even from macro expansions">; +def dM : Flag<"-dM">, + HelpText<"Print macro definitions in -E mode instead of normal output">; +def dD : Flag<"-dD">, + HelpText<"Print macro definitions in -E mode in addition to normal output">; diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile index c0f2cc7b6777..18f3e58d7db4 100644 --- a/include/clang/Driver/Makefile +++ b/include/clang/Driver/Makefile @@ -5,11 +5,11 @@ TABLEGEN_INC_FILES_COMMON = 1 include $(LEVEL)/Makefile.common -$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(ObjDir)/.dir +$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang Driver Option tables with tblgen" $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< -$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(ObjDir)/.dir +$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang CC1 Option tables with tblgen" $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td index 70b59c69c264..f5b6980d8f6a 100644 --- a/include/clang/Driver/OptParser.td +++ b/include/clang/Driver/OptParser.td @@ -14,14 +14,20 @@ // Define the kinds of options. -class OptionKind<string name, int predecence = 0> { +class OptionKind<string name, int predecence = 0, bit sentinel = 0> { string Name = name; // The kind precedence, kinds with lower precedence are matched first. int Precedence = predecence; + // Indicate a sentinel option. + bit Sentinel = sentinel; } // An option group. def KIND_GROUP : OptionKind<"Group">; +// The input option kind. +def KIND_INPUT : OptionKind<"Input", 1, 1>; +// The unknown option kind. +def KIND_UNKNOWN : OptionKind<"Unknown", 2, 1>; // A flag with no values. def KIND_FLAG : OptionKind<"Flag">; // An option which prefixes its (single) value. @@ -114,3 +120,10 @@ class Flags<list<OptionFlag> flags> { list<OptionFlag> Flags = flags; } class Group<OptionGroup group> { OptionGroup Group = group; } class HelpText<string text> { string HelpText = text; } class MetaVarName<string name> { string MetaVarName = name; } + +// Predefined options. + +// FIXME: Have generator validate that these appear in correct position (and +// aren't duplicated). +def INPUT : Option<"<input>", KIND_INPUT>, Flags<[DriverOption]>; +def UNKNOWN : Option<"<unknown>", KIND_UNKNOWN>; diff --git a/include/clang/Driver/OptSpecifier.h b/include/clang/Driver/OptSpecifier.h index c38b36c2f70f..bb1cd1740bbb 100644 --- a/include/clang/Driver/OptSpecifier.h +++ b/include/clang/Driver/OptSpecifier.h @@ -22,9 +22,12 @@ namespace driver { explicit OptSpecifier(bool); // DO NOT IMPLEMENT public: + OptSpecifier() : ID(0) {} /*implicit*/ OptSpecifier(unsigned _ID) : ID(_ID) {} /*implicit*/ OptSpecifier(const Option *Opt); + bool isValid() const { return ID != 0; } + unsigned getID() const { return ID; } bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); } diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h index b05d5afd7578..ac312cdfd4d2 100644 --- a/include/clang/Driver/Options.h +++ b/include/clang/Driver/Options.h @@ -17,8 +17,6 @@ namespace driver { namespace options { enum ID { OPT_INVALID = 0, // This is not an option ID. - OPT_INPUT, // Reserved ID for input option. - OPT_UNKNOWN, // Reserved ID for unknown option. #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) OPT_##ID, #include "clang/Driver/Options.inc" diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 0e7d55e6e45b..26efa9745600 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -83,6 +83,7 @@ ASTConsumer *CreateBackendConsumer(BackendAction Action, const LangOptions &Features, const CodeGenOptions &CodeGenOpts, const TargetOptions &TargetOpts, + bool TimePasses, const std::string &ModuleID, llvm::raw_ostream *OS, llvm::LLVMContext& C); diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 7dfabbadd8fd..04dc5ed8cc56 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -22,16 +22,17 @@ #include <string> namespace clang { - class FileManager; - class FileEntry; - class SourceManager; - class Diagnostic; - class TextDiagnosticBuffer; - class HeaderSearch; - class TargetInfo; - class Preprocessor; - class ASTContext; - class Decl; +class ASTContext; +class CompilerInvocation; +class Decl; +class Diagnostic; +class FileEntry; +class FileManager; +class HeaderSearch; +class Preprocessor; +class SourceManager; +class TargetInfo; +class TextDiagnosticBuffer; using namespace idx; @@ -92,21 +93,35 @@ public: /// /// \param Filename - The PCH file to load. /// - /// \param diagClient - The diagnostics client to use. Specify NULL + /// \param DiagClient - The diagnostics client to use. Specify NULL /// to use a default client that emits warnings/errors to standard error. /// The ASTUnit objects takes ownership of this object. /// - /// \param FileMgr - The FileManager to use. - /// /// \param ErrMsg - Error message to report if the PCH file could not be /// loaded. /// /// \returns - The initialized ASTUnit or null if the PCH failed to load. static ASTUnit *LoadFromPCHFile(const std::string &Filename, std::string *ErrMsg = 0, - DiagnosticClient *diagClient = NULL, + DiagnosticClient *DiagClient = NULL, bool OnlyLocalDecls = false, bool UseBumpAllocator = false); + + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a + /// CompilerInvocation object. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. + /// + /// \param Diags - The diagnostics engine to use for reporting errors. + // + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCompilerInvocation(const CompilerInvocation &CI, + Diagnostic &Diags, + bool OnlyLocalDecls = false, + bool UseBumpAllocator = false); + }; } // namespace clang diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h index 7a324331ecdc..24fed6e76ac1 100644 --- a/include/clang/Frontend/AnalysisConsumer.h +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -77,7 +77,7 @@ public: AnalyzeAll = 0; AnalyzerDisplayProgress = 0; EagerlyAssume = 0; - PurgeDead = 0; + PurgeDead = 1; TrimGraph = 0; VisualizeEGDot = 0; VisualizeEGUbi = 0; diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h index d5a0598dfab2..bea468b01791 100644 --- a/include/clang/Frontend/CommandLineSourceLoc.h +++ b/include/clang/Frontend/CommandLineSourceLoc.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H #include "llvm/Support/CommandLine.h" -#include <cstdio> +#include "llvm/Support/raw_ostream.h" namespace clang { @@ -25,6 +25,23 @@ struct ParsedSourceLocation { std::string FileName; unsigned Line; unsigned Column; + +public: + /// Construct a parsed source location from a string; the Filename is empty on + /// error. + static ParsedSourceLocation FromString(llvm::StringRef Str) { + ParsedSourceLocation PSL; + std::pair<llvm::StringRef, llvm::StringRef> ColSplit = Str.rsplit(':'); + std::pair<llvm::StringRef, llvm::StringRef> LineSplit = + ColSplit.first.rsplit(':'); + + // If both tail splits were valid integers, return success. + if (!ColSplit.second.getAsInteger(10, PSL.Column) && + !LineSplit.second.getAsInteger(10, PSL.Line)) + PSL.FileName = LineSplit.first; + + return PSL; + } }; } @@ -48,35 +65,13 @@ namespace llvm { clang::ParsedSourceLocation &Val) { using namespace clang; - const char *ExpectedFormat - = "source location must be of the form filename:line:column"; - StringRef::size_type SecondColon = ArgValue.rfind(':'); - if (SecondColon == std::string::npos) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - - unsigned Column; - if (ArgValue.substr(SecondColon + 1).getAsInteger(10, Column)) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - ArgValue = ArgValue.substr(0, SecondColon); - - StringRef::size_type FirstColon = ArgValue.rfind(':'); - if (FirstColon == std::string::npos) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - unsigned Line; - if (ArgValue.substr(FirstColon + 1).getAsInteger(10, Line)) { - std::fprintf(stderr, "%s\n", ExpectedFormat); + Val = ParsedSourceLocation::FromString(ArgValue); + if (Val.FileName.empty()) { + errs() << "error: " + << "source location must be of the form filename:line:column\n"; return true; } - Val.FileName = ArgValue.substr(0, FirstColon); - Val.Line = Line; - Val.Column = Column; return false; } } diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index ed280508778a..d7e7d991f379 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -21,6 +21,7 @@ namespace llvm { class LLVMContext; class raw_ostream; class raw_fd_ostream; +class Timer; } namespace clang { @@ -89,6 +90,9 @@ class CompilerInstance { /// The code completion consumer. llvm::OwningPtr<CodeCompleteConsumer> CompletionConsumer; + /// The frontend timer + llvm::OwningPtr<llvm::Timer> FrontendTimer; + /// The list of active output files. std::list< std::pair<std::string, llvm::raw_ostream*> > OutputFiles; @@ -367,6 +371,17 @@ public: void setCodeCompletionConsumer(CodeCompleteConsumer *Value); /// } + /// @name Frontend timer + /// { + + bool hasFrontendTimer() const { return FrontendTimer != 0; } + + llvm::Timer &getFrontendTimer() const { + assert(FrontendTimer && "Compiler instance has no frontend timer!"); + return *FrontendTimer; + } + + /// } /// @name Output Files /// { @@ -462,6 +477,9 @@ public: bool UseDebugPrinter, bool ShowMacros, llvm::raw_ostream &OS); + /// Create the frontend timer and replace any existing one with it. + void createFrontendTimer(); + /// Create the default output file (from the invocation's options) and add it /// to the list of tracked output files. llvm::raw_fd_ostream * diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index 9d068c523c69..e7c51aabba59 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -31,6 +31,8 @@ namespace llvm { namespace clang { +class Diagnostic; + /// CompilerInvocation - Helper class for holding the data necessary to invoke /// the compiler. /// @@ -77,12 +79,18 @@ public: /// CreateFromArgs - Create a compiler invocation from a list of input /// options. /// - /// FIXME: Documenting error behavior. - /// /// \param Res [out] - The resulting invocation. - /// \param Args - The input argument strings. - static void CreateFromArgs(CompilerInvocation &Res, - const llvm::SmallVectorImpl<llvm::StringRef> &Args); + /// \param ArgBegin - The first element in the argument vector. + /// \param ArgEnd - The last element in the argument vector. + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + /// \param Diags - The diagnostic engine to use for errors. + static void CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, + const char **ArgEnd, const char *Argv0, + void *MainAddr, + Diagnostic &Diags); /// toArgs - Convert the CompilerInvocation to a list of strings suitable for /// passing to CreateFromArgs. diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index 8b80d1dc11d8..c750492a270e 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -7,46 +7,46 @@ // //===----------------------------------------------------------------------===// // -// This file defines the XML statement database structure as written in -// <TranslationUnit> sub-nodes of the XML document. +// This file defines the XML statement database structure as written in +// <TranslationUnit> sub-nodes of the XML document. // The semantics of the attributes and enums are mostly self-documenting // by looking at the appropriate internally used functions and values. // The following macros are used: // -// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete -// statement of class CLASS where CLASS is a class name used internally by clang. -// After a NODE_XML the definition of all (optional) attributes of that statement +// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete +// statement of class CLASS where CLASS is a class name used internally by clang. +// After a NODE_XML the definition of all (optional) attributes of that statement // node and possible sub-nodes follows. // // END_NODE_XML - Closes the attribute definition of the current node. // -// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a -// string, which value uniquely identify that statement. Other nodes may refer +// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a +// string, which value uniquely identify that statement. Other nodes may refer // by reference attributes to this value (currently used only for Label). // // TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an // expression by a "type" attribute. FN is internally used by clang. -// -// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally +// +// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally // used by clang. A boolean attribute have the values "0" or "1". // -// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves -// a special handling. See the appropriate documentations. +// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves +// a special handling. See the appropriate documentations. // // ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of // a statement in the source file(s). // -// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. -// Optional attributes are omitted for boolean types, if the value is false, -// for integral types, if the value is null and for strings, +// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. +// Optional attributes are omitted for boolean types, if the value is false, +// for integral types, if the value is null and for strings, // if the value is the empty string. FN is internally used by clang. // // ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value -// is an enumeration defined with ENUM_XML macros immediately following after -// that macro. An optional attribute is ommited, if the particular enum is the +// is an enumeration defined with ENUM_XML macros immediately following after +// that macro. An optional attribute is ommited, if the particular enum is the // empty string. FN is internally used by clang. -// -// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is +// +// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is // internally used by clang. // // END_ENUM_XML - Closes the enumeration definition of the current attribute. @@ -55,7 +55,7 @@ // // SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes. // -// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or +// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or // its sub-classes. // //===----------------------------------------------------------------------===// @@ -114,8 +114,8 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl") TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") - ATTRIBUTE_OPT_XML(isStatic(), "static") - ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_OPT_XML(isStatic(), "static") + ATTRIBUTE_OPT_XML(isVirtual(), "virtual") ATTRIBUTE_XML(getNumParams(), "num_args") SUB_NODE_SEQUENCE_XML(ParmVarDecl) //SUB_NODE_OPT_XML("Body") @@ -124,7 +124,7 @@ END_NODE_XML //NODE_XML("Body") // SUB_NODE_XML(Stmt) //END_NODE_XML - + NODE_XML(NamespaceDecl, "Namespace") ID_ATTRIBUTE_XML ATTRIBUTE_FILE_LOCATION_XML @@ -152,7 +152,7 @@ NODE_XML(RecordDecl, "Record") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") ATTRIBUTE_OPT_XML(isDefinition() == false, "forward") - ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates + ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates SUB_NODE_SEQUENCE_XML(FieldDecl) END_NODE_XML @@ -162,7 +162,7 @@ NODE_XML(EnumDecl, "Enum") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") ATTRIBUTE_OPT_XML(isDefinition() == false, "forward") - ATTRIBUTE_SPECIAL_XML(getIntegerType(), "type") // is NULL in pure declarations thus deserves special handling + ATTRIBUTE_SPECIAL_XML(getIntegerType(), "type") // is NULL in pure declarations thus deserves special handling SUB_NODE_SEQUENCE_XML(EnumConstantDecl) // only present in definition END_NODE_XML @@ -209,7 +209,7 @@ NODE_XML(VarDecl, "Var") ENUM_XML(VarDecl::Static, "static") ENUM_XML(VarDecl::PrivateExtern, "__private_extern__") END_ENUM_XML - SUB_NODE_OPT_XML(Expr) // init expr + SUB_NODE_OPT_XML(Expr) // init expr END_NODE_XML NODE_XML(ParmVarDecl, "ParmVar") @@ -218,7 +218,7 @@ NODE_XML(ParmVarDecl, "ParmVar") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_OPT_XML(Expr) // default argument expression + SUB_NODE_OPT_XML(Expr) // default argument expression END_NODE_XML NODE_XML(LinkageSpecDecl, "LinkageSpec") @@ -234,7 +234,7 @@ END_NODE_XML //===----------------------------------------------------------------------===// #undef NODE_XML -#undef ID_ATTRIBUTE_XML +#undef ID_ATTRIBUTE_XML #undef TYPE_ATTRIBUTE_XML #undef ATTRIBUTE_XML #undef ATTRIBUTE_SPECIAL_XML @@ -243,8 +243,8 @@ END_NODE_XML #undef ATTRIBUTE_ENUM_OPT_XML #undef ATTRIBUTE_FILE_LOCATION_XML #undef ENUM_XML -#undef END_ENUM_XML -#undef END_NODE_XML +#undef END_ENUM_XML +#undef END_NODE_XML #undef SUB_NODE_XML #undef SUB_NODE_SEQUENCE_XML #undef SUB_NODE_OPT_XML diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index 469ea535f6aa..3042767af874 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -14,10 +14,6 @@ #include "llvm/ADT/OwningPtr.h" #include <string> -namespace llvm { -class Timer; -} - namespace clang { class ASTUnit; class ASTConsumer; @@ -29,7 +25,6 @@ class FrontendAction { std::string CurrentFile; llvm::OwningPtr<ASTUnit> CurrentASTUnit; CompilerInstance *Instance; - llvm::Timer *CurrentTimer; protected: /// @name Implementation Action Interface @@ -112,18 +107,6 @@ public: void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0); /// @} - /// @name Timing Utilities - /// @{ - - llvm::Timer *getCurrentTimer() const { - return CurrentTimer; - } - - void setCurrentTimer(llvm::Timer *Value) { - CurrentTimer = Value; - } - - /// @} /// @name Supported Modes /// @{ diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 197a2a05e5e0..c1ec8e70f1c6 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -107,7 +107,7 @@ public: public: FrontendOptions() { - DebugCodeCompletionPrinter = 0; + DebugCodeCompletionPrinter = 1; DisableFree = 0; EmptyInputOnly = 0; ProgramAction = frontend::ParseSyntaxOnly; diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h new file mode 100644 index 000000000000..441d34f5a388 --- /dev/null +++ b/include/clang/Frontend/LangStandard.h @@ -0,0 +1,83 @@ +//===--- LangStandard.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H +#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H + +#include "llvm/ADT/StringRef.h" + +namespace clang { + +namespace frontend { + +enum LangFeatures { + BCPLComment = (1 << 0), + C99 = (1 << 1), + CPlusPlus = (1 << 2), + CPlusPlus0x = (1 << 3), + Digraphs = (1 << 4), + GNUMode = (1 << 5), + HexFloat = (1 << 6), + ImplicitInt = (1 << 7) +}; + +} + +/// LangStandard - Information about the properties of a particular language +/// standard. +struct LangStandard { + enum Kind { +#define LANGSTANDARD(id, name, desc, features) \ + lang_##id, +#include "clang/Frontend/LangStandards.def" + lang_unspecified + }; + + const char *ShortName; + const char *Description; + unsigned Flags; + +public: + /// getName - Get the name of this standard. + const char *getName() const { return ShortName; } + + /// getDescription - Get the description of this standard. + const char *getDescription() const { return Description; } + + /// hasBCPLComments - Language supports '//' comments. + bool hasBCPLComments() const { return Flags & frontend::BCPLComment; } + + /// isC99 - Language is a superset of C99. + bool isC99() const { return Flags & frontend::C99; } + + /// isCPlusPlus - Language is a C++ variant. + bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } + + /// isCPlusPlus0x - Language is a C++0x variant. + bool isCPlusPlus0x() const { return Flags & frontend::CPlusPlus0x; } + + /// hasDigraphs - Language supports digraphs. + bool hasDigraphs() const { return Flags & frontend::Digraphs; } + + /// isGNUMode - Language includes GNU extensions. + bool isGNUMode() const { return Flags & frontend::GNUMode; } + + /// hasHexFloats - Language supports hexadecimal float constants. + bool hasHexFloats() const { return Flags & frontend::HexFloat; } + + /// hasImplicitInt - Language allows variables to be typed as int implicitly. + bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; } + + static const LangStandard &getLangStandardForKind(Kind K); + static const LangStandard *getLangStandardForName(llvm::StringRef Name); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def new file mode 100644 index 000000000000..52aa4636084d --- /dev/null +++ b/include/clang/Frontend/LangStandards.def @@ -0,0 +1,83 @@ +//===-- LangStandards.def - Language Standard Data --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LANGSTANDARD +#error "LANGSTANDARD must be defined before including this file" +#endif + +/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// +/// \param IDENT - The name of the standard as a C++ identifier. +/// \param NAME - The name of the standard. +/// \param DESC - A short description of the standard. +/// \param FEATURES - The standard features as flags, these are enums from the +/// clang::frontend namespace, which is assumed to be be available. + +// C89-ish modes. +LANGSTANDARD(c89, "c89", + "ISO C 1990", + ImplicitInt) +LANGSTANDARD(c90, "c90", + "ISO C 1990", + ImplicitInt) +LANGSTANDARD(iso9899_1990, "iso9899:1990", + "ISO C 1990", + ImplicitInt) + +LANGSTANDARD(c94, "iso9899:199409", + "ISO C 1990 with amendment 1", + Digraphs | ImplicitInt) + +LANGSTANDARD(gnu89, "gnu89", + "ISO C 1990 with GNU extensions", + BCPLComment | Digraphs | GNUMode | ImplicitInt) + +// C99-ish modes +LANGSTANDARD(c99, "c99", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(c9x, "c9x", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_1999, + "iso9899:1999", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_199x, + "iso9899:199x", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) + +LANGSTANDARD(gnu99, "gnu99", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat | Digraphs) +LANGSTANDARD(gnu9x, "gnu9x", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat) + +// C++ modes +LANGSTANDARD(cxx98, "c++98", + "ISO C++ 1998 with amendments", + BCPLComment | CPlusPlus | Digraphs) +LANGSTANDARD(gnucxx98, "gnu++98", + "ISO C++ 1998 with " "amendments and GNU extensions", + BCPLComment | CPlusPlus | Digraphs | GNUMode) + +LANGSTANDARD(cxx0x, "c++0x", + "Upcoming ISO C++ 200x with amendments", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs) +LANGSTANDARD(gnucxx0x, "gnu++0x", + "Upcoming ISO C++ 200x with amendments and GNU extensions", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode) + +// OpenCL + +LANGSTANDARD(opencl, "cl", + "OpenCL 1.0", + BCPLComment | C99 | Digraphs | HexFloat) + +#undef LANGSTANDARD diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index b2bb9a13771d..98463c308e51 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -336,7 +336,9 @@ namespace clang { /// \brief The ObjC 'id' type. PREDEF_TYPE_OBJC_ID = 26, /// \brief The ObjC 'Class' type. - PREDEF_TYPE_OBJC_CLASS = 27 + PREDEF_TYPE_OBJC_CLASS = 27, + /// \brief The ObjC 'SEL' type. + PREDEF_TYPE_OBJC_SEL = 28 }; /// \brief The number of predefined type IDs that are reserved for @@ -438,7 +440,9 @@ namespace clang { /// \brief Block descriptor type for Blocks CodeGen SPECIAL_TYPE_BLOCK_DESCRIPTOR = 12, /// \brief Block extedned descriptor type for Blocks CodeGen - SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13 + SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13, + /// \brief Objective-C "SEL" redefinition type + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14 }; /// \brief Record codes for each kind of declaration. diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h index 98831ba37fe3..f8d2eebeb687 100644 --- a/include/clang/Frontend/PathDiagnosticClients.h +++ b/include/clang/Frontend/PathDiagnosticClients.h @@ -14,9 +14,7 @@ #ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H #define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H -#include <memory> #include <string> -#include "llvm/ADT/SmallVector.h" namespace clang { diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def index fd79cf0c6ccb..2f0da9e7b117 100644 --- a/include/clang/Frontend/StmtXML.def +++ b/include/clang/Frontend/StmtXML.def @@ -7,46 +7,46 @@ // //===----------------------------------------------------------------------===// // -// This file defines the XML statement database structure as written in -// <TranslationUnit> sub-nodes of the XML document. +// This file defines the XML statement database structure as written in +// <TranslationUnit> sub-nodes of the XML document. // The semantics of the attributes and enums are mostly self-documenting // by looking at the appropriate internally used functions and values. // The following macros are used: // -// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete -// statement of class CLASS where CLASS is a class name used internally by clang. -// After a NODE_XML the definition of all (optional) attributes of that statement +// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete +// statement of class CLASS where CLASS is a class name used internally by clang. +// After a NODE_XML the definition of all (optional) attributes of that statement // node and possible sub-nodes follows. // // END_NODE_XML - Closes the attribute definition of the current node. // -// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a -// string, which value uniquely identify that statement. Other nodes may refer +// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a +// string, which value uniquely identify that statement. Other nodes may refer // by reference attributes to this value (currently used only for Label). // // TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an // expression by a "type" attribute. FN is internally used by clang. -// -// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally +// +// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally // used by clang. A boolean attribute have the values "0" or "1". // -// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves -// a special handling. See the appropriate documentations. +// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves +// a special handling. See the appropriate documentations. // // ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of // a statement in the source file(s). // -// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. -// Optional attributes are omitted for boolean types, if the value is false, -// for integral types, if the value is null and for strings, +// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. +// Optional attributes are omitted for boolean types, if the value is false, +// for integral types, if the value is null and for strings, // if the value is the empty string. FN is internally used by clang. // // ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value -// is an enumeration defined with ENUM_XML macros immediately following after -// that macro. An optional attribute is ommited, if the particular enum is the +// is an enumeration defined with ENUM_XML macros immediately following after +// that macro. An optional attribute is ommited, if the particular enum is the // empty string. FN is internally used by clang. -// -// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is +// +// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is // internally used by clang. // // END_ENUM_XML - Closes the enumeration definition of the current attribute. @@ -55,7 +55,7 @@ // // SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes. // -// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or +// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or // its sub-classes. // //===----------------------------------------------------------------------===// @@ -94,21 +94,21 @@ END_NODE_XML NODE_XML(CaseStmt, "CaseStmt") // case expr: body; ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body SUB_NODE_XML(Expr) // expr SUB_NODE_XML(Expr) // rhs expr in gc extension: case expr .. expr: body; END_NODE_XML NODE_XML(DefaultStmt, "DefaultStmt") // default: body; ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body END_NODE_XML NODE_XML(LabelStmt, "LabelStmt") // Label: body; ID_ATTRIBUTE_XML ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getName(), "name") // string - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body END_NODE_XML NODE_XML(IfStmt, "IfStmt") // if (cond) stmt1; else stmt2; @@ -173,23 +173,23 @@ NODE_XML(AsmStmt, "AsmStmt") // GNU inline-assembly sta // FIXME END_NODE_XML -NODE_XML(DeclStmt, "DeclStmt") // a declaration statement +NODE_XML(DeclStmt, "DeclStmt") // a declaration statement ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_SEQUENCE_XML(Decl) + SUB_NODE_SEQUENCE_XML(Decl) END_NODE_XML // C++ statements NODE_XML(CXXTryStmt, "CXXTryStmt") // try CompoundStmt CXXCatchStmt1 CXXCatchStmt2 .. ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getNumHandlers(), "num_handlers") - SUB_NODE_XML(CompoundStmt) - SUB_NODE_SEQUENCE_XML(CXXCatchStmt) + SUB_NODE_XML(CompoundStmt) + SUB_NODE_SEQUENCE_XML(CXXCatchStmt) END_NODE_XML NODE_XML(CXXCatchStmt, "CXXCatchStmt") // catch (decl) Stmt ATTRIBUTE_FILE_LOCATION_XML SUB_NODE_XML(VarDecl) - SUB_NODE_XML(Stmt) + SUB_NODE_XML(Stmt) END_NODE_XML // Expressions @@ -234,7 +234,7 @@ NODE_XML(StringLiteral, "StringLiteral") ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) ATTRIBUTE_SPECIAL_XML(getStrData(), "value") // string, special handling for escaping needed - ATTRIBUTE_OPT_XML(isWide(), "is_wide") // boolean + ATTRIBUTE_OPT_XML(isWide(), "is_wide") // boolean END_NODE_XML NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op @@ -251,7 +251,7 @@ NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op ENUM_XML(UnaryOperator::Minus, "minus") ENUM_XML(UnaryOperator::Not, "not") // bitwise not ENUM_XML(UnaryOperator::LNot, "lnot") // boolean not - ENUM_XML(UnaryOperator::Real, "__real") + ENUM_XML(UnaryOperator::Real, "__real") ENUM_XML(UnaryOperator::Imag, "__imag") ENUM_XML(UnaryOperator::Extension, "__extension__") ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof") @@ -314,7 +314,7 @@ END_NODE_XML NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr") // sizeof(expr) or alignof(expr) ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_XML(isSizeOf(), "is_sizeof") + ATTRIBUTE_XML(isSizeOf(), "is_sizeof") ATTRIBUTE_XML(isArgumentType(), "is_type") // "1" if expr denotes a type ATTRIBUTE_SPECIAL_XML(getArgumentType(), "type_ref") // optional, denotes the type of expr, if is_type=="1", special handling needed since getArgumentType() could assert SUB_NODE_OPT_XML(Expr) // expr, if is_type=="0" @@ -346,29 +346,29 @@ END_NODE_XML NODE_XML(CStyleCastExpr, "CStyleCastExpr") // (type)expr ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) + TYPE_ATTRIBUTE_XML(getType()) ATTRIBUTE_XML(getTypeAsWritten(), "type_ref") // denotes the type as written in the source code SUB_NODE_XML(Expr) // expr END_NODE_XML NODE_XML(ImplicitCastExpr, "ImplicitCastExpr") ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_XML(Expr) + TYPE_ATTRIBUTE_XML(getType()) + SUB_NODE_XML(Expr) END_NODE_XML -NODE_XML(CompoundLiteralExpr, "CompoundLiteralExpr") // [C99 6.5.2.5] +NODE_XML(CompoundLiteralExpr, "CompoundLiteralExpr") // [C99 6.5.2.5] SUB_NODE_XML(Expr) // init END_NODE_XML NODE_XML(ExtVectorElementExpr, "ExtVectorElementExpr") - SUB_NODE_XML(Expr) // base + SUB_NODE_XML(Expr) // base END_NODE_XML NODE_XML(InitListExpr, "InitListExpr") // struct foo x = { expr1, { expr2, expr3 } }; ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_OPT_XML(getInitializedFieldInUnion(), "field_ref") // if a union is initialized, this refers to the initialized union field id + ATTRIBUTE_OPT_XML(getInitializedFieldInUnion(), "field_ref") // if a union is initialized, this refers to the initialized union field id ATTRIBUTE_XML(getNumInits(), "num_inits") // unsigned SUB_NODE_SEQUENCE_XML(Expr) // expr1..exprN END_NODE_XML @@ -412,8 +412,8 @@ END_NODE_XML NODE_XML(TypesCompatibleExpr, "TypesCompatibleExpr") // GNU builtin-in function __builtin_types_compatible_p ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_XML(getArgType1(), "type1_ref") // id of type1 - ATTRIBUTE_XML(getArgType2(), "type2_ref") // id of type2 + ATTRIBUTE_XML(getArgType1(), "type1_ref") // id of type1 + ATTRIBUTE_XML(getArgType2(), "type2_ref") // id of type2 END_NODE_XML NODE_XML(ChooseExpr, "ChooseExpr") // GNU builtin-in function __builtin_choose_expr(expr1, expr2, expr3) @@ -495,16 +495,9 @@ NODE_XML(CXXDefaultArgExpr, "CXXDefaultArgExpr") ATTRIBUTE_XML(getParam(), "ref") // id of the parameter declaration (the expression is a subnode of the declaration) END_NODE_XML -NODE_XML(CXXConditionDeclExpr, "CXXConditionDeclExpr") - ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_XML(VarDecl) // a CXXConditionDeclExpr owns the declaration -END_NODE_XML - - //===----------------------------------------------------------------------===// #undef NODE_XML -#undef ID_ATTRIBUTE_XML +#undef ID_ATTRIBUTE_XML #undef TYPE_ATTRIBUTE_XML #undef ATTRIBUTE_XML #undef ATTRIBUTE_SPECIAL_XML @@ -513,8 +506,8 @@ END_NODE_XML #undef ATTRIBUTE_ENUM_OPT_XML #undef ATTRIBUTE_FILE_LOCATION_XML #undef ENUM_XML -#undef END_ENUM_XML -#undef END_NODE_XML +#undef END_ENUM_XML +#undef END_NODE_XML #undef SUB_NODE_XML #undef SUB_NODE_SEQUENCE_XML #undef SUB_NODE_OPT_XML diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h index 4e907e1965ea..380a1dd224af 100644 --- a/include/clang/Frontend/TextDiagnosticBuffer.h +++ b/include/clang/Frontend/TextDiagnosticBuffer.h @@ -41,6 +41,10 @@ public: virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info); + + /// FlushDiagnostics - Flush the buffered diagnostics to an given + /// diagnostic engine. + void FlushDiagnostics(Diagnostic &Diags) const; }; } // end namspace clang diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index c2db4d357c51..52bf194883df 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -78,7 +78,7 @@ public: /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. - Lexer(FileID FID, Preprocessor &PP); + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, Preprocessor &PP); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text @@ -89,7 +89,8 @@ public: /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. - Lexer(FileID FID, const SourceManager &SM, const LangOptions &Features); + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, + const SourceManager &SM, const LangOptions &Features); /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 1c0036e3edcb..edd34b718969 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -329,9 +329,9 @@ public: void EnterMainSourceFile(); /// EnterSourceFile - Add a source file to the top of the include stack and - /// start lexing tokens from it instead of the current buffer. If isMainFile - /// is true, this is the main file for the translation unit. - void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); + /// start lexing tokens from it instead of the current buffer. Return true + /// on failure. + bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); /// EnterMacro - Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. Args specifies the diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3d3232b6f68e..fc56cc68476e 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -203,11 +203,15 @@ public: /// this occurs when deriving from "std::vector<T>::allocator_type", where T /// is a template parameter. /// + /// \param ObjectType if we're checking whether an identifier is a type + /// within a C++ member access expression, this will be the type of the + /// /// \returns the type referred to by this identifier, or NULL if the type /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS = 0, - bool isClassName = false) = 0; + bool isClassName = false, + TypeTy *ObjectType = 0) = 0; /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If @@ -668,6 +672,9 @@ public: return StmtEmpty(); } + virtual void ActOnForEachDeclStmt(DeclGroupPtrTy Decl) { + } + virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) { return OwningStmtResult(*this, Expr->release()); } @@ -698,14 +705,39 @@ public: return StmtEmpty(); } + /// \brief Parsed an "if" statement. + /// + /// \param IfLoc the location of the "if" keyword. + /// + /// \param CondVal if the "if" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "if" condition was parsed as a condition variable, + /// the condition variable itself. + /// + /// \param ThenVal the "then" statement. + /// + /// \param ElseLoc the location of the "else" keyword. + /// + /// \param ElseVal the "else" statement. virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + FullExprArg CondVal, + DeclPtrTy CondVar, + StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { return StmtEmpty(); } - virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) { + /// \brief Parsed the start of a "switch" statement. + /// + /// \param Cond if the "switch" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "switch" condition was parsed as a condition + /// variable, the condition variable itself. + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + DeclPtrTy CondVar) { return StmtEmpty(); } @@ -714,8 +746,18 @@ public: return StmtEmpty(); } + /// \brief Parsed a "while" statement. + /// + /// \param Cond if the "while" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "while" condition was parsed as a condition + /// variable, the condition variable itself. + /// + /// \param Body the body of the "while" loop. virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, StmtArg Body) { + FullExprArg Cond, DeclPtrTy CondVar, + StmtArg Body) { return StmtEmpty(); } virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, @@ -725,13 +767,36 @@ public: SourceLocation CondRParen) { return StmtEmpty(); } + + /// \brief Parsed a "for" statement. + /// + /// \param ForLoc the location of the "for" keyword. + /// + /// \param LParenLoc the location of the left parentheses. + /// + /// \param First the statement used to initialize the for loop. + /// + /// \param Second the condition to be checked during each iteration, if + /// that condition was parsed as an expression. + /// + /// \param SecondArg the condition variable to be checked during each + /// iterator, if that condition was parsed as a variable declaration. + /// + /// \param Third the expression that will be evaluated to "increment" any + /// values prior to the next iteration. + /// + /// \param RParenLoc the location of the right parentheses. + /// + /// \param Body the body of the "body" loop. virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - ExprArg Third, SourceLocation RParenLoc, + StmtArg First, FullExprArg Second, + DeclPtrTy SecondVar, FullExprArg Third, + SourceLocation RParenLoc, StmtArg Body) { return StmtEmpty(); } + virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, SourceLocation LParenLoc, StmtArg First, ExprArg Second, @@ -852,23 +917,12 @@ public: /// \brief The parser is entering a new expression evaluation context. /// /// \param NewContext is the new expression evaluation context. - /// - /// \returns the previous expression evaluation context. - virtual ExpressionEvaluationContext - PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { - return PotentiallyEvaluated; - } + virtual void + PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { } - /// \brief The parser is existing an expression evaluation context. - /// - /// \param OldContext the expression evaluation context that the parser is - /// leaving. - /// - /// \param NewContext the expression evaluation context that the parser is - /// returning to. + /// \brief The parser is exiting an expression evaluation context. virtual void - PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext) { } + PopExpressionEvaluationContext() { } // Primary Expressions. @@ -927,9 +981,10 @@ public: return move(Val); // Default impl returns operand. } - virtual OwningExprResult ActOnParenListExpr(SourceLocation L, + virtual OwningExprResult ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val) { + MultiExprArg Val, + TypeTy *TypeOfCast=0) { return ExprEmpty(); } @@ -1041,6 +1096,10 @@ public: return ExprEmpty(); } + virtual bool TypeIsVectorType(TypeTy *Ty) { + return false; + } + virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, ExprArg LHS, ExprArg RHS) { @@ -1371,15 +1430,22 @@ public: return ExprEmpty(); } - /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a - /// C++ if/switch/while/for statement. - /// e.g: "if (int x = f()) {...}" - virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, - SourceLocation StartLoc, - Declarator &D, - SourceLocation EqualLoc, - ExprArg AssignExprVal) { - return ExprEmpty(); + /// \brief Parsed a condition declaration in a C++ if, switch, or while + /// statement. + /// + /// This callback will be invoked after parsing the declaration of "x" in + /// + /// \code + /// if (int x = f()) { + /// // ... + /// } + /// \endcode + /// + /// \param S the scope of the if, switch, or while statement. + /// + /// \param D the declarator that that describes the variable being declared. + virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { + return DeclResult(); } /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the @@ -1470,6 +1536,7 @@ public: MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, + bool IsDefinition, bool Deleted = false) { return DeclPtrTy(); } @@ -1678,10 +1745,14 @@ public: /// \param ObjectType if this dependent template name occurs in the /// context of a member access expression, the type of the object being /// accessed. + /// + /// \param EnteringContext whether we are entering the context of this + /// template. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, - TypeTy *ObjectType) { + TypeTy *ObjectType, + bool EnteringContext) { return TemplateTy(); } @@ -2515,7 +2586,8 @@ public: /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName = false); + bool isClassName = false, + TypeTy *ObjectType = 0); /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. @@ -2578,21 +2650,15 @@ class EnterExpressionEvaluationContext { /// \brief The action object. Action &Actions; - /// \brief The previous expression evaluation context. - Action::ExpressionEvaluationContext PrevContext; - - /// \brief The current expression evaluation context. - Action::ExpressionEvaluationContext CurContext; - public: EnterExpressionEvaluationContext(Action &Actions, Action::ExpressionEvaluationContext NewContext) - : Actions(Actions), CurContext(NewContext) { - PrevContext = Actions.PushExpressionEvaluationContext(NewContext); + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext); } ~EnterExpressionEvaluationContext() { - Actions.PopExpressionEvaluationContext(CurContext, PrevContext); + Actions.PopExpressionEvaluationContext(); } }; diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 81bb3007baea..ecaa6aee470b 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -33,19 +33,22 @@ namespace clang { class AttributeList { IdentifierInfo *AttrName; SourceLocation AttrLoc; + IdentifierInfo *ScopeName; + SourceLocation ScopeLoc; IdentifierInfo *ParmName; SourceLocation ParmLoc; ActionBase::ExprTy **Args; unsigned NumArgs; AttributeList *Next; - bool DeclspecAttribute; + bool DeclspecAttribute, CXX0XAttribute; AttributeList(const AttributeList &); // DO NOT IMPLEMENT void operator=(const AttributeList &); // DO NOT IMPLEMENT public: AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, IdentifierInfo *ParmName, SourceLocation ParmLoc, ActionBase::ExprTy **args, unsigned numargs, - AttributeList *Next, bool declspec = false); + AttributeList *Next, bool declspec = false, bool cxx0x = false); ~AttributeList(); enum Kind { // Please keep this list alphabetized. @@ -56,7 +59,9 @@ public: AT_always_inline, AT_analyzer_noreturn, AT_annotate, + AT_base_check, AT_blocks, + AT_carries_dependency, AT_cdecl, AT_cleanup, AT_const, @@ -67,9 +72,11 @@ public: AT_dllimport, AT_ext_vector_type, AT_fastcall, + AT_final, AT_format, AT_format_arg, AT_gnu_inline, + AT_hiding, AT_malloc, AT_mode, AT_nodebug, @@ -80,6 +87,7 @@ public: AT_nothrow, AT_nsobject, AT_objc_exception, + AT_override, AT_cf_returns_retained, // Clang-specific. AT_ns_returns_retained, // Clang-specific. AT_objc_gc, @@ -106,8 +114,15 @@ public: IdentifierInfo *getName() const { return AttrName; } SourceLocation getLoc() const { return AttrLoc; } + + bool hasScope() const { return ScopeName; } + IdentifierInfo *getScopeName() const { return ScopeName; } + SourceLocation getScopeLoc() const { return ScopeLoc; } + IdentifierInfo *getParameterName() const { return ParmName; } + bool isDeclspecAttribute() const { return DeclspecAttribute; } + bool isCXX0XAttribute() const { return CXX0XAttribute; } Kind getKind() const { return getKind(getName()); } static Kind getKind(const IdentifierInfo *Name); @@ -181,6 +196,22 @@ inline AttributeList* addAttributeLists (AttributeList *Left, return Left; } +/// CXX0XAttributeList - A wrapper around a C++0x attribute list. +/// Stores, in addition to the list proper, whether or not an actual list was +/// (as opposed to an empty list, which may be ill-formed in some places) and +/// the source range of the list. +struct CXX0XAttributeList { + AttributeList *AttrList; + SourceRange Range; + bool HasAttr; + CXX0XAttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) + : AttrList(attrList), Range(range), HasAttr (hasAttr) { + } + CXX0XAttributeList () + : AttrList(0), Range(), HasAttr(false) { + } +}; + } // end namespace clang #endif diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 7e7d0b3f28e8..fe899b3fdb17 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -484,6 +484,8 @@ public: IK_OperatorFunctionId, /// \brief A conversion function name, e.g., operator int. IK_ConversionFunctionId, + /// \brief A user-defined literal name, e.g., operator "" _i. + IK_LiteralOperatorId, /// \brief A constructor name. IK_ConstructorName, /// \brief A destructor name. @@ -495,7 +497,8 @@ public: /// \brief Anonymous union that holds extra data associated with the /// parsed unqualified-id. union { - /// \brief When Kind == IK_Identifier, the parsed identifier. + /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind + /// == IK_UserLiteralId, the identifier suffix. IdentifierInfo *Identifier; /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator @@ -607,6 +610,22 @@ public: EndLocation = EndLoc; ConversionFunctionId = Ty; } + + /// \brief Specific that this unqualified-id was parsed as a + /// literal-operator-id. + /// + /// \param Id the parsed identifier. + /// + /// \param OpLoc the location of the 'operator' keyword. + /// + /// \param IdLoc the location of the identifier. + void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, + SourceLocation IdLoc) { + Kind = IK_LiteralOperatorId; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = OpLoc; + EndLocation = IdLoc; + } /// \brief Specify that this unqualified-id was parsed as a constructor name. /// diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f7ccccac0952..81a80ebcbc61 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -24,6 +24,7 @@ namespace clang { class AttributeList; + struct CXX0XAttributeList; class PragmaHandler; class Scope; class DiagnosticBuilder; @@ -753,10 +754,10 @@ private: //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. - DeclGroupPtrTy ParseExternalDeclaration(); + DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr); bool isDeclarationAfterDeclarator(); bool isStartOfFunctionDefinition(); - DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr, AccessSpecifier AS = AS_none); DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, @@ -832,10 +833,10 @@ private: OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - bool parseParenAsExprList); + TypeTy *TypeOfCast); OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, - bool parseParenAsExprList = false); + TypeTy *TypeOfCast = 0); OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS); OwningExprResult ParseSizeofAlignofExpression(); OwningExprResult ParseBuiltinPrimaryExpression(); @@ -865,7 +866,7 @@ private: }; OwningExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool parseAsExprList, + TypeTy *TypeOfCast, TypeTy *&CastTy, SourceLocation &RParenLoc); @@ -933,8 +934,8 @@ private: SourceLocation Start); //===--------------------------------------------------------------------===// - // C++ if/switch/while/for condition expression. - OwningExprResult ParseCXXCondition(); + // C++ if/switch/while condition expression. + bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult); //===--------------------------------------------------------------------===// // C++ types @@ -994,24 +995,23 @@ private: return ParseStatementOrDeclaration(true); } OwningStmtResult ParseStatementOrDeclaration(bool OnlyStatement = false); - OwningStmtResult ParseLabeledStatement(); - OwningStmtResult ParseCaseStatement(); - OwningStmtResult ParseDefaultStatement(); - OwningStmtResult ParseCompoundStatement(bool isStmtExpr = false); + OwningStmtResult ParseLabeledStatement(AttributeList *Attr); + OwningStmtResult ParseCaseStatement(AttributeList *Attr); + OwningStmtResult ParseDefaultStatement(AttributeList *Attr); + OwningStmtResult ParseCompoundStatement(AttributeList *Attr, + bool isStmtExpr = false); OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false); - bool ParseParenExprOrCondition(OwningExprResult &CondExp, - bool OnlyAllowCondition = false, - SourceLocation *LParenLoc = 0, - SourceLocation *RParenLoc = 0); - OwningStmtResult ParseIfStatement(); - OwningStmtResult ParseSwitchStatement(); - OwningStmtResult ParseWhileStatement(); - OwningStmtResult ParseDoStatement(); - OwningStmtResult ParseForStatement(); - OwningStmtResult ParseGotoStatement(); - OwningStmtResult ParseContinueStatement(); - OwningStmtResult ParseBreakStatement(); - OwningStmtResult ParseReturnStatement(); + bool ParseParenExprOrCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult); + OwningStmtResult ParseIfStatement(AttributeList *Attr); + OwningStmtResult ParseSwitchStatement(AttributeList *Attr); + OwningStmtResult ParseWhileStatement(AttributeList *Attr); + OwningStmtResult ParseDoStatement(AttributeList *Attr); + OwningStmtResult ParseForStatement(AttributeList *Attr); + OwningStmtResult ParseGotoStatement(AttributeList *Attr); + OwningStmtResult ParseContinueStatement(AttributeList *Attr); + OwningStmtResult ParseBreakStatement(AttributeList *Attr); + OwningStmtResult ParseReturnStatement(AttributeList *Attr); OwningStmtResult ParseAsmStatement(bool &msAsm); OwningStmtResult FuzzyParseMicrosoftAsmStatement(); bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, @@ -1021,7 +1021,7 @@ private: //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks - OwningStmtResult ParseCXXTryBlock(); + OwningStmtResult ParseCXXTryBlock(AttributeList *Attr); OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); OwningStmtResult ParseCXXCatchBlock(); @@ -1045,9 +1045,11 @@ private: DSC_class // class context, enables 'friend' }; - DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd, + CXX0XAttributeList Attr); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd = 0); @@ -1217,11 +1219,14 @@ private: void ParseBlockId(); // EndLoc, if non-NULL, is filled with the location of the last token of // the attribute list. - AttributeList *ParseAttributes(SourceLocation *EndLoc = 0); + CXX0XAttributeList ParseCXX0XAttributes(SourceLocation *EndLoc = 0); + AttributeList *ParseGNUAttributes(SourceLocation *EndLoc = 0); AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0); AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0); void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); + + OwningExprResult ParseCXX0XAlignArgument(SourceLocation Start); /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is @@ -1265,7 +1270,8 @@ private: typedef void (Parser::*DirectDeclParseFunction)(Declarator&); void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); - void ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed = true); + void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, + bool CXX0XAttributesAllowed = true); void ParseDirectDeclarator(Declarator &D); void ParseParenDeclarator(Declarator &D); void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, @@ -1278,12 +1284,17 @@ private: //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] + bool isCXX0XAttributeSpecifier(bool FullLookahead = false, + tok::TokenKind *After = 0); + DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); DeclPtrTy ParseLinkage(unsigned Context); DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + CXX0XAttributeList Attrs); DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); @@ -1353,6 +1364,7 @@ private: SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, TemplateParameterList &TemplateParams); + bool isStartOfTemplateTypeParameter(); DeclPtrTy ParseTemplateParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTypeParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index ed747613c385..84c179f789d1 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -209,7 +209,8 @@ public: void Serialize(llvm::raw_ostream &OS) const; /// \brief Deserialize a code-completion string from the given string. - static CodeCompletionString *Deserialize(llvm::StringRef &Str); + static CodeCompletionString *Deserialize(const char *&Str, + const char *StrEnd); }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, @@ -221,6 +222,10 @@ class CodeCompleteConsumer { protected: /// \brief Whether to include macros in the code-completion results. bool IncludeMacros; + + /// \brief Whether the output format for the code-completion consumer is + /// binary. + bool OutputIsBinary; public: /// \brief Captures a result of code completion. @@ -394,17 +399,20 @@ public: Sema &S) const; }; - CodeCompleteConsumer() : IncludeMacros(false) { } + CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { } - explicit CodeCompleteConsumer(bool IncludeMacros) - : IncludeMacros(IncludeMacros) { } + CodeCompleteConsumer(bool IncludeMacros, bool OutputIsBinary) + : IncludeMacros(IncludeMacros), OutputIsBinary(OutputIsBinary) { } /// \brief Whether the code-completion consumer wants to see macros. bool includeMacros() const { return IncludeMacros; } + + /// \brief Determine whether the output of this consumer is binary. + bool isOutputBinary() const { return OutputIsBinary; } /// \brief Deregisters and destroys this code-completion consumer. virtual ~CodeCompleteConsumer(); - + /// \name Code-completion callbacks //@{ /// \brief Process the finalized code-completion results. @@ -436,7 +444,7 @@ public: /// results to the given raw output stream. PrintingCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros, false), OS(OS) { } /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, @@ -458,7 +466,7 @@ public: /// results to the given raw output stream in a format readable to the CIndex /// library. CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros, true), OS(OS) { } /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index dc13e7f4688c..6c9ecf089b98 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -48,6 +48,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { ObjCIdRedefinitionType = QualType(); ObjCClassRedefinitionType = QualType(); + ObjCSelRedefinitionType = QualType(); if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); InitBuiltinTypes(); @@ -220,10 +221,12 @@ void ASTContext::InitBuiltinTypes() { // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). ObjCIdTypedefType = QualType(); ObjCClassTypedefType = QualType(); + ObjCSelTypedefType = QualType(); - // Builtin types for 'id' and 'Class'. + // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); + InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); ObjCConstantStringType = QualType(); @@ -517,18 +520,23 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { /// getDeclAlignInBytes - Return a conservative estimate of the alignment of the /// specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. -unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { +/// If @p RefAsPointee, references are treated like their underlying type +/// (for alignof), else they're treated like pointers (for CodeGen). +unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { unsigned Align = Target.getCharWidth(); if (const AlignedAttr* AA = D->getAttr<AlignedAttr>()) - Align = std::max(Align, AA->getAlignment()); + Align = std::max(Align, AA->getMaxAlignment()); if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - Align = Target.getPointerAlign(AS); - } else if (!T->isIncompleteType() && !T->isFunctionType()) { + if (RefAsPointee) + T = RT->getPointeeType(); + else + T = getPointerType(RT->getPointeeType()); + } + if (!T->isIncompleteType() && !T->isFunctionType()) { // Incomplete or function types default to 1. while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T)) T = cast<ArrayType>(T)->getElementType(); @@ -687,19 +695,21 @@ ASTContext::getTypeInfo(const Type *T) { Align = Target.getPointerAlign(AS); break; } + case Type::LValueReference: + case Type::RValueReference: { + // alignof and sizeof should never enter this code path here, so we go + // the pointer route. + unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } case Type::Pointer: { unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace(); Width = Target.getPointerWidth(AS); Align = Target.getPointerAlign(AS); break; } - case Type::LValueReference: - case Type::RValueReference: - // "When applied to a reference or a reference type, the result is the size - // of the referenced type." C++98 5.3.3p2: expr.sizeof. - // FIXME: This is wrong for struct layout: a reference in a struct has - // pointer size. - return getTypeInfo(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { // FIXME: This is ABI dependent. We use the Itanium C++ ABI. // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers @@ -761,7 +771,8 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) { - Align = Aligned->getAlignment(); + Align = std::max(Aligned->getMaxAlignment(), + getTypeAlign(Typedef->getUnderlyingType().getTypePtr())); Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr()); } else return getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); @@ -1460,16 +1471,24 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals, SourceRange Brackets) { - assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && + assert((!NumElts || NumElts->isTypeDependent() || + NumElts->isValueDependent()) && "Size must be type- or value-dependent!"); - llvm::FoldingSetNodeID ID; - DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, - EltTypeQuals, NumElts); - void *InsertPos = 0; - DependentSizedArrayType *Canon - = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentSizedArrayType *Canon = 0; + + if (NumElts) { + // Dependently-sized array types that do not have a specified + // number of elements will have their sizes deduced from an + // initializer. + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, + EltTypeQuals, NumElts); + + Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + } + DependentSizedArrayType *New; if (Canon) { // We already have a canonical version of this array type; use it as @@ -1483,7 +1502,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, New = new (*this, TypeAlignment) DependentSizedArrayType(*this, EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); - DependentSizedArrayTypes.InsertNode(New, InsertPos); + + if (NumElts) + DependentSizedArrayTypes.InsertNode(New, InsertPos); } else { QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, ASM, EltTypeQuals, @@ -1818,9 +1839,10 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, - const TemplateArgumentLoc *Args, - unsigned NumArgs, + const TemplateArgumentListInfo &Args, QualType Canon) { + unsigned NumArgs = Args.size(); + llvm::SmallVector<TemplateArgument, 4> ArgVec; ArgVec.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2320,6 +2342,22 @@ CanQualType ASTContext::getCanonicalType(QualType T) { VAT->getBracketsRange())); } +DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { + if (TemplateDecl *TD = Name.getAsTemplateDecl()) + return TD->getDeclName(); + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + if (DTN->isIdentifier()) { + return DeclarationNames.getIdentifier(DTN->getIdentifier()); + } else { + return DeclarationNames.getCXXOperatorName(DTN->getOperator()); + } + } + + assert(Name.getAsOverloadedFunctionDecl()); + return Name.getAsOverloadedFunctionDecl()->getDeclName(); +} + TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { // If this template name refers to a template, the canonical // template name merely stores the template itself. @@ -3374,9 +3412,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, false); return; } - + if (const PointerType *PT = T->getAs<PointerType>()) { + if (PT->isObjCSelType()) { + S += ':'; + return; + } QualType PointeeTy = PT->getPointeeType(); + bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -3407,10 +3450,6 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S.replace(S.end()-2, S.end(), replace); } } - if (isObjCSelType(PointeeTy)) { - S += ':'; - return; - } if (PointeeTy->isCharType()) { // char pointer types should be encoded as '*' unless it is a @@ -3633,21 +3672,7 @@ void ASTContext::setObjCIdType(QualType T) { } void ASTContext::setObjCSelType(QualType T) { - ObjCSelType = T; - - const TypedefType *TT = T->getAs<TypedefType>(); - if (!TT) - return; - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>(); - if (!ptr) - return; - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - if (!rec) - return; - SelStructType = rec; + ObjCSelTypedefType = T; } void ASTContext::setObjCProtoType(QualType QT) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bdc804722c41..572d76ff72d2 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -211,6 +211,203 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, // NamedDecl Implementation //===----------------------------------------------------------------------===// +static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { + assert(D->getDeclContext()->getLookupContext()->isFileContext() && + "Not a name having namespace scope"); + ASTContext &Context = D->getASTContext(); + + // C++ [basic.link]p3: + // A name having namespace scope (3.3.6) has internal linkage if it + // is the name of + // - an object, reference, function or function template that is + // explicitly declared static; or, + // (This bullet corresponds to C99 6.2.2p3.) + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + // Explicitly declared static. + if (Var->getStorageClass() == VarDecl::Static) + return NamedDecl::InternalLinkage; + + // - an object or reference that is explicitly declared const + // and neither explicitly declared extern nor previously + // declared to have external linkage; or + // (there is no equivalent in C99) + if (Context.getLangOptions().CPlusPlus && + Var->getType().isConstant(Context) && + Var->getStorageClass() != VarDecl::Extern && + Var->getStorageClass() != VarDecl::PrivateExtern) { + bool FoundExtern = false; + for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); + PrevVar && !FoundExtern; + PrevVar = PrevVar->getPreviousDeclaration()) + if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage) + FoundExtern = true; + + if (!FoundExtern) + return NamedDecl::InternalLinkage; + } + } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { + const FunctionDecl *Function = 0; + if (const FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(D)) + Function = FunTmpl->getTemplatedDecl(); + else + Function = cast<FunctionDecl>(D); + + // Explicitly declared static. + if (Function->getStorageClass() == FunctionDecl::Static) + return NamedDecl::InternalLinkage; + } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + // - a data member of an anonymous union. + if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) + return NamedDecl::InternalLinkage; + } + + // C++ [basic.link]p4: + + // A name having namespace scope has external linkage if it is the + // name of + // + // - an object or reference, unless it has internal linkage; or + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (!Context.getLangOptions().CPlusPlus && + (Var->getStorageClass() == VarDecl::Extern || + Var->getStorageClass() == VarDecl::PrivateExtern)) { + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { + if (NamedDecl::Linkage L = PrevVar->getLinkage()) + return L; + } + } + + // C99 6.2.2p5: + // If the declaration of an identifier for an object has file + // scope and no storage-class specifier, its linkage is + // external. + return NamedDecl::ExternalLinkage; + } + + // - a function, unless it has internal linkage; or + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + // C99 6.2.2p5: + // If the declaration of an identifier for a function has no + // storage-class specifier, its linkage is determined exactly + // as if it were declared with the storage-class specifier + // extern. + if (!Context.getLangOptions().CPlusPlus && + (Function->getStorageClass() == FunctionDecl::Extern || + Function->getStorageClass() == FunctionDecl::PrivateExtern || + Function->getStorageClass() == FunctionDecl::None)) { + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { + if (NamedDecl::Linkage L = PrevFunc->getLinkage()) + return L; + } + } + + return NamedDecl::ExternalLinkage; + } + + // - a named class (Clause 9), or an unnamed class defined in a + // typedef declaration in which the class has the typedef name + // for linkage purposes (7.1.3); or + // - a named enumeration (7.2), or an unnamed enumeration + // defined in a typedef declaration in which the enumeration + // has the typedef name for linkage purposes (7.1.3); or + if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) + if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) + return NamedDecl::ExternalLinkage; + + // - an enumerator belonging to an enumeration with external linkage; + if (isa<EnumConstantDecl>(D)) + if (cast<NamedDecl>(D->getDeclContext())->getLinkage() + == NamedDecl::ExternalLinkage) + return NamedDecl::ExternalLinkage; + + // - a template, unless it is a function template that has + // internal linkage (Clause 14); + if (isa<TemplateDecl>(D)) + return NamedDecl::ExternalLinkage; + + // - a namespace (7.3), unless it is declared within an unnamed + // namespace. + if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) + return NamedDecl::ExternalLinkage; + + return NamedDecl::NoLinkage; +} + +NamedDecl::Linkage NamedDecl::getLinkage() const { + // Handle linkage for namespace-scope names. + if (getDeclContext()->getLookupContext()->isFileContext()) + if (Linkage L = getLinkageForNamespaceScopeDecl(this)) + return L; + + // C++ [basic.link]p5: + // In addition, a member function, static data member, a named + // class or enumeration of class scope, or an unnamed class or + // enumeration defined in a class-scope typedef declaration such + // that the class or enumeration has the typedef name for linkage + // purposes (7.1.3), has external linkage if the name of the class + // has external linkage. + if (getDeclContext()->isRecord() && + (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) || + (isa<TagDecl>(this) && + (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) && + cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage) + return ExternalLinkage; + + // C++ [basic.link]p6: + // The name of a function declared in block scope and the name of + // an object declared by a block scope extern declaration have + // linkage. If there is a visible declaration of an entity with + // linkage having the same name and type, ignoring entities + // declared outside the innermost enclosing namespace scope, the + // block scope declaration declares that same entity and receives + // the linkage of the previous declaration. If there is more than + // one such matching entity, the program is ill-formed. Otherwise, + // if no matching entity is found, the block scope entity receives + // external linkage. + if (getLexicalDeclContext()->isFunctionOrMethod()) { + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { + if (Function->getPreviousDeclaration()) + if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) + return L; + + return ExternalLinkage; + } + + if (const VarDecl *Var = dyn_cast<VarDecl>(this)) + if (Var->getStorageClass() == VarDecl::Extern || + Var->getStorageClass() == VarDecl::PrivateExtern) { + if (Var->getPreviousDeclaration()) + if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) + return L; + + return ExternalLinkage; + } + } + + // C++ [basic.link]p6: + // Names not covered by these rules have no linkage. + return NoLinkage; +} + std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getLangOptions()); } @@ -300,13 +497,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - if (const VarDecl *VD = dyn_cast<VarDecl>(this)) - return VD->hasExternalStorage() || VD->isFileVarDecl(); - - if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this)) - return true; - - return false; + return getLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDecl() { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 831f552489f9..2dcd80b01fcc 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -55,8 +55,7 @@ const char *DeclContext::getDeclKindName() const { } bool Decl::CollectingStats(bool Enable) { - if (Enable) - StatSwitch = true; + if (Enable) StatSwitch = true; return StatSwitch; } @@ -119,7 +118,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { OS << Message; - if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) + if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) OS << " '" << DN->getQualifiedNameAsString() << '\''; OS << '\n'; } @@ -130,9 +129,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { // Out-of-line virtual method providing a home for Decl. Decl::~Decl() { - if (isOutOfSemaDC()) - delete getMultipleDC(); - assert(!HasAttrs && "attributes should have been freed by Destroy"); } @@ -148,7 +144,7 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { return; if (isInSemaDC()) { - MultipleDC *MDC = new MultipleDC(); + MultipleDC *MDC = new (getASTContext()) MultipleDC(); MDC->SemanticDC = getDeclContext(); MDC->LexicalDC = DC; DeclCtx = MDC; @@ -343,9 +339,12 @@ void Decl::Destroy(ASTContext &C) { N = Tmp; } + if (isOutOfSemaDC()) + delete (C) getMultipleDC(); + this->~Decl(); C.Deallocate((void *)this); -#endif +#endif } Decl *Decl::castFromDeclContext (const DeclContext *D) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a21c93ffcdc9..40019880074a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -36,8 +36,6 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), - Conversions(DC, DeclarationName()), - VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -299,14 +297,11 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, void CXXRecordDecl::collectConversionFunctions( - llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) + llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const { - OverloadedFunctionDecl *TopConversions = getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - TFunc = TopConversions->function_begin(), - TFuncEnd = TopConversions->function_end(); - TFunc != TFuncEnd; ++TFunc) { - NamedDecl *TopConv = TFunc->get(); + const UnresolvedSet *Cs = getConversionFunctions(); + for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + NamedDecl *TopConv = *I; CanQualType TConvType; if (FunctionTemplateDecl *TConversionTemplate = dyn_cast<FunctionTemplateDecl>(TopConv)) @@ -336,14 +331,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Cs = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - NamedDecl *Conv = Func->get(); + for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. CanQualType ConvType; @@ -405,8 +397,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -OverloadedFunctionDecl * -CXXRecordDecl::getVisibleConversionFunctions() { +const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) return &Conversions; @@ -425,26 +416,26 @@ void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - VisibleConversions.addOverload(ConvDecl); + VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - VisibleConversions.addOverload(ConvDecl); + VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - Conversions.addOverload(ConvDecl); + Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - Conversions.addOverload(ConvDecl); + Conversions.addDecl(ConvDecl); } CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { @@ -895,12 +886,21 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Used, + 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); } +NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { + if (NamespaceAliasDecl *NA = + dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace)) + return NA->getNamespace(); + return cast_or_null<NamespaceDecl>(NominatedNamespace); +} + NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation AliasLoc, @@ -909,6 +909,8 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, NamedDecl *Namespace) { + if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace)) + Namespace = NS->getOriginalNamespace(); return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, Qualifier, IdentLoc, Namespace); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 131de8b2e11b..a5982cfd97f1 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -18,19 +18,18 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> { + class DeclPrinter : public DeclVisitor<DeclPrinter> { llvm::raw_ostream &Out; ASTContext &Context; PrintingPolicy Policy; unsigned Indentation; - llvm::raw_ostream& Indent(); + llvm::raw_ostream& Indent() { return Indent(Indentation); } + llvm::raw_ostream& Indent(unsigned Indentation); void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); void Print(AccessSpecifier AS); @@ -154,8 +153,8 @@ void Decl::dump() const { print(llvm::errs()); } -llvm::raw_ostream& DeclPrinter::Indent() { - for (unsigned i = 0; i < Indentation; ++i) +llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) { + for (unsigned i = 0; i != Indentation; ++i) Out << " "; return Out; } @@ -205,6 +204,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { AccessSpecifier AS = D->getAccess(); if (AS != CurAS) { + if (Indent) + this->Indent(Indentation - Policy.Indentation); Print(AS); Out << ":\n"; CurAS = AS; @@ -502,7 +503,7 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespace()->getNameAsString(); + Out << D->getNominatedNamespaceAsWritten()->getNameAsString(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 0c14714812f5..902339e1efcf 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -214,9 +214,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), - NTTP->getLocation(), - NTTP->getType()->isDependentType(), - /*Value-dependent=*/true); + NTTP->getLocation()); TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); @@ -453,8 +451,9 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, - TemplateArgumentLoc *ArgInfos, unsigned N, + const TemplateArgumentListInfo &ArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl) { + unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; for (unsigned I = 0; I != N; ++I) ClonedArgs[I] = ArgInfos[I]; diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 1ff068c9862c..3471657b6523 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -50,6 +50,17 @@ public: void *FETokenInfo; }; +/// CXXLiberalOperatorName - Contains the actual identifier that makes up the +/// name. +/// +/// This identifier is stored here rather than directly in DeclarationName so as +/// to allow Objective-C selectors, which are about a million times more common, +/// to consume minimal memory. +class CXXLiteralOperatorIdName : public DeclarationNameExtra { +public: + IdentifierInfo *ID; +}; + bool operator<(DeclarationName LHS, DeclarationName RHS) { if (LHS.getNameKind() != RHS.getNameKind()) return LHS.getNameKind() < RHS.getNameKind(); @@ -89,6 +100,10 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { case DeclarationName::CXXOperatorName: return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator(); + + case DeclarationName::CXXLiteralOperatorName: + return LHS.getCXXLiteralIdentifier()->getName() < + RHS.getCXXLiteralIdentifier()->getName(); case DeclarationName::CXXUsingDirective: return false; @@ -143,6 +158,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; + case DeclarationNameExtra::CXXLiteralOperator: + return CXXLiteralOperatorName; + case DeclarationNameExtra::CXXUsingDirective: return CXXUsingDirective; @@ -208,6 +226,10 @@ std::string DeclarationName::getAsString() const { return Result; } + case CXXLiteralOperatorName: { + return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName()); + } + case CXXConversionFunctionName: { std::string Result = "operator "; QualType Type = getCXXNameType(); @@ -242,6 +264,13 @@ OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { } } +IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const { + if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName()) + return CXXLit->ID; + else + return 0; +} + Selector DeclarationName::getObjCSelector() const { switch (getNameKind()) { case ObjCZeroArgSelector: @@ -273,6 +302,9 @@ void *DeclarationName::getFETokenInfoAsVoid() const { case CXXOperatorName: return getAsCXXOperatorIdName()->FETokenInfo; + case CXXLiteralOperatorName: + return getCXXLiteralIdentifier()->getFETokenInfo<void>(); + default: assert(false && "Declaration name has no FETokenInfo"); } @@ -295,6 +327,10 @@ void DeclarationName::setFETokenInfo(void *T) { getAsCXXOperatorIdName()->FETokenInfo = T; break; + case CXXLiteralOperatorName: + getCXXLiteralIdentifier()->setFETokenInfo(T); + break; + default: assert(false && "Declaration name has no FETokenInfo"); } @@ -390,6 +426,14 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { return DeclarationName(&CXXOperatorNames[(unsigned)Op]); } +DeclarationName +DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { + CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName; + LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; + LiteralName->ID = II; + return DeclarationName(LiteralName); +} + unsigned llvm::DenseMapInfo<clang::DeclarationName>:: getHashValue(clang::DeclarationName N) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 90b50c61f989..624a620b9fbb 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -31,49 +31,104 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// +void ExplicitTemplateArgumentList::initializeFrom( + const TemplateArgumentListInfo &Info) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); +} + +void ExplicitTemplateArgumentList::copyInto( + TemplateArgumentListInfo &Info) const { + Info.setLAngleLoc(LAngleLoc); + Info.setRAngleLoc(RAngleLoc); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + Info.addArgument(getTemplateArgs()[I]); +} + +std::size_t ExplicitTemplateArgumentList::sizeFor( + const TemplateArgumentListInfo &Info) { + return sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgumentLoc) * Info.size(); +} + +void DeclRefExpr::computeDependence() { + TypeDependent = false; + ValueDependent = false; + + NamedDecl *D = getDecl(); + + // (TD) C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // + // and + // + // (VD) C++ [temp.dep.constexpr]p2: + // An identifier is value-dependent if it is: + + // (TD) - an identifier that was declared with dependent type + // (VD) - a name declared with a dependent type, + if (getType()->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + } + // (TD) - a conversion-function-id that specifies a dependent type + else if (D->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + D->getDeclName().getCXXNameType()->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + } + // (TD) - a template-id that is dependent, + else if (hasExplicitTemplateArgumentList() && + TemplateSpecializationType::anyDependentTemplateArguments( + getTemplateArgs(), + getNumTemplateArgs())) { + TypeDependent = true; + ValueDependent = true; + } + // (VD) - the name of a non-type template parameter, + else if (isa<NonTypeTemplateParmDecl>(D)) + ValueDependent = true; + // (VD) - a constant with integral or enumeration type and is + // initialized with an expression that is value-dependent. + else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->getType()->isIntegralType() && + Var->getType().getCVRQualifiers() == Qualifiers::Const && + Var->getInit() && + Var->getInit()->isValueDependent()) + ValueDependent = true; + } + // (TD) - a nested-name-specifier or a qualified-id that names a + // member of an unknown specialization. + // (handled by DependentScopeDeclRefExpr) +} + DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD) - : Expr(DeclRefExprClass, T, TD, VD), + const TemplateArgumentListInfo *TemplateArgs, + QualType T) + : Expr(DeclRefExprClass, T, false, false), DecoratedD(D, (Qualifier? HasQualifierFlag : 0) | - (HasExplicitTemplateArgumentList? - HasExplicitTemplateArgumentListFlag : 0)), + (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), Loc(NameLoc) { + assert(!isa<OverloadedFunctionDecl>(D)); if (Qualifier) { NameQualifier *NQ = getNameQualifier(); NQ->NNS = Qualifier; NQ->Range = QualifierRange; } - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = LAngleLoc; - ETemplateArgs->RAngleLoc = RAngleLoc; - ETemplateArgs->NumTemplateArgs = NumExplicitTemplateArgs; - - TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < NumExplicitTemplateArgs; ++I) - new (TemplateArgs + I) TemplateArgumentLoc(ExplicitTemplateArgs[I]); - } -} + if (TemplateArgs) + getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - NamedDecl *D, - SourceLocation NameLoc, - QualType T, bool TD, bool VD) { - return Create(Context, Qualifier, QualifierRange, D, NameLoc, - false, SourceLocation(), 0, 0, SourceLocation(), - T, TD, VD); + computeDependence(); } DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, @@ -81,28 +136,18 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD) { + QualType T, + const TemplateArgumentListInfo *TemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (Qualifier != 0) Size += sizeof(NameQualifier); - if (HasExplicitTemplateArgumentList) - Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs; + if (TemplateArgs) + Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>()); return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc, - HasExplicitTemplateArgumentList, - LAngleLoc, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - RAngleLoc, - T, TD, VD); + TemplateArgs, T); } SourceRange DeclRefExpr::getSourceRange() const { @@ -427,15 +472,13 @@ QualType CallExpr::getCallReturnType() const { MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, - SourceLocation l, bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, unsigned numtargs, - SourceLocation rangle, QualType ty) + SourceLocation l, const TemplateArgumentListInfo *targs, + QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent() || (qual && qual->isDependent()), base->isValueDependent() || (qual && qual->isDependent())), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) { + HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) { // Initialize the qualifier, if any. if (HasQualifier) { NameQualifier *NQ = getMemberQualifier(); @@ -444,17 +487,8 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, } // Initialize the explicit template argument list, if any. - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = langle; - ETemplateArgs->RAngleLoc = rangle; - ETemplateArgs->NumTemplateArgs = numtargs; - - TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < numtargs; ++I) - new (TemplateArgs + I) TemplateArgumentLoc(targs[I]); - } + if (targs) + getExplicitTemplateArgumentList()->initializeFrom(*targs); } MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, @@ -462,24 +496,18 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, - unsigned numtargs, - SourceLocation rangle, + const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); if (qual != 0) Size += sizeof(NameQualifier); - if (has_explicit) - Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * numtargs; + if (targs) + Size += ExplicitTemplateArgumentList::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, - has_explicit, langle, targs, numtargs, rangle, - ty); + targs, ty); } const char *CastExpr::getCastKindName() const { @@ -528,6 +556,8 @@ const char *CastExpr::getCastKindName() const { return "FloatingToIntegral"; case CastExpr::CK_FloatingCast: return "FloatingCast"; + case CastExpr::CK_MemberPointerToBoolean: + return "MemberPointerToBoolean"; } assert(0 && "Unhandled cast kind!"); @@ -640,12 +670,17 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) - : Expr(InitListExprClass, QualType(), - hasAnyTypeDependentArguments(initExprs, numInits), - hasAnyValueDependentArguments(initExprs, numInits)), + : Expr(InitListExprClass, QualType(), false, false), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), - UnionFieldInit(0), HadArrayRangeDesignator(false) { - + UnionFieldInit(0), HadArrayRangeDesignator(false) +{ + for (unsigned I = 0; I != numInits; ++I) { + if (initExprs[I]->isTypeDependent()) + TypeDependent = true; + if (initExprs[I]->isValueDependent()) + ValueDependent = true; + } + InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); } @@ -1091,10 +1126,10 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case PredefinedExprClass: return LV_Valid; + case UnresolvedLookupExprClass: + return LV_Valid; case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx); - case CXXConditionDeclExprClass: - return LV_Valid; case CStyleCastExprClass: case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: @@ -1141,18 +1176,6 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; } - case TemplateIdRefExprClass: { - const TemplateIdRefExpr *TID = cast<TemplateIdRefExpr>(this); - TemplateName Template = TID->getTemplateName(); - NamedDecl *ND = Template.getAsTemplateDecl(); - if (!ND) - ND = Template.getAsOverloadedFunctionDecl(); - if (ND && DeclCanBeLvalue(ND, Ctx)) - return LV_Valid; - - break; - } - default: break; } @@ -1491,19 +1514,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXNullPtrLiteralExprClass: case Expr::CXXThisExprClass: case Expr::CXXThrowExprClass: - case Expr::CXXConditionDeclExprClass: // FIXME: is this correct? case Expr::CXXNewExprClass: case Expr::CXXDeleteExprClass: case Expr::CXXPseudoDestructorExprClass: - case Expr::UnresolvedFunctionNameExprClass: - case Expr::UnresolvedDeclRefExprClass: - case Expr::TemplateIdRefExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::CXXExprWithTemporariesClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: - case Expr::CXXUnresolvedMemberExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCMessageExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 0ba4608ee198..d1a0390a0a68 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -72,14 +72,6 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() { return child_iterator(); } -// CXXConditionDeclExpr -Stmt::child_iterator CXXConditionDeclExpr::child_begin() { - return getVarDecl(); -} -Stmt::child_iterator CXXConditionDeclExpr::child_end() { - return child_iterator(); -} - // CXXNewExpr CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, @@ -121,11 +113,45 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { return &Base + 1; } -// UnresolvedFunctionNameExpr -Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { +// UnresolvedLookupExpr +UnresolvedLookupExpr * +UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, DeclarationName Name, + SourceLocation NameLoc, bool ADL, + const TemplateArgumentListInfo &Args) +{ + void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + + ExplicitTemplateArgumentList::sizeFor(Args)); + UnresolvedLookupExpr *ULE + = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + Dependent, Qualifier, QualifierRange, + Name, NameLoc, ADL, + /*Overload*/ true, + /*ExplicitTemplateArgs*/ true); + + reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args); + + return ULE; +} + +bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin, + NamedDecl * const *End, + const TemplateArgumentListInfo *Args) { + for (NamedDecl * const *I = Begin; I != End; ++I) + if ((*I)->getDeclContext()->isDependentContext()) + return true; + + if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args)) + return true; + + return false; +} + +Stmt::child_iterator UnresolvedLookupExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { +Stmt::child_iterator UnresolvedLookupExpr::child_end() { return child_iterator(); } // UnaryTypeTraitExpr @@ -136,72 +162,37 @@ Stmt::child_iterator UnaryTypeTraitExpr::child_end() { return child_iterator(); } -// UnresolvedDeclRefExpr -StmtIterator UnresolvedDeclRefExpr::child_begin() { - return child_iterator(); +// DependentScopeDeclRefExpr +DependentScopeDeclRefExpr * +DependentScopeDeclRefExpr::Create(ASTContext &C, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *Args) { + std::size_t size = sizeof(DependentScopeDeclRefExpr); + if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args); + void *Mem = C.Allocate(size); + + DependentScopeDeclRefExpr *DRE + = new (Mem) DependentScopeDeclRefExpr(C.DependentTy, + Qualifier, QualifierRange, + Name, NameLoc, + Args != 0); + + if (Args) + reinterpret_cast<ExplicitTemplateArgumentList*>(DRE+1) + ->initializeFrom(*Args); + + return DRE; } -StmtIterator UnresolvedDeclRefExpr::child_end() { +StmtIterator DependentScopeDeclRefExpr::child_begin() { return child_iterator(); } -TemplateIdRefExpr::TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) - : Expr(TemplateIdRefExprClass, T, - (Template.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, NumTemplateArgs)), - (Template.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, NumTemplateArgs))), - Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), - TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), - RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { - TemplateArgumentLoc *StoredTemplateArgs - = reinterpret_cast<TemplateArgumentLoc *> (this+1); - for (unsigned I = 0; I != NumTemplateArgs; ++I) - new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); -} - -TemplateIdRefExpr * -TemplateIdRefExpr::Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, SourceLocation RAngleLoc) { - void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + - sizeof(TemplateArgumentLoc) * NumTemplateArgs); - return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template, - TemplateNameLoc, LAngleLoc, TemplateArgs, - NumTemplateArgs, RAngleLoc); -} - -void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { - const TemplateArgumentLoc *TemplateArgs = getTemplateArgs(); - for (unsigned I = 0; I != NumTemplateArgs; ++I) - if (Expr *E = TemplateArgs[I].getArgument().getAsExpr()) - E->Destroy(Context); - this->~TemplateIdRefExpr(); - Context.Deallocate(this); -} - -Stmt::child_iterator TemplateIdRefExpr::child_begin() { - // FIXME: Walk the expressions in the template arguments (?) - return Stmt::child_iterator(); -} - -Stmt::child_iterator TemplateIdRefExpr::child_end() { - // FIXME: Walk the expressions in the template arguments (?) - return Stmt::child_iterator(); +StmtIterator DependentScopeDeclRefExpr::child_end() { + return child_iterator(); } bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { @@ -526,7 +517,7 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs); } -CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -534,33 +525,20 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) - : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + const TemplateArgumentListInfo *TemplateArgs) + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), Base(Base), IsArrow(IsArrow), - HasExplicitTemplateArgumentList(HasExplicitTemplateArgs), + HasExplicitTemplateArgumentList(TemplateArgs), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = LAngleLoc; - ETemplateArgs->RAngleLoc = RAngleLoc; - ETemplateArgs->NumTemplateArgs = NumTemplateArgs; - - TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < NumTemplateArgs; ++I) - new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); - } + if (TemplateArgs) + getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); } -CXXUnresolvedMemberExpr * -CXXUnresolvedMemberExpr::Create(ASTContext &C, +CXXDependentScopeMemberExpr * +CXXDependentScopeMemberExpr::Create(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -568,37 +546,79 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { - if (!HasExplicitTemplateArgs) - return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + const TemplateArgumentListInfo *TemplateArgs) { + if (!TemplateArgs) + return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, Member, MemberLoc); - void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + - sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * NumTemplateArgs, - llvm::alignof<CXXUnresolvedMemberExpr>()); - return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + std::size_t size = sizeof(CXXDependentScopeMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>()); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, Member, MemberLoc, - HasExplicitTemplateArgs, - LAngleLoc, - TemplateArgs, - NumTemplateArgs, - RAngleLoc); + TemplateArgs); +} + +Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { + return child_iterator(&Base); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { +Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { + return child_iterator(&Base + 1); +} + +UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName MemberName, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) + : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), + Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + HasExplicitTemplateArgs(TemplateArgs != 0), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + MemberName(MemberName), MemberLoc(MemberLoc) { + if (TemplateArgs) + getExplicitTemplateArgs()->initializeFrom(*TemplateArgs); +} + +UnresolvedMemberExpr * +UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) { + std::size_t size = sizeof(UnresolvedMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); + return new (Mem) UnresolvedMemberExpr( + Dependent ? C.DependentTy : C.OverloadTy, + Dependent, HasUnresolvedUsing, Base, IsArrow, + OperatorLoc, Qualifier, QualifierRange, + Member, MemberLoc, TemplateArgs); +} + +Stmt::child_iterator UnresolvedMemberExpr::child_begin() { return child_iterator(&Base); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { +Stmt::child_iterator UnresolvedMemberExpr::child_end() { return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 2689859e8e4a..a20e1cc6f56b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -19,7 +19,6 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/Compiler.h" #include <cstring> using namespace clang; @@ -153,7 +152,7 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, } namespace { -class VISIBILITY_HIDDEN HasSideEffect +class HasSideEffect : public StmtVisitor<HasSideEffect, bool> { EvalInfo &Info; public: @@ -210,7 +209,7 @@ public: // LValue Evaluation //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN LValueExprEvaluator +class LValueExprEvaluator : public StmtVisitor<LValueExprEvaluator, APValue> { EvalInfo &Info; public: @@ -353,7 +352,7 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN PointerExprEvaluator +class PointerExprEvaluator : public StmtVisitor<PointerExprEvaluator, APValue> { EvalInfo &Info; public: @@ -508,7 +507,7 @@ APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN VectorExprEvaluator + class VectorExprEvaluator : public StmtVisitor<VectorExprEvaluator, APValue> { EvalInfo &Info; APValue GetZeroVector(QualType VecType); @@ -702,7 +701,7 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN IntExprEvaluator +class IntExprEvaluator : public StmtVisitor<IntExprEvaluator, bool> { EvalInfo &Info; APValue &Result; @@ -776,7 +775,20 @@ public: T1.getUnqualifiedType()), E); } - bool VisitDeclRefExpr(const DeclRefExpr *E); + + bool CheckReferencedDecl(const Expr *E, const Decl *D); + bool VisitDeclRefExpr(const DeclRefExpr *E) { + return CheckReferencedDecl(E, E->getDecl()); + } + bool VisitMemberExpr(const MemberExpr *E) { + if (CheckReferencedDecl(E, E->getMemberDecl())) { + // Conservatively assume a MemberExpr will have side-effects + Info.EvalResult.HasSideEffects = true; + return true; + } + return false; + } + bool VisitCallExpr(const CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); @@ -834,12 +846,12 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { return true; } -bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { +bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. - if (const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(E->getDecl())) { + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { // FIXME: This is an ugly hack around the fact that enums don't set their // signedness consistently; see PR3173. - APSInt SI = D->getInitVal(); + APSInt SI = ECD->getInitVal(); SI.setIsUnsigned(!E->getType()->isSignedIntegerType()); // FIXME: This is an ugly hack around the fact that enums don't // set their width (!?!) consistently; see PR3173. @@ -851,15 +863,15 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C, they can also be folded, although they are not ICEs. if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() == Qualifiers::Const) { - if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { const VarDecl *Def = 0; - if (const Expr *Init = D->getDefinition(Def)) { - if (APValue *V = D->getEvaluatedValue()) + if (const Expr *Init = VD->getDefinition(Def)) { + if (APValue *V = VD->getEvaluatedValue()) return Success(V->getInt(), E); if (Visit(const_cast<Expr*>(Init))) { // Cache the evaluated value in the variable declaration. - D->setEvaluatedValue(Info.Ctx, Result); + VD->setEvaluatedValue(Info.Ctx, Result); return true; } @@ -1244,6 +1256,13 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { } unsigned IntExprEvaluator::GetAlignOfType(QualType T) { + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + // Get information about the alignment. unsigned CharSize = Info.Ctx.Target.getCharWidth(); @@ -1257,10 +1276,11 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); + return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl()); + return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(), + /*RefAsPointee*/true); return GetAlignOfType(E->getType()); } @@ -1280,6 +1300,12 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { } QualType SrcTy = E->getTypeOfArgument(); + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>()) + SrcTy = Ref->getPointeeType(); // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc // extension. @@ -1460,7 +1486,7 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FloatExprEvaluator +class FloatExprEvaluator : public StmtVisitor<FloatExprEvaluator, bool> { EvalInfo &Info; APFloat &Result; @@ -1652,7 +1678,7 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ComplexExprEvaluator +class ComplexExprEvaluator : public StmtVisitor<ComplexExprEvaluator, APValue> { EvalInfo &Info; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index b9cfcfec74f0..326a1dcd270a 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -14,7 +14,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" -#include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" #include <llvm/ADT/SmallSet.h> #include <llvm/Support/MathExtras.h> @@ -22,9 +21,9 @@ using namespace clang; ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) - : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0), - DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), - PrimaryBase(0), PrimaryBaseWasVirtual(false) {} + : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0), + MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), + NonVirtualAlignment(8) { } /// LayoutVtable - Lay out the vtable and set PrimaryBase. void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { @@ -34,7 +33,7 @@ void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { } SelectPrimaryBase(RD); - if (PrimaryBase == 0) { + if (!PrimaryBase.getBase()) { int AS = 0; UpdateAlignment(Ctx.Target.getPointerAlign(AS)); Size += Ctx.Target.getPointerWidth(AS); @@ -52,7 +51,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); // Skip the PrimaryBase here, as it is laid down first. - if (Base != PrimaryBase || PrimaryBaseWasVirtual) + if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual()) LayoutBaseNonVirtually(Base, false); } } @@ -74,12 +73,13 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { } void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = + Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo(); // If the record has a primary base class that is virtual, add it to the set // of primary bases. - if (Layout.getPrimaryBaseWasVirtual()) - IndirectPrimaryBases.insert(Layout.getPrimaryBase()); + if (BaseInfo.isVirtual()) + IndirectPrimaryBases.insert(BaseInfo.getBase()); // Now traverse all bases and find primary bases for them. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), @@ -107,7 +107,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); if (!i->isVirtual()) { SelectPrimaryVBase(Base, FirstPrimary); - if (PrimaryBase) + if (PrimaryBase.getBase()) return; continue; } @@ -115,7 +115,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, if (FirstPrimary==0) FirstPrimary = Base; if (!IndirectPrimaryBases.count(Base)) { - setPrimaryBase(Base, true); + setPrimaryBase(Base, /*IsVirtual=*/true); return; } } @@ -141,14 +141,17 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // base class, if one exists. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { - if (!i->isVirtual()) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (Base->isDynamicClass()) { - // We found it. - setPrimaryBase(Base, false); - return; - } + // Ignore virtual bases. + if (i->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isDynamicClass()) { + // We found it. + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false); + return; } } @@ -166,8 +169,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // Otherwise if is the first nearly empty virtual base, if one exists, // otherwise there is no primary base class. - if (!PrimaryBase) - setPrimaryBase(FirstPrimary, true); + if (!PrimaryBase.getBase()) + setPrimaryBase(FirstPrimary, /*IsVirtual=*/true); } void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { @@ -232,9 +235,10 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, } if (Base->getNumVBases()) { - const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); - const CXXRecordDecl *PB = L.getPrimaryBase(); - LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary); + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase(); + LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark, + IndirectPrimary); } } } @@ -448,17 +452,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // If this is a C++ class, lay out the vtable and the non-virtual bases. const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); if (RD) { LayoutVtable(RD); // PrimaryBase goes first. - if (PrimaryBase) { - if (PrimaryBaseWasVirtual) - IndirectPrimaryBases.insert(PrimaryBase); - LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual); + if (PrimaryBase.getBase()) { + if (PrimaryBase.isVirtual()) + IndirectPrimaryBases.insert(PrimaryBase.getBase()); + LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual()); } LayoutNonVirtualBases(RD); } @@ -470,7 +474,8 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (RD) { llvm::SmallSet<const CXXRecordDecl*, 32> mark; - LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases); + LayoutVirtualBases(RD, RD, PrimaryBase.getBase(), + 0, mark, IndirectPrimaryBases); } // Finally, round the size of the total struct up to the alignment of the @@ -498,7 +503,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; @@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { LayoutField(*Field); } +void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { + bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); + uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); + uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue(); + + std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + if (FieldPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + + // Check if we need to add padding to give the field the correct + // alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // Padding members don't affect overall alignment + if (!D->getIdentifier()) + FieldAlign = 1; + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // 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); + } else { + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); + UnfilledBitsInLastByte = DataSize - NewSizeInBits; + } + + // Update the size. + Size = std::max(Size, DataSize); + + // Remember max struct/class alignment. + UpdateAlignment(FieldAlign); +} + void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { - bool FieldPacked = Packed; + if (D->isBitField()) { + LayoutBitField(D); + return; + } + + // Reset the unfilled bits. + UnfilledBitsInLastByte = 0; + + bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t FieldOffset = IsUnion ? 0 : DataSize; uint64_t FieldSize; unsigned FieldAlign; - - FieldPacked |= D->hasAttr<PackedAttr>(); - - if (const Expr *BitWidthExpr = D->getBitWidth()) { - // TODO: Need to check this algorithm on other targets! - // (tested on Linux-X86) - FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); - + + if (D->getType()->isIncompleteArrayType()) { + // This is a flexible array member; we can't directly + // query getTypeInfo about these, so we figure it out here. + // Flexible array members don't have any size, but they + // have to be aligned appropriately for their element type. + FieldSize = 0; + const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); + FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); + } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); - uint64_t TypeSize = FieldInfo.first; - + FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; + } - if (FieldPacked) - FieldAlign = 1; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - // The maximum field alignment overrides the aligned attribute. - if (MaxFieldAlignment) - FieldAlign = std::min(FieldAlign, MaxFieldAlignment); - - // Check if we need to add padding to give the field the correct - // alignment. - if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - - // Padding members don't affect overall alignment - if (!D->getIdentifier()) - FieldAlign = 1; - } else { - if (D->getType()->isIncompleteArrayType()) { - // This is a flexible array member; we can't directly - // query getTypeInfo about these, so we figure it out here. - // Flexible array members don't have any size, but they - // have to be aligned appropriately for their element type. - FieldSize = 0; - const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); - FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); - } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Ctx.Target.getPointerWidth(AS); - FieldAlign = Ctx.Target.getPointerAlign(AS); - } else { - std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); - FieldSize = FieldInfo.first; - FieldAlign = FieldInfo.second; - } + if (FieldPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); - if (FieldPacked) - FieldAlign = 8; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - // The maximum field alignment overrides the aligned attribute. - if (MaxFieldAlignment) - FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); - // Round up the current record size to the field's alignment boundary. - FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); - - if (!IsUnion) { - while (true) { - // Check if we can place the field at this offset. - if (canPlaceFieldAtOffset(D, FieldOffset)) - break; - - // We couldn't place the field at the offset. Try again at a new offset. - FieldOffset += FieldAlign; - } + // Round up the current record size to the field's alignment boundary. + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + + if (!IsUnion) { + while (true) { + // Check if we can place the field at this offset. + if (canPlaceFieldAtOffset(D, FieldOffset)) + break; - UpdateEmptyClassOffsets(D, FieldOffset); + // We couldn't place the field at the offset. Try again at a new offset. + FieldOffset += FieldAlign; } + + UpdateEmptyClassOffsets(D, FieldOffset); } - + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); @@ -619,7 +651,7 @@ void ASTRecordLayoutBuilder::FinishLayout() { Size = 8; // Finally, round the size of the record up to the alignment of the // record itself. - Size = (Size + (Alignment-1)) & ~(Alignment-1); + Size = llvm::RoundUpToAlignment(Size, Alignment); } void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { @@ -631,6 +663,31 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } +static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) { + if (!RD->isDynamicClass()) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + const FunctionDecl *fn; + if (MD->getBody(fn) && !fn->isOutOfLine()) + continue; + + // We found it. + return MD; + } + + return 0; +} + const ASTRecordLayout * ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, const RecordDecl *D) { @@ -654,17 +711,19 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, uint64_t NonVirtualSize = IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D)); + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), NonVirtualSize, Builder.NonVirtualAlignment, Builder.PrimaryBase, - Builder.PrimaryBaseWasVirtual, Builder.Bases.data(), Builder.Bases.size(), Builder.VBases.data(), - Builder.VBases.size()); + Builder.VBases.size(), + KeyFunction); } const ASTRecordLayout * diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 077072343b1b..69e0498917c7 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H #define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H +#include "clang/AST/RecordLayout.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/System/DataTypes.h" @@ -27,12 +28,21 @@ namespace clang { class ASTRecordLayoutBuilder { ASTContext &Ctx; + /// Size - The current size of the record layout. uint64_t Size; + + /// Alignment - The current alignment of the record layout. unsigned Alignment; + llvm::SmallVector<uint64_t, 16> FieldOffsets; /// Packed - Whether the record is packed or not. bool Packed; + + /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, + /// this contains the number of bits in the last byte that can be used for + /// an adjacent bitfield if necessary. + unsigned char UnfilledBitsInLastByte; /// MaxFieldAlignment - The maximum allowed field alignment. This is set by /// #pragma pack. @@ -45,8 +55,8 @@ class ASTRecordLayoutBuilder { uint64_t NonVirtualSize; unsigned NonVirtualAlignment; - const CXXRecordDecl *PrimaryBase; - bool PrimaryBaseWasVirtual; + + ASTRecordLayout::PrimaryBaseInfo PrimaryBase; typedef llvm::SmallVector<std::pair<const CXXRecordDecl *, uint64_t>, 4> BaseOffsetsTy; @@ -74,6 +84,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutBitField(const FieldDecl *D); void SelectPrimaryBase(const CXXRecordDecl *RD); void SelectPrimaryVBase(const CXXRecordDecl *RD, @@ -84,9 +95,8 @@ class ASTRecordLayoutBuilder { /// base class. void IdentifyPrimaryBases(const CXXRecordDecl *RD); - void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) { - PrimaryBase = PB; - PrimaryBaseWasVirtual = Virtual; + void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) { + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual); } bool IsNearlyEmpty(const CXXRecordDecl *RD) const; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6e0da4714912..fad80ec0cf23 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -88,8 +88,8 @@ void Stmt::addStmtClass(StmtClass s) { static bool StatSwitch = false; -bool Stmt::CollectingStats(bool enable) { - if (enable) StatSwitch = true; +bool Stmt::CollectingStats(bool Enable) { + if (Enable) StatSwitch = true; return StatSwitch; } @@ -559,7 +559,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() { return &HandlerBlock + 1; } -QualType CXXCatchStmt::getCaughtType() { +QualType CXXCatchStmt::getCaughtType() const { if (ExceptionDecl) return ExceptionDecl->getType(); return QualType(); diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 93bf8755d580..bbe6a7120141 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" #include <cstdio> using namespace clang; @@ -26,7 +25,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> { + class StmtDumper : public StmtVisitor<StmtDumper> { SourceManager *SM; FILE *F; unsigned IndentLevel; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 4bd7f964be6c..205ea0d182d4 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -16,7 +16,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" using namespace clang; @@ -25,7 +24,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { + class StmtPrinter : public StmtVisitor<StmtPrinter> { llvm::raw_ostream &OS; ASTContext &Context; unsigned IndentLevel; @@ -483,19 +482,26 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { Policy); } -void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { +void StmtPrinter::VisitDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *Node) { Node->getQualifier()->print(OS, Policy); OS << Node->getDeclName().getAsString(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } -void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { +void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { if (Node->getQualifier()) Node->getQualifier()->print(OS, Policy); - Node->getTemplateName().print(OS, Policy, true); - OS << TemplateSpecializationType::PrintTemplateArgumentList( - Node->getTemplateArgs(), + OS << Node->getName().getAsString(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), Node->getNumTemplateArgs(), - Policy); + Policy); } void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { @@ -1048,11 +1054,6 @@ void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) { OS << Node->getType().getAsString() << "()"; } -void -StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) { - PrintRawDecl(E->getVarDecl()); -} - void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { if (E->isGlobalNew()) OS << "::"; @@ -1118,10 +1119,6 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << TypeS; } -void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { - OS << E->getName().getAsString(); -} - void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { // Nothing to print. } @@ -1146,7 +1143,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( OS << ")"; } -void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { +void StmtPrinter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); if (NestedNameSpecifier *Qualifier = Node->getQualifier()) @@ -1165,6 +1163,24 @@ void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { } } +void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + + // FIXME: this might originally have been written with 'template' + + OS << Node->getMemberName().getAsString(); + + if (Node->hasExplicitTemplateArgs()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } +} + static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { default: assert(false && "Unknown type trait"); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 4458c2b9cd25..d832a4649e75 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -20,11 +20,10 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor<StmtProfiler> { + class StmtProfiler : public StmtVisitor<StmtProfiler> { llvm::FoldingSetNodeID &ID; ASTContext &Context; bool Canonical; @@ -108,14 +107,17 @@ void StmtProfiler::VisitLabelStmt(LabelStmt *S) { void StmtProfiler::VisitIfStmt(IfStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitWhileStmt(WhileStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitDoStmt(DoStmt *S) { @@ -481,10 +483,6 @@ void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) { - VisitDeclRefExpr(S); -} - void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) { VisitExpr(S); ID.AddBoolean(S->isGlobalDelete()); @@ -515,9 +513,13 @@ void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { } void -StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) { +StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) { VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { @@ -526,18 +528,14 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { VisitType(S->getQueriedType()); } -void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { +void +StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { VisitExpr(S); VisitName(S->getDeclName()); VisitNestedNameSpecifier(S->getQualifier()); - ID.AddBoolean(S->isAddressOfOperand()); -} - -void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) { - VisitExpr(S); - VisitNestedNameSpecifier(S->getQualifier()); - VisitTemplateName(S->getTemplateName()); - VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { @@ -554,11 +552,25 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { VisitType(S->getTypeAsWritten()); } -void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) { +void +StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { VisitExpr(S); ID.AddBoolean(S->isArrow()); VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); + ID.AddBoolean(S->hasExplicitTemplateArgumentList()); + if (S->hasExplicitTemplateArgumentList()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMemberName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp index 61fd750ccc83..8be287e7cb21 100644 --- a/lib/AST/StmtViz.cpp +++ b/lib/AST/StmtViz.cpp @@ -30,8 +30,9 @@ void Stmt::viewAST() const { namespace llvm { template<> struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph, - bool ShortNames) { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) { #ifndef NDEBUG std::string OutSStr; diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index ff02f9a31cb2..f341b45fb971 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/FoldingSet.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" @@ -59,8 +60,17 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, break; case Template: - ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) - .getAsVoidPointer()); + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>( + getAsTemplate().getAsTemplateDecl())) { + ID.AddBoolean(true); + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getPosition()); + } else { + ID.AddBoolean(false); + ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) + .getAsVoidPointer()); + } break; case Integral: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 297534eaf1fc..5a2434da3c37 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -725,6 +725,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case UndeducedAuto: return "auto"; case ObjCId: return "id"; case ObjCClass: return "Class"; + case ObjCSel: return "SEL"; } } @@ -866,6 +867,11 @@ static bool isDependent(const TemplateArgument &Arg) { } bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) { + return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size()); +} + +bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { for (unsigned i = 0; i != N; ++i) if (isDependent(Args[i].getArgument())) diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index a48233378286..562e830b367e 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -535,6 +535,8 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, ObjCQIString = "id"; else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) ObjCQIString = "Class"; + else if (T->isObjCSelType()) + ObjCQIString = "SEL"; else ObjCQIString = T->getInterfaceDecl()->getNameAsString(); @@ -599,6 +601,14 @@ static void PrintTemplateArgument(std::string &Buffer, } } +std::string TemplateSpecializationType:: + PrintTemplateArgumentList(const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy) { + return PrintTemplateArgumentList(Args.getArgumentArray(), + Args.size(), + Policy); +} + std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 640912ad6b39..339e2c93cea9 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -18,21 +18,12 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/Support/BumpVector.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; -AnalysisContext::~AnalysisContext() { - delete cfg; - delete liveness; - delete PM; -} - -AnalysisContextManager::~AnalysisContextManager() { - for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) - delete I->second; -} - void AnalysisContextManager::clear() { for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) delete I->second; @@ -73,7 +64,7 @@ LiveVariables *AnalysisContext::getLiveVariables() { if (!c) return 0; - liveness = new LiveVariables(D->getASTContext(), *c); + liveness = new LiveVariables(*this); liveness->runOnCFG(*c); liveness->runOnAllBlocks(*c, 0, true); } @@ -157,3 +148,75 @@ ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx, } return scope; } + +//===----------------------------------------------------------------------===// +// Lazily generated map to query the external variables referenced by a Block. +//===----------------------------------------------------------------------===// + +namespace { +class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{ + BumpVector<const VarDecl*> &BEVals; + BumpVectorContext &BC; +public: + FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals, + BumpVectorContext &bc) + : BEVals(bevals), BC(bc) {} + + void VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();I!=E;++I) + if (Stmt *child = *I) + Visit(child); + } + + void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) + BEVals.push_back(VD, BC); + } +}; +} // end anonymous namespace + +typedef BumpVector<const VarDecl*> DeclVec; + +static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, + void *&Vec, + llvm::BumpPtrAllocator &A) { + if (Vec) + return (DeclVec*) Vec; + + BumpVectorContext BC(A); + DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>(); + new (BV) DeclVec(BC, 10); + + // Find the referenced variables. + FindBlockDeclRefExprsVals F(*BV, BC); + F.Visit(BD->getBody()); + + Vec = BV; + return BV; +} + +std::pair<AnalysisContext::referenced_decls_iterator, + AnalysisContext::referenced_decls_iterator> +AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { + if (!ReferencedBlockVars) + ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); + + DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); + return std::make_pair(V->begin(), V->end()); +} + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +AnalysisContext::~AnalysisContext() { + delete cfg; + delete liveness; + delete PM; + delete ReferencedBlockVars; +} + +AnalysisContextManager::~AnalysisContextManager() { + for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) + delete I->second; +} diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp index 549a22bec172..3d95ab183471 100644 --- a/lib/Analysis/ArrayBoundChecker.cpp +++ b/lib/Analysis/ArrayBoundChecker.cpp @@ -20,7 +20,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN ArrayBoundChecker : +class ArrayBoundChecker : public CheckerVisitor<ArrayBoundChecker> { BuiltinBug *BT; public: @@ -62,8 +62,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.GenerateNode(S, StOutBound, true); - + ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; @@ -80,7 +79,12 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(S->getSourceRange()); - C.EmitReport(report); + return; } + + // Array bound check succeeded. From this point forward the array bound + // should always succeed. + assert(StInBound); + C.addTransition(StInBound); } diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp index 01e1a1fcf69b..aa21700c2483 100644 --- a/lib/Analysis/AttrNonNullChecker.cpp +++ b/lib/Analysis/AttrNonNullChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN AttrNonNullChecker +class AttrNonNullChecker : public CheckerVisitor<AttrNonNullChecker> { BugType *BT; public: @@ -39,7 +39,6 @@ void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) { void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); - const GRState *originalState = state; // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); @@ -74,7 +73,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. - if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { + if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once @@ -109,6 +108,5 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. - if (state != originalState) - C.addTransition(C.GenerateNode(CE, state)); + C.addTransition(state); } diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp deleted file mode 100644 index 7a7ea188ba59..000000000000 --- a/lib/Analysis/BadCallChecker.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines BadCallChecker, a builtin check in GRExprEngine that performs -// checks for bad callee at call sites. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "GRExprEngineInternalChecks.h" - -using namespace clang; - -namespace { -class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> { - BuiltinBug *BT; -public: - BadCallChecker() : BT(0) {} - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; -} // end anonymous namespace - -void clang::RegisterBadCallChecker(GRExprEngine &Eng) { - Eng.registerCheck(new BadCallChecker()); -} - -void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const Expr *Callee = CE->getCallee()->IgnoreParens(); - SVal L = C.getState()->getSVal(Callee); - - if (L.isUndef() || isa<loc::ConcreteInt>(L)) { - if (ExplodedNode *N = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BuiltinBug("Invalid function call", - "Called function pointer is a null or undefined pointer value"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription(), N); - - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetCalleeExpr(N)); - - C.EmitReport(R); - } - } -} diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index d0b828952854..6c3f7b2245df 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -16,14 +16,13 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; -namespace { class VISIBILITY_HIDDEN ConstNotEq {}; } -namespace { class VISIBILITY_HIDDEN ConstEq {}; } +namespace { class ConstNotEq {}; } +namespace { class ConstEq {}; } typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy; typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy; @@ -46,7 +45,7 @@ struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> { namespace { // BasicConstraintManager only tracks equality and inequality constraints of // constants and integer variables. -class VISIBILITY_HIDDEN BasicConstraintManager +class BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index c2ecfa1f417f..c91377986496 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -22,12 +22,12 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathDiagnostic.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" -#include "llvm/Support/Compiler.h" using namespace clang; @@ -52,12 +52,12 @@ static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { namespace { -class VISIBILITY_HIDDEN APIMisuse : public BugType { +class APIMisuse : public BugType { public: APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} }; -class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { +class BasicObjCFoundationChecks : public GRSimpleAPICheck { APIMisuse *BT; BugReporter& BR; ASTContext &Ctx; @@ -87,7 +87,7 @@ private: // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("nil argument"); - RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N); + RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); R->addRange(ME->getArg(Arg)->getSourceRange()); BR.EmitReport(R); } @@ -228,7 +228,7 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, namespace { -class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck { +class AuditCFNumberCreate : public GRSimpleAPICheck { APIMisuse* BT; // FIXME: Either this should be refactored into GRSimpleAPICheck, or @@ -435,7 +435,7 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, // Lazily create the BugType object. This will be owned // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); - RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N); + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); report->addRange(Ex->getSourceRange()); BR.EmitReport(report); } @@ -450,7 +450,7 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck { +class AuditCFRetainRelease : public GRSimpleAPICheck { APIMisuse *BT; // FIXME: Either this should be refactored into GRSimpleAPICheck, or @@ -522,6 +522,64 @@ clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { } //===----------------------------------------------------------------------===// +// Check for sending 'retain', 'release', or 'autorelease' directly to a Class. +//===----------------------------------------------------------------------===// + +namespace { +class ClassReleaseChecker : + public CheckerVisitor<ClassReleaseChecker> { + Selector releaseS; + Selector retainS; + Selector autoreleaseS; + Selector drainS; + BugType *BT; +public: + ClassReleaseChecker(ASTContext &Ctx) + : releaseS(GetNullarySelector("release", Ctx)), + retainS(GetNullarySelector("retain", Ctx)), + autoreleaseS(GetNullarySelector("autorelease", Ctx)), + drainS(GetNullarySelector("drain", Ctx)), + BT(0) {} + + static void *getTag() { static int x = 0; return &x; } + + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); +}; +} + +void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const IdentifierInfo *ClsName = ME->getClassName(); + if (!ClsName) + return; + + Selector S = ME->getSelector(); + if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) + return; + + if (!BT) + BT = new APIMisuse("message incorrectly sent to class instead of class " + "instance"); + + ExplodedNode *N = C.GenerateNode(); + + if (!N) + return; + + llvm::SmallString<200> buf; + llvm::raw_svector_ostream os(buf); + + os << "The '" << S.getAsString() << "' message should be sent to instances " + "of class '" << ClsName->getName() + << "' and not the class directly"; + + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + report->addRange(ME->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -536,4 +594,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { RegisterNSErrorChecks(BR, Eng, D); RegisterNSAutoreleasePoolChecks(Eng); + Eng.registerCheck(new ClassReleaseChecker(Ctx)); } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h index ea4d3ecfcaee..679c6dc1df2d 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Analysis/BasicObjCFoundationChecks.h @@ -13,24 +13,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Support/Compiler.h" - #ifndef LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS #define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS namespace clang { -class GRSimpleAPICheck; class ASTContext; -class GRStateManager; class BugReporter; +class Decl; class GRExprEngine; +class GRSimpleAPICheck; GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR); diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 800a76fb0aee..45fc11a534a5 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/Analysis/PathSensitive/GRState.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -24,7 +23,7 @@ typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy; namespace { -class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap { +class BasicStoreSubRegionMap : public SubRegionMap { public: BasicStoreSubRegionMap() {} @@ -33,7 +32,7 @@ public: } }; -class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager { +class BasicStoreManager : public StoreManager { BindingsTy::Factory VBFactory; public: BasicStoreManager(GRStateManager& mgr) diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 8235f4acb179..c26a60af9c85 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -119,7 +119,7 @@ typedef llvm::DenseMap<const ExplodedNode*, const ExplodedNode*> NodeBackMap; namespace { -class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver { +class NodeMapClosure : public BugReport::NodeResolver { NodeBackMap& M; public: NodeMapClosure(NodeBackMap *m) : M(*m) {} @@ -131,7 +131,7 @@ public: } }; -class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext { +class PathDiagnosticBuilder : public BugReporterContext { BugReport *R; PathDiagnosticClient *PDC; llvm::OwningPtr<ParentMap> PM; @@ -358,7 +358,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N, } namespace { -class VISIBILITY_HIDDEN NotableSymbolHandler +class NotableSymbolHandler : public StoreManager::BindingsHandler { SymbolRef Sym; @@ -458,7 +458,7 @@ static void HandleNotableSymbol(const ExplodedNode* N, } namespace { -class VISIBILITY_HIDDEN ScanNotableSymbols +class ScanNotableSymbols : public StoreManager::BindingsHandler { llvm::SmallSet<SymbolRef, 10> AlreadyProcessed; @@ -802,7 +802,7 @@ static bool IsControlFlowExpr(const Stmt *S) { } namespace { -class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation { +class ContextLocation : public PathDiagnosticLocation { bool IsDead; public: ContextLocation(const PathDiagnosticLocation &L, bool isdead = false) @@ -812,7 +812,7 @@ public: bool isDead() const { return IsDead; } }; -class VISIBILITY_HIDDEN EdgeBuilder { +class EdgeBuilder { std::vector<ContextLocation> CLocs; typedef std::vector<ContextLocation>::iterator iterator; PathDiagnostic &PD; @@ -1645,7 +1645,7 @@ void BugReporter::EmitReport(BugReport* R) { //===----------------------------------------------------------------------===// namespace { -struct VISIBILITY_HIDDEN FRIEC_WLItem { +struct FRIEC_WLItem { const ExplodedNode *N; ExplodedNode::const_succ_iterator I, E; @@ -1738,7 +1738,7 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { // uses global state, which eventually should go elsewhere. //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode { +class DiagCacheItem : public llvm::FoldingSetNode { llvm::FoldingSetNodeID ID; public: DiagCacheItem(BugReport *R, PathDiagnostic *PD) { @@ -1835,14 +1835,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { PD->HandlePathDiagnostic(D.take()); } -void BugReporter::EmitBasicReport(const char* name, const char* str, +void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str, SourceLocation Loc, SourceRange* RBeg, unsigned NumRanges) { EmitBasicReport(name, "", str, Loc, RBeg, NumRanges); } -void BugReporter::EmitBasicReport(const char* name, const char* category, - const char* str, SourceLocation Loc, +void BugReporter::EmitBasicReport(llvm::StringRef name, + llvm::StringRef category, + llvm::StringRef str, SourceLocation Loc, SourceRange* RBeg, unsigned NumRanges) { // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'. diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp index 89c9ca10ec57..87de30ae7aec 100644 --- a/lib/Analysis/BugReporterVisitors.cpp +++ b/lib/Analysis/BugReporterVisitors.cpp @@ -83,7 +83,7 @@ clang::bugreporter::GetRetValExpr(const ExplodedNode *N) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor { +class FindLastStoreBRVisitor : public BugReporterVisitor { const MemRegion *R; SVal V; bool satisfied; @@ -231,7 +231,7 @@ static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R, BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); } -class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor { +class TrackConstraintBRVisitor : public BugReporterVisitor { DefinedSVal Constraint; const bool Assumption; bool isSatisfied; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 31417597f798..c97692f57082 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -17,7 +17,6 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Format.h" #include "llvm/ADT/DenseMap.h" @@ -50,7 +49,7 @@ static SourceLocation GetEndLoc(Decl* D) { /// constructed prior to its predecessor. This allows us to nicely capture /// implicit fall-throughs without extra basic blocks. /// -class VISIBILITY_HIDDEN CFGBuilder { +class CFGBuilder { ASTContext *Context; llvm::OwningPtr<CFG> cfg; @@ -461,9 +460,12 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { return VisitStmt(B, alwaysAdd); } -CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) { - // FIXME - return NYS(); +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, E); + } + return Block; } CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E, @@ -1624,7 +1626,7 @@ CFG::~CFG() { namespace { -class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { +class StmtPrinterHelper : public PrinterHelper { typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; StmtMapTy StmtMap; @@ -1668,7 +1670,7 @@ public: namespace { -class VISIBILITY_HIDDEN CFGBlockTerminatorPrint +class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint,void> { llvm::raw_ostream& OS; @@ -2047,8 +2049,10 @@ void CFG::viewCFG(const LangOptions &LO) const { namespace llvm { template<> struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph, - bool ShortNames) { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { #ifndef NDEBUG std::string OutSStr; diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 55e5f174cb9f..b95f981275e6 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -22,13 +22,14 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/STLExtras.h" #include <stdarg.h> @@ -168,7 +169,7 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { } namespace { -class VISIBILITY_HIDDEN GenericNodeBuilder { +class GenericNodeBuilder { GRStmtNodeBuilder *SNB; Stmt *S; const void *tag; @@ -246,7 +247,7 @@ namespace { /// RetEffect is used to summarize a function/method call's behavior with /// respect to its return value. -class VISIBILITY_HIDDEN RetEffect { +class RetEffect { public: enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias, @@ -312,7 +313,7 @@ public: // Reference-counting logic (typestate + counts). //===----------------------------------------------------------------------===// -class VISIBILITY_HIDDEN RefVal { +class RefVal { public: enum Kind { Owned = 0, // Owning reference. @@ -536,7 +537,7 @@ namespace clang { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RetainSummary { +class RetainSummary { /// Args - an ordered vector of (index, ArgEffect) pairs, where index /// specifies the argument (starting from 0). This can be sparsely /// populated; arguments with no entry in Args use 'DefaultArgEffect'. @@ -627,7 +628,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ObjCSummaryKey { +class ObjCSummaryKey { IdentifierInfo* II; Selector S; public: @@ -682,7 +683,7 @@ template <> struct DenseMapInfo<ObjCSummaryKey> { } // end llvm namespace namespace { -class VISIBILITY_HIDDEN ObjCSummaryCache { +class ObjCSummaryCache { typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy; MapTy M; public: @@ -776,7 +777,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RetainSummaryManager { +class RetainSummaryManager { //==-----------------------------------------------------------------==// // Typedefs. @@ -1865,8 +1866,8 @@ typedef llvm::ImmutableList<SymbolRef> ARStack; static int AutoRCIndex = 0; static int AutoRBIndex = 0; -namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; } -namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; } +namespace { class AutoreleasePoolContents {}; } +namespace { class AutoreleaseStack {}; } namespace clang { template<> struct GRStateTrait<AutoreleaseStack> @@ -1908,7 +1909,7 @@ static const GRState * SendAutorelease(const GRState *state, namespace { -class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { +class CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { public: @@ -2093,11 +2094,11 @@ namespace { // Bug Descriptions. // //===-------------===// - class VISIBILITY_HIDDEN CFRefBug : public BugType { + class CFRefBug : public BugType { protected: CFRefCount& TF; - CFRefBug(CFRefCount* tf, const char* name) + CFRefBug(CFRefCount* tf, llvm::StringRef name) : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} public: @@ -2110,7 +2111,7 @@ namespace { virtual bool isLeak() const { return false; } }; - class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug { + class UseAfterRelease : public CFRefBug { public: UseAfterRelease(CFRefCount* tf) : CFRefBug(tf, "Use-after-release") {} @@ -2120,7 +2121,7 @@ namespace { } }; - class VISIBILITY_HIDDEN BadRelease : public CFRefBug { + class BadRelease : public CFRefBug { public: BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} @@ -2130,7 +2131,7 @@ namespace { } }; - class VISIBILITY_HIDDEN DeallocGC : public CFRefBug { + class DeallocGC : public CFRefBug { public: DeallocGC(CFRefCount *tf) : CFRefBug(tf, "-dealloc called while using garbage collection") {} @@ -2140,7 +2141,7 @@ namespace { } }; - class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug { + class DeallocNotOwned : public CFRefBug { public: DeallocNotOwned(CFRefCount *tf) : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} @@ -2150,7 +2151,7 @@ namespace { } }; - class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug { + class OverAutorelease : public CFRefBug { public: OverAutorelease(CFRefCount *tf) : CFRefBug(tf, "Object sent -autorelease too many times") {} @@ -2160,7 +2161,7 @@ namespace { } }; - class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug { + class ReturnedNotOwnedForOwned : public CFRefBug { public: ReturnedNotOwnedForOwned(CFRefCount *tf) : CFRefBug(tf, "Method should return an owned object") {} @@ -2171,10 +2172,10 @@ namespace { } }; - class VISIBILITY_HIDDEN Leak : public CFRefBug { + class Leak : public CFRefBug { const bool isReturn; protected: - Leak(CFRefCount* tf, const char* name, bool isRet) + Leak(CFRefCount* tf, llvm::StringRef name, bool isRet) : CFRefBug(tf, name), isReturn(isRet) {} public: @@ -2183,15 +2184,15 @@ namespace { bool isLeak() const { return true; } }; - class VISIBILITY_HIDDEN LeakAtReturn : public Leak { + class LeakAtReturn : public Leak { public: - LeakAtReturn(CFRefCount* tf, const char* name) + LeakAtReturn(CFRefCount* tf, llvm::StringRef name) : Leak(tf, name, true) {} }; - class VISIBILITY_HIDDEN LeakWithinFunction : public Leak { + class LeakWithinFunction : public Leak { public: - LeakWithinFunction(CFRefCount* tf, const char* name) + LeakWithinFunction(CFRefCount* tf, llvm::StringRef name) : Leak(tf, name, false) {} }; @@ -2199,7 +2200,7 @@ namespace { // Bug Reports. // //===---------===// - class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport { + class CFRefReport : public RangedBugReport { protected: SymbolRef Sym; const CFRefCount &TF; @@ -2209,7 +2210,7 @@ namespace { : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, const char* endText) + ExplodedNode *n, SymbolRef sym, llvm::StringRef endText) : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} virtual ~CFRefReport() {} @@ -2240,7 +2241,7 @@ namespace { BugReporterContext& BRC); }; - class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport { + class CFRefLeakReport : public CFRefReport { SourceLocation AllocSite; const MemRegion* AllocBinding; public: @@ -2255,64 +2256,7 @@ namespace { }; } // end anonymous namespace -void CFRefCount::RegisterChecks(GRExprEngine& Eng) { - BugReporter &BR = Eng.getBugReporter(); - - useAfterRelease = new UseAfterRelease(this); - BR.Register(useAfterRelease); - - releaseNotOwned = new BadRelease(this); - BR.Register(releaseNotOwned); - - deallocGC = new DeallocGC(this); - BR.Register(deallocGC); - - deallocNotOwned = new DeallocNotOwned(this); - BR.Register(deallocNotOwned); - - overAutorelease = new OverAutorelease(this); - BR.Register(overAutorelease); - - returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); - BR.Register(returnNotOwnedForOwned); - - // First register "return" leaks. - const char* name = 0; - - if (isGCEnabled()) - name = "Leak of returned object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of returned object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak of returned object"; - } - - // Leaks should not be reported if they are post-dominated by a sink. - leakAtReturn = new LeakAtReturn(this, name); - leakAtReturn->setSuppressOnSink(true); - BR.Register(leakAtReturn); - - // Second, register leaks within a function/method. - if (isGCEnabled()) - name = "Leak of object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak"; - } - - // Leaks should not be reported if they are post-dominated by sinks. - leakWithinFunction = new LeakWithinFunction(this, name); - leakWithinFunction->setSuppressOnSink(true); - BR.Register(leakWithinFunction); - // Save the reference to the BugReporter. - this->BR = &BR; -} static const char* Msgs[] = { // GC only @@ -2603,7 +2547,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } namespace { - class VISIBILITY_HIDDEN FindUniqueBinding : + class FindUniqueBinding : public StoreManager::BindingsHandler { SymbolRef Sym; const MemRegion* Binding; @@ -3052,9 +2996,20 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, ExplodedNode* Pred) { - const FunctionDecl* FD = L.getAsFunctionDecl(); - RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() - : Summaries.getSummary(const_cast<FunctionDecl*>(FD)); + + RetainSummary *Summ = 0; + + // FIXME: Better support for blocks. For now we stop tracking anything + // that is passed to blocks. + // FIXME: Need to handle variables that are "captured" by the block. + if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { + Summ = Summaries.getPersistentStopSummary(); + } + else { + const FunctionDecl* FD = L.getAsFunctionDecl(); + Summ = !FD ? Summaries.getDefaultSummary() : + Summaries.getSummary(const_cast<FunctionDecl*>(FD)); + } assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, @@ -3066,6 +3021,16 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, ExplodedNode* Pred) { + // FIXME: Since we moved the nil check into a checker, we could get nil + // receiver here. Need a better way to check such case. + if (Expr* Receiver = ME->getReceiver()) { + const GRState *state = Pred->getState(); + DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); + if (!state->Assume(L, true)) { + Dst.Add(Pred); + return; + } + } RetainSummary *Summ = ME->getReceiver() @@ -3079,7 +3044,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, } namespace { -class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor { +class StopTrackingCallback : public SymbolVisitor { const GRState *state; public: StopTrackingCallback(const GRState *st) : state(st) {} @@ -3501,7 +3466,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd CFRefReport *report = new CFRefReport(*static_cast<CFRefBug*>(overAutorelease), - *this, N, Sym, os.str().c_str()); + *this, N, Sym, os.str()); BR->EmitReport(report); } @@ -3670,9 +3635,114 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, } //===----------------------------------------------------------------------===// +// Pieces of the retain/release checker implemented using a CheckerVisitor. +// More pieces of the retain/release checker will be migrated to this interface +// (ideally, all of it some day). +//===----------------------------------------------------------------------===// + +namespace { +class RetainReleaseChecker + : public CheckerVisitor<RetainReleaseChecker> { + CFRefCount *TF; +public: + RetainReleaseChecker(CFRefCount *tf) : TF(tf) {} + static void* getTag() { static int x = 0; return &x; } + + void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); +}; +} // end anonymous namespace + + +void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, + const BlockExpr *BE) { + + // Scan the BlockDecRefExprs for any object the retain/release checker + // may be tracking. + if (!BE->hasBlockDeclRefExprs()) + return; + + const GRState *state = C.getState(); + const BlockDataRegion *R = + cast<BlockDataRegion>(state->getSVal(BE).getAsRegion()); + + BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), + E = R->referenced_vars_end(); + + if (I == E) + return; + + state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState(); + C.addTransition(state); +} + +//===----------------------------------------------------------------------===// // Transfer function creation for external clients. //===----------------------------------------------------------------------===// +void CFRefCount::RegisterChecks(GRExprEngine& Eng) { + BugReporter &BR = Eng.getBugReporter(); + + useAfterRelease = new UseAfterRelease(this); + BR.Register(useAfterRelease); + + releaseNotOwned = new BadRelease(this); + BR.Register(releaseNotOwned); + + deallocGC = new DeallocGC(this); + BR.Register(deallocGC); + + deallocNotOwned = new DeallocNotOwned(this); + BR.Register(deallocNotOwned); + + overAutorelease = new OverAutorelease(this); + BR.Register(overAutorelease); + + returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); + BR.Register(returnNotOwnedForOwned); + + // First register "return" leaks. + const char* name = 0; + + if (isGCEnabled()) + name = "Leak of returned object when using garbage collection"; + else if (getLangOptions().getGCMode() == LangOptions::HybridGC) + name = "Leak of returned object when not using garbage collection (GC) in " + "dual GC/non-GC code"; + else { + assert(getLangOptions().getGCMode() == LangOptions::NonGC); + name = "Leak of returned object"; + } + + // Leaks should not be reported if they are post-dominated by a sink. + leakAtReturn = new LeakAtReturn(this, name); + leakAtReturn->setSuppressOnSink(true); + BR.Register(leakAtReturn); + + // Second, register leaks within a function/method. + if (isGCEnabled()) + name = "Leak of object when using garbage collection"; + else if (getLangOptions().getGCMode() == LangOptions::HybridGC) + name = "Leak of object when not using garbage collection (GC) in " + "dual GC/non-GC code"; + else { + assert(getLangOptions().getGCMode() == LangOptions::NonGC); + name = "Leak"; + } + + // Leaks should not be reported if they are post-dominated by sinks. + leakWithinFunction = new LeakWithinFunction(this, name); + leakWithinFunction->setSuppressOnSink(true); + BR.Register(leakWithinFunction); + + // Save the reference to the BugReporter. + this->BR = &BR; + + // Register the RetainReleaseChecker with the GRExprEngine object. + // Functionality in CFRefCount will be migrated to RetainReleaseChecker + // over time. + Eng.registerCheck(new RetainReleaseChecker(this)); +} + GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts) { return new CFRefCount(Ctx, GCEnabled, lopts); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 8e8c1e7b25ed..409292d451d8 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -4,7 +4,6 @@ add_clang_library(clangAnalysis AnalysisContext.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp - BadCallChecker.cpp BasicConstraintManager.cpp BasicObjCFoundationChecks.cpp BasicStore.cpp @@ -13,6 +12,7 @@ add_clang_library(clangAnalysis BugReporterVisitors.cpp CFG.cpp CFRefCount.cpp + CallAndMessageChecker.cpp CallGraph.cpp CallInliner.cpp CastToStructChecker.cpp @@ -22,6 +22,7 @@ add_clang_library(clangAnalysis CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp + Checker.cpp DereferenceChecker.cpp DivZeroChecker.cpp Environment.cpp @@ -31,7 +32,6 @@ add_clang_library(clangAnalysis GRCoreEngine.cpp GRExprEngine.cpp GRExprEngineExperimentalChecks.cpp - GRExprEngineInternalChecks.cpp GRState.cpp LiveVariables.cpp MallocChecker.cpp @@ -54,7 +54,8 @@ add_clang_library(clangAnalysis SimpleSValuator.cpp Store.cpp SymbolManager.cpp - UndefinedArgChecker.cpp + UndefBranchChecker.cpp + UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp UninitializedValues.cpp diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp new file mode 100644 index 000000000000..d8dd16c57b81 --- /dev/null +++ b/lib/Analysis/CallAndMessageChecker.cpp @@ -0,0 +1,267 @@ +//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines CallAndMessageChecker, a builtin checker that checks for various +// errors of call and objc message expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/ParentMap.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class CallAndMessageChecker + : public CheckerVisitor<CallAndMessageChecker> { + BugType *BT_call_null; + BugType *BT_call_undef; + BugType *BT_call_arg; + BugType *BT_msg_undef; + BugType *BT_msg_arg; + BugType *BT_msg_ret; +public: + CallAndMessageChecker() : + BT_call_null(0), BT_call_undef(0), BT_call_arg(0), + BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {} + + static void *getTag() { + static int x = 0; + return &x; + } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + +private: + void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); + void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, + ExplodedNode *N); + + void HandleNilReceiver(CheckerContext &C, const GRState *state, + const ObjCMessageExpr *ME); +}; +} // end anonymous namespace + +void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) { + Eng.registerCheck(new CallAndMessageChecker()); +} + +void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, + const CallExpr *CE) { + ExplodedNode *N = C.GenerateSink(); + if (!N) + return; + + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetCalleeExpr(N)); + C.EmitReport(R); +} + +void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, + const CallExpr *CE){ + + const Expr *Callee = CE->getCallee()->IgnoreParens(); + SVal L = C.getState()->getSVal(Callee); + + if (L.isUndef()) { + if (!BT_call_undef) + BT_call_undef = + new BuiltinBug("Called function pointer is an undefined pointer value"); + EmitBadCall(BT_call_undef, C, CE); + return; + } + + if (isa<loc::ConcreteInt>(L)) { + if (!BT_call_null) + BT_call_null = + new BuiltinBug("Called function pointer is null (null dereference)"); + EmitBadCall(BT_call_null, C, CE); + } + + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + if (C.getState()->getSVal(*I).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_call_arg) + BT_call_arg = new BuiltinBug("Pass-by-value argument in function call" + " is undefined"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg, + BT_call_arg->getName(), N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + return; + } + } + } +} + +void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const GRState *state = C.getState(); + + if (const Expr *receiver = ME->getReceiver()) + if (state->getSVal(receiver).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_msg_undef) + BT_msg_undef = + new BuiltinBug("Receiver in message expression is a garbage value"); + EnhancedBugReport *R = + new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); + R->addRange(receiver->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + C.EmitReport(R); + } + return; + } + + // Check for any arguments that are uninitialized/undefined. + for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), + E = ME->arg_end(); I != E; ++I) { + if (state->getSVal(*I).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_msg_arg) + BT_msg_arg = + new BuiltinBug("Pass-by-value argument in message expression" + " is undefined"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg, + BT_msg_arg->getName(), N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + return; + } + } + } + + // Check if the receiver was nil and then returns a value that may + // be garbage. + if (const Expr *Receiver = ME->getReceiver()) { + DefinedOrUnknownSVal receiverVal = + cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); + + const GRState *notNullState, *nullState; + llvm::tie(notNullState, nullState) = state->Assume(receiverVal); + + if (nullState && !notNullState) { + HandleNilReceiver(C, nullState, ME); + C.setDoneEvaluating(); // FIXME: eventually remove. + return; + } + + assert(notNullState); + state = notNullState; + } + + // Add a state transition if the state has changed. + C.addTransition(state); +} + +void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, + const ObjCMessageExpr *ME, + ExplodedNode *N) { + + if (!BT_msg_ret) + BT_msg_ret = + new BuiltinBug("Receiver in message expression is " + "'nil' and returns a garbage value"); + + llvm::SmallString<200> buf; + llvm::raw_svector_ostream os(buf); + os << "The receiver of message '" << ME->getSelector().getAsString() + << "' is nil and returns a value of type '" + << ME->getType().getAsString() << "' that will be garbage"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); + const Expr *receiver = ME->getReceiver(); + report->addRange(receiver->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + C.EmitReport(report); +} + +static bool SupportsNilWithFloatRet(const llvm::Triple &triple) { + return triple.getVendor() == llvm::Triple::Apple && + triple.getDarwinMajorNumber() >= 9; +} + +void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, + const GRState *state, + const ObjCMessageExpr *ME) { + + // Check the return type of the message expression. A message to nil will + // return different values depending on the return type and the architecture. + QualType RetTy = ME->getType(); + + ASTContext &Ctx = C.getASTContext(); + CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); + + if (CanRetTy->isStructureType()) { + // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead + // have the "use of undefined value" be smarter about where the + // undefined value came from. + if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + if (ExplodedNode* N = C.GenerateSink(state)) + EmitNilReceiverBug(C, ME, N); + return; + } + + // The result is not consumed by a surrounding expression. Just propagate + // the current state. + C.addTransition(state); + return; + } + + // Other cases: check if the return type is smaller than void*. + if (CanRetTy != Ctx.VoidTy && + C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + // Compute: sizeof(void *) and sizeof(return type) + const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); + const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); + + if (voidPtrSize < returnTypeSize && + !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) && + (Ctx.FloatTy == CanRetTy || + Ctx.DoubleTy == CanRetTy || + Ctx.LongDoubleTy == CanRetTy || + Ctx.LongLongTy == CanRetTy))) { + if (ExplodedNode* N = C.GenerateSink(state)) + EmitNilReceiverBug(C, ME, N); + return; + } + + // Handle the safe cases where the return value is 0 if the + // receiver is nil. + // + // FIXME: For now take the conservative approach that we only + // return null values if we *know* that the receiver is nil. + // This is because we can have surprises like: + // + // ... = [[NSScreens screens] objectAtIndex:0]; + // + // What can happen is that [... screens] could return nil, but + // it most likely isn't nil. We should assume the semantics + // of this case unless we have *a lot* more knowledge. + // + SVal V = C.getValueManager().makeZeroVal(ME->getType()); + C.GenerateNode(state->BindExpr(ME, V)); + return; + } + + C.addTransition(state); +} diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index 06e3317691e3..c1040f0c9949 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -137,8 +137,10 @@ namespace llvm { template <> struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + static std::string getNodeLabel(const CallGraphNode *Node, - const CallGraph &CG, bool ShortNames) { + const CallGraph &CG) { return Node->getName(); } diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp index cca8584a61fa..43523c293d58 100644 --- a/lib/Analysis/CallInliner.cpp +++ b/lib/Analysis/CallInliner.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs { +class CallInliner : public GRTransferFuncs { ASTContext &Ctx; public: CallInliner(ASTContext &ctx) : Ctx(ctx) {} diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp index ccd4a3333e22..a3663421a082 100644 --- a/lib/Analysis/CastToStructChecker.cpp +++ b/lib/Analysis/CastToStructChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN CastToStructChecker +class CastToStructChecker : public CheckerVisitor<CastToStructChecker> { BuiltinBug *BT; public: @@ -59,7 +59,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, // Now the cast-to-type is struct pointer, the original type is not void*. if (!OrigPointeeTy->isRecordType()) { - if (ExplodedNode *N = C.GenerateNode(CE)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Cast from non-struct type to struct type", "Casting a non-structure type to a structure type " diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index d5cb7ca7fdd3..ad63eb4122b0 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -22,13 +22,12 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ParentMap.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy { +class DeadStoreObs : public LiveVariables::ObserverTy { ASTContext &Ctx; BugReporter& BR; ParentMap& Parents; @@ -77,7 +76,7 @@ public: break; } - BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R); + BR.EmitBasicReport(BugType, "Dead store", msg, L, R); } void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val, @@ -134,16 +133,15 @@ public: if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS())) if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - Expr* RHS = B->getRHS()->IgnoreParenCasts(); - // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. if (VD->getType()->isPointerType()) { - if (IntegerLiteral* L = dyn_cast<IntegerLiteral>(RHS)) - // FIXME: Probably should have an Expr::isNullPointerConstant. - if (L->getValue() == 0) - return; + if (B->getRHS()->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull)) + return; } + + Expr* RHS = B->getRHS()->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS)) @@ -226,7 +224,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{ +class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{ CFG *cfg; public: FindEscaped(CFG *c) : cfg(c) {} diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp index 92e3e112d9f1..87c1f270a65c 100644 --- a/lib/Analysis/CheckObjCDealloc.cpp +++ b/lib/Analysis/CheckObjCDealloc.cpp @@ -169,7 +169,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, os << "Objective-C class '" << D->getNameAsString() << "' lacks a 'dealloc' instance method"; - BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; } @@ -187,7 +187,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; } @@ -251,8 +251,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, "but was released in 'dealloc'"; } - BR.EmitBasicReport(name, category, - os.str().c_str(), (*I)->getLocation()); + BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation()); } } } diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp index 8c0d39629d50..10ba896557df 100644 --- a/lib/Analysis/CheckObjCInstMethSignature.cpp +++ b/lib/Analysis/CheckObjCInstMethSignature.cpp @@ -65,7 +65,7 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, "behavior for clients of these classes."; BR.EmitBasicReport("Incompatible instance method return type", - os.str().c_str(), MethDerived->getLocStart()); + os.str(), MethDerived->getLocStart()); } } diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 2d9b53163f6a..d4067c900f3f 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" using namespace clang; @@ -85,6 +86,17 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { } } +static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, + SourceManager &SM) { + for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end(); + I!=E; ++I) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + SourceLocation L = FD->getLocStart(); + if (SM.getFileID(L) == FID) + Scan(M, FD->getBody()); + } +} + void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { @@ -110,10 +122,30 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (M.empty()) return; - + // Now scan the implementation declaration. Scan(M, D); + + // Any potentially unused ivars? + bool hasUnused = false; + for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) + if (I->second == Unused) { + hasUnused = true; + break; + } + + if (!hasUnused) + return; + + // We found some potentially unused ivars. Scan the entire translation unit + // for functions inside the @implementation that reference these ivars. + // FIXME: In the future hopefully we can just use the lexical DeclContext + // to go from the ObjCImplementationDecl to the lexically "nested" + // C functions. + SourceManager &SM = BR.getSourceManager(); + Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM); + // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { @@ -125,6 +157,6 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, "(although it may be used by category methods)."; BR.EmitBasicReport("Unused instance variable", "Optimization", - os.str().c_str(), I->first->getLocation()); + os.str(), I->first->getLocation()); } } diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index f1b9c2194f8b..e6ab17a75905 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -14,13 +14,12 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/StmtVisitor.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> { +class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; IdentifierInfo *II_gets; IdentifierInfo *II_getpw; @@ -210,7 +209,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { ranges.push_back(drInc->getSourceRange()); const char *bugType = "Floating point variable used as loop counter"; - BR.EmitBasicReport(bugType, "Security", os.str().c_str(), + BR.EmitBasicReport(bugType, "Security", os.str(), FS->getLocStart(), ranges.data(), ranges.size()); } @@ -347,7 +346,7 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CE->getLocStart(), &R, 1); } @@ -437,7 +436,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CE->getLocStart(), &R, 1); } diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp index 174beefbca45..4f5da9f5a716 100644 --- a/lib/Analysis/CheckSizeofPointer.cpp +++ b/lib/Analysis/CheckSizeofPointer.cpp @@ -15,12 +15,11 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/LocalCheckers.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> { +class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; public: diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp new file mode 100644 index 000000000000..0d907e501686 --- /dev/null +++ b/lib/Analysis/Checker.cpp @@ -0,0 +1,35 @@ +//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating +// domain-specific checks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checker.h" +using namespace clang; + +Checker::~Checker() {} + +CheckerContext::~CheckerContext() { + // Do we need to autotransition? 'Dst' can get populated in a variety of + // ways, including 'addTransition()' adding the predecessor node to Dst + // without actually generated a new node. We also shouldn't autotransition + // if we are building sinks or we generated a node and decided to not + // add it as a transition. + if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) { + if (state && state != B.GetState(Pred)) { + static int autoTransitionTag = 0; + B.Tag = &autoTransitionTag; + addTransition(state); + } + else + Dst.Add(Pred); + } +} diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp index c3aa8f3a2879..98243874d7d9 100644 --- a/lib/Analysis/DereferenceChecker.cpp +++ b/lib/Analysis/DereferenceChecker.cpp @@ -21,7 +21,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN DereferenceChecker : public Checker { +class DereferenceChecker : public Checker { BuiltinBug *BT_null; BuiltinBug *BT_undef; llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; @@ -56,8 +56,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { // Check for dereference of an undefined value. if (l.isUndef()) { - ExplodedNode *N = C.GenerateNode(S, true); - if (N) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_undef) BT_undef = new BuiltinBug("Dereference of undefined pointer value"); @@ -82,34 +81,55 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, // The explicit NULL case. if (nullState) { - // Generate an error node. - ExplodedNode *N = C.GenerateNode(S, nullState, true); - if (N) { - if (!notNullState) { - // We know that 'location' cannot be non-null. This is what - // we call an "explicit" null dereference. - if (!BT_null) - BT_null = new BuiltinBug("Null pointer dereference", - "Dereference of null pointer"); - - EnhancedBugReport *report = - new EnhancedBugReport(*BT_null, BT_null->getDescription(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); - - C.EmitReport(report); + if (!notNullState) { + // Generate an error node. + ExplodedNode *N = C.GenerateSink(nullState); + if (!N) return; + + // We know that 'location' cannot be non-null. This is what + // we call an "explicit" null dereference. + if (!BT_null) + BT_null = new BuiltinBug("Dereference of null pointer"); + + llvm::SmallString<100> buf; + + switch (S->getStmtClass()) { + case Stmt::UnaryOperatorClass: { + const UnaryOperator *U = cast<UnaryOperator>(S); + const Expr *SU = U->getSubExpr()->IgnoreParens(); + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + llvm::raw_svector_ostream os(buf); + os << "Dereference of null pointer loaded from variable '" + << VD->getName() << '\''; + } + } + } + default: + break; } + EnhancedBugReport *report = + new EnhancedBugReport(*BT_null, + buf.empty() ? BT_null->getDescription():buf.str(), + N); + + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + + C.EmitReport(report); + return; + } + else { // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null - // dereference. - ImplicitNullDerefNodes.push_back(N); + // dereference. + if (ExplodedNode *N = C.GenerateSink(nullState)) + ImplicitNullDerefNodes.push_back(N); } } // From this point forward, we know that the location is not null. - assert(notNullState); - C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) : - C.getPredecessor()); + C.addTransition(notNullState); } diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp index a8630f10088e..266c23609422 100644 --- a/lib/Analysis/DivZeroChecker.cpp +++ b/lib/Analysis/DivZeroChecker.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> { +class DivZeroChecker : public CheckerVisitor<DivZeroChecker> { BuiltinBug *BT; public: DivZeroChecker() : BT(0) {} @@ -63,7 +63,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); if (stateZero && !stateNotZero) { - if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (ExplodedNode *N = C.GenerateSink(stateZero)) { if (!BT) BT = new BuiltinBug("Division by zero"); @@ -80,6 +80,5 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, // If we get here, then the denom should not be zero. We abandon the implicit // zero denom case for now. - if (stateNotZero != C.getState()) - C.addTransition(C.GenerateNode(B, stateNotZero)); + C.addTransition(stateNotZero); } diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index 1610ad4d271d..dd2f08b48f76 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -83,7 +82,7 @@ Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S, } namespace { -class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor { +class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp index 80096dcb70d0..031ca44b602e 100644 --- a/lib/Analysis/FixedAddressChecker.cpp +++ b/lib/Analysis/FixedAddressChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN FixedAddressChecker +class FixedAddressChecker : public CheckerVisitor<FixedAddressChecker> { BuiltinBug *BT; public: @@ -53,7 +53,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, if (!RV.isConstant() || RV.isZeroConstant()) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Use fixed address", "Using a fixed address is not portable because that " diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index b99ba4f257ef..644dd199bead 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/PathSensitive/GRCoreEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/AST/Expr.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" #include <vector> @@ -30,7 +29,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN DFS : public GRWorkList { +class DFS : public GRWorkList { llvm::SmallVector<GRWorkListUnit,20> Stack; public: virtual bool hasWork() const { @@ -49,7 +48,7 @@ public: } }; -class VISIBILITY_HIDDEN BFS : public GRWorkList { +class BFS : public GRWorkList { std::queue<GRWorkListUnit> Queue; public: virtual bool hasWork() const { @@ -79,7 +78,7 @@ GRWorkList *GRWorkList::MakeDFS() { return new DFS(); } GRWorkList *GRWorkList::MakeBFS() { return new BFS(); } namespace { - class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList { + class BFSBlockDFSContents : public GRWorkList { std::queue<GRWorkListUnit> Queue; llvm::SmallVector<GRWorkListUnit,20> Stack; public: diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 26331776141f..20820d4f3833 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" #include "clang/Analysis/PathSensitive/Checker.h" @@ -22,7 +23,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/PrettyStackTrace.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/StringSwitch.h" @@ -37,12 +37,21 @@ using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(0, &II); +} + +//===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck { +class MappedBatchAuditor : public GRSimpleAPICheck { typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks; typedef llvm::DenseMap<void*,Checks> MapTy; @@ -107,16 +116,17 @@ public: // Checker worklist routines. //===----------------------------------------------------------------------===// -void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, +bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { if (Checkers.empty()) { - Dst = Src; - return; + Dst.insert(Src); + return false; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; + bool stopProcessingAfterCurrentChecker = false; for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { @@ -126,17 +136,33 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; - + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); + NI != NE; ++NI) { + // FIXME: Halting evaluation of the checkers is something we may + // not support later. The design is still evolving. + if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, + tag, isPrevisit)) { + if (CurrSet != &Dst) + Dst.insert(*CurrSet); + + stopProcessingAfterCurrentChecker = true; + continue; + } + assert(stopProcessingAfterCurrentChecker == false && + "Inconsistent setting of 'stopProcessingAfterCurrentChecker'"); + } + + if (stopProcessingAfterCurrentChecker) + return true; - // Update which NodeSet is the current one. + // Continue on to the next checker. Update the current NodeSet. PrevSet = CurrSet; } // Don't autotransition. The CheckerContext objects should do this // automatically. + return false; } // FIXME: This is largely copy-paste from CheckerVisit(). Need to @@ -179,12 +205,30 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, // Engine construction and deletion. //===----------------------------------------------------------------------===// -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(0, &II); +static void RegisterInternalChecks(GRExprEngine &Eng) { + // Register internal "built-in" BugTypes with the BugReporter. These BugTypes + // are different than what probably many checks will do since they don't + // create BugReports on-the-fly but instead wait until GRExprEngine finishes + // analyzing a function. Generation of BugReport objects is done via a call + // to 'FlushReports' from BugReporter. + // The following checks do not need to have their associated BugTypes + // explicitly registered with the BugReporter. If they issue any BugReports, + // their associated BugType will get registered with the BugReporter + // automatically. Note that the check itself is owned by the GRExprEngine + // object. + RegisterAttrNonNullChecker(Eng); + RegisterCallAndMessageChecker(Eng); + RegisterDereferenceChecker(Eng); + RegisterVLASizeChecker(Eng); + RegisterDivZeroChecker(Eng); + RegisterReturnStackAddressChecker(Eng); + RegisterReturnUndefChecker(Eng); + RegisterUndefinedArraySubscriptChecker(Eng); + RegisterUndefinedAssignmentChecker(Eng); + RegisterUndefBranchChecker(Eng); + RegisterUndefResultChecker(Eng); } - GRExprEngine::GRExprEngine(AnalysisManager &mgr) : AMgr(mgr), CoreEngine(mgr.getASTContext(), *this), @@ -198,7 +242,11 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr) CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), - BR(mgr, *this) {} + BR(mgr, *this) +{ + // Register internal checks. + RegisterInternalChecks(*this); +} GRExprEngine::~GRExprEngine() { BR.FlushReports(); @@ -211,7 +259,6 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// - void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { StateMgr.TF = tf; tf->RegisterChecks(*this); @@ -410,6 +457,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst); break; + case Stmt::BlockExprClass: + VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst); + break; + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast<BinaryOperator>(S); @@ -771,55 +822,49 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, Condition->getLocStart(), "Error evaluating branch"); - const GRState* PrevState = builder.getState(); - SVal X = PrevState->getSVal(Condition); - DefinedSVal *V = NULL; - - while (true) { - V = dyn_cast<DefinedSVal>(&X); - - if (!V) { - if (X.isUnknown()) { - if (const Expr *Ex = dyn_cast<Expr>(Condition)) { - if (Ex->getType()->isIntegerType()) { - // Try to recover some path-sensitivity. Right now casts of symbolic - // integers that promote their values are currently not tracked well. - // If 'Condition' is such an expression, try and recover the - // underlying value and use that instead. - SVal recovered = RecoverCastedSymbol(getStateManager(), - builder.getState(), Condition, - getContext()); - - if (!recovered.isUnknown()) { - X = recovered; - continue; - } - } - } + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + checker->VisitBranchCondition(builder, *this, Condition, tag); + } - builder.generateNode(MarkBranch(PrevState, Term, true), true); - builder.generateNode(MarkBranch(PrevState, Term, false), false); - return; - } + // If the branch condition is undefined, return; + if (!builder.isFeasible(true) && !builder.isFeasible(false)) + return; - assert(X.isUndef()); - ExplodedNode *N = builder.generateNode(PrevState, true); + const GRState* PrevState = builder.getState(); + SVal X = PrevState->getSVal(Condition); - if (N) { - N->markAsSink(); - UndefBranches.insert(N); + if (X.isUnknown()) { + // Give it a chance to recover from unknown. + if (const Expr *Ex = dyn_cast<Expr>(Condition)) { + if (Ex->getType()->isIntegerType()) { + // Try to recover some path-sensitivity. Right now casts of symbolic + // integers that promote their values are currently not tracked well. + // If 'Condition' is such an expression, try and recover the + // underlying value and use that instead. + SVal recovered = RecoverCastedSymbol(getStateManager(), + builder.getState(), Condition, + getContext()); + + if (!recovered.isUnknown()) { + X = recovered; + } } - - builder.markInfeasible(false); + } + // If the condition is still unknown, give up. + if (X.isUnknown()) { + builder.generateNode(MarkBranch(PrevState, Term, true), true); + builder.generateNode(MarkBranch(PrevState, Term, false), false); return; } - - break; } + DefinedSVal V = cast<DefinedSVal>(X); + // Process the true branch. if (builder.isFeasible(true)) { - if (const GRState *state = PrevState->Assume(*V, true)) + if (const GRState *state = PrevState->Assume(V, true)) builder.generateNode(MarkBranch(state, Term, true), true); else builder.markInfeasible(true); @@ -827,7 +872,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, // Process the false branch. if (builder.isFeasible(false)) { - if (const GRState *state = PrevState->Assume(*V, false)) + if (const GRState *state = PrevState->Assume(V, false)) builder.generateNode(MarkBranch(state, Term, false), false); else builder.markInfeasible(false); @@ -866,8 +911,9 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) { // Dispatch to the first target and mark it as a sink. - ExplodedNode* N = builder.generateNode(builder.begin(), state, true); - UndefBranches.insert(N); + //ExplodedNode* N = builder.generateNode(builder.begin(), state, true); + // FIXME: add checker visit. + // UndefBranches.insert(N); return; } @@ -918,8 +964,10 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { SVal CondV_untested = state->getSVal(CondE); if (CondV_untested.isUndef()) { - ExplodedNode* N = builder.generateDefaultCaseNode(state, true); - UndefBranches.insert(N); + //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); + // FIXME: add checker + //UndefBranches.insert(N); + return; } DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested); @@ -1052,6 +1100,22 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, // Transfer functions: Loads and stores. //===----------------------------------------------------------------------===// +void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + ExplodedNodeSet Tmp; + + CanQualType T = getContext().getCanonicalType(BE->getType()); + SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T, + Pred->getLocationContext()); + + MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), + ProgramPoint::PostLValueKind); + + // Post-visit the BlockExpr. + CheckerVisit(BE, Dst, Tmp, false); +} + void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { @@ -1278,7 +1342,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, bool isLoad) { - + // Early checks for performance reason. if (location.isUnknown() || Checkers.empty()) { Dst.Add(Pred); return; @@ -1298,9 +1362,13 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state, + NI != NE; ++NI) { + // Use the 'state' argument only when the predecessor node is the + // same as Pred. This allows us to catch updates to the state. + checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, + *NI == Pred ? state : GetState(*NI), location, tag, isLoad); + } // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -1850,197 +1918,89 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - // FIXME: More logic for the processing the method call. - - const GRState* state = GetState(Pred); - bool RaisesException = false; - - - if (Expr* Receiver = ME->getReceiver()) { - - SVal L_untested = state->getSVal(Receiver); - - // Check for undefined control-flow. - if (L_untested.isUndef()) { - ExplodedNode* N = Builder->generateNode(ME, state, Pred); - - if (N) { - N->markAsSink(); - UndefReceivers.insert(N); - } - - return; - } - - // "Assume" that the receiver is not NULL. - DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested); - const GRState *StNotNull = state->Assume(L, true); - - // "Assume" that the receiver is NULL. - const GRState *StNull = state->Assume(L, false); - - if (StNull) { - QualType RetTy = ME->getType(); - - // Check if the receiver was nil and the return value a struct. - if (RetTy->isRecordType()) { - if (Pred->getParentMap().isConsumedExpr(ME)) { - // The [0 ...] expressions will return garbage. Flag either an - // explicit or implicit error. Because of the structure of this - // function we currently do not bifurfacte the state graph at - // this point. - // FIXME: We should bifurcate and fill the returned struct with - // garbage. - if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { - N->markAsSink(); - if (StNotNull) - NilReceiverStructRetImplicit.insert(N); - else - NilReceiverStructRetExplicit.insert(N); - } - } - } - else { - ASTContext& Ctx = getContext(); - if (RetTy != Ctx.VoidTy) { - if (Pred->getParentMap().isConsumedExpr(ME)) { - // sizeof(void *) - const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); - // sizeof(return type) - const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType()); - - if (voidPtrSize < returnTypeSize) { - if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { - N->markAsSink(); - if (StNotNull) - NilReceiverLargerThanVoidPtrRetImplicit.insert(N); - else - NilReceiverLargerThanVoidPtrRetExplicit.insert(N); - } - } - else if (!StNotNull) { - // Handle the safe cases where the return value is 0 if the - // receiver is nil. - // - // FIXME: For now take the conservative approach that we only - // return null values if we *know* that the receiver is nil. - // This is because we can have surprises like: - // - // ... = [[NSScreens screens] objectAtIndex:0]; - // - // What can happen is that [... screens] could return nil, but - // it most likely isn't nil. We should assume the semantics - // of this case unless we have *a lot* more knowledge. - // - SVal V = ValMgr.makeZeroVal(ME->getType()); - MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V)); - return; - } - } - } - } - // We have handled the cases where the receiver is nil. The remainder - // of this method should assume that the receiver is not nil. - if (!StNotNull) - return; - - state = StNotNull; - } - - // Check if the "raise" message was sent. - if (ME->getSelector() == RaiseSel) - RaisesException = true; + // Handle previsits checks. + ExplodedNodeSet Src, DstTmp; + Src.Add(Pred); + + if (CheckerVisit(ME, DstTmp, Src, true)) { + Dst.insert(DstTmp); + return; } - else { - - IdentifierInfo* ClsName = ME->getClassName(); - Selector S = ME->getSelector(); - - // Check for special instance methods. + + unsigned size = Dst.size(); - if (!NSExceptionII) { - ASTContext& Ctx = getContext(); + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); + DI!=DE; ++DI) { + Pred = *DI; + bool RaisesException = false; - NSExceptionII = &Ctx.Idents.get("NSException"); + if (ME->getReceiver()) { + // Check if the "raise" message was sent. + if (ME->getSelector() == RaiseSel) + RaisesException = true; } + else { - if (ClsName == NSExceptionII) { - - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. + IdentifierInfo* ClsName = ME->getClassName(); + Selector S = ME->getSelector(); - if (!NSExceptionInstanceRaiseSelectors) { + // Check for special instance methods. + if (!NSExceptionII) { ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; + NSExceptionII = &Ctx.Idents.get("NSException"); + } - llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; - unsigned idx = 0; + if (ClsName == NSExceptionII) { - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); + enum { NUM_RAISE_SELECTORS = 2 }; - // raise:format::arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - } + // Lazily create a cache of the selectors. - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; break; - } - } - } + if (!NSExceptionInstanceRaiseSelectors) { - // Check for any arguments that are uninitialized/undefined. + ASTContext& Ctx = getContext(); - for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end(); - I != E; ++I) { + NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; - if (state->getSVal(*I).isUndef()) { + llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; + unsigned idx = 0; - // Generate an error node for passing an uninitialized/undefined value - // as an argument to a message expression. This node is a sink. - ExplodedNode* N = Builder->generateNode(ME, state, Pred); + // raise:format: + II.push_back(&Ctx.Idents.get("raise")); + II.push_back(&Ctx.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); - if (N) { - N->markAsSink(); - MsgExprUndefArgs[N] = *I; - } + // raise:format::arguments: + II.push_back(&Ctx.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + } - return; + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) + if (S == NSExceptionInstanceRaiseSelectors[i]) { + RaisesException = true; break; + } + } } - } - // Handle previsits checks. - ExplodedNodeSet Src, DstTmp; - Src.Add(Pred); - CheckerVisit(ME, DstTmp, Src, true); - - // Check if we raise an exception. For now treat these as sinks. Eventually - // we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - if (RaisesException) - Builder->BuildSinks = true; + // Check if we raise an exception. For now treat these as sinks. Eventually + // we will want to handle exceptions properly. + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - unsigned size = Dst.size(); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI!=DE; ++DI) - EvalObjCMessageExpr(Dst, ME, *DI); + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred); + } // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - MakeNode(Dst, ME, Pred, state); + MakeNode(Dst, ME, Pred, GetState(Pred)); } //===----------------------------------------------------------------------===// @@ -2157,7 +2117,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, namespace { // This class is used by VisitInitListExpr as an item in a worklist // for processing the values contained in an InitListExpr. -class VISIBILITY_HIDDEN InitListWLItem { +class InitListWLItem { public: llvm::ImmutableList<SVal> Vals; ExplodedNode* N; @@ -2246,8 +2206,6 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, return; } - - printf("InitListExpr type = %s\n", T.getAsString().c_str()); assert(0 && "unprocessed InitListExpr type"); } @@ -2689,6 +2647,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, else Visit(LHS, Pred, Tmp1); + ExplodedNodeSet Tmp3; + for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { SVal LeftV = (*I1)->getState()->getSVal(LHS); ExplodedNodeSet Tmp2; @@ -2723,7 +2683,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); + EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); continue; } @@ -2735,28 +2695,17 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, if (Result.isUnknown()) { if (OldSt != state) { // Generate a new node if we have already created a new state. - MakeNode(Dst, B, *I2, state); + MakeNode(Tmp3, B, *I2, state); } else - Dst.Add(*I2); + Tmp3.Add(*I2); continue; } state = state->BindExpr(B, Result); - if (Result.isUndef()) { - // The operands were *not* undefined, but the result is undefined. - // This is a special node that should be flagged as an error. - if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; - } - - // Otherwise, create a new node. - MakeNode(Dst, B, *I2, state); + MakeNode(Tmp3, B, *I2, state); continue; } @@ -2809,15 +2758,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, RightV, CTy), state, B->getType(), CTy); - if (Result.isUndef()) { - // The operands were not undefined, but the result is undefined. - if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) { - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; - } - // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. @@ -2844,11 +2784,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); } - EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result), + EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result), location, LHSVal); } } } + + CheckerVisit(B, Dst, Tmp3, false); } //===----------------------------------------------------------------------===// @@ -2870,8 +2812,11 @@ static SourceManager* GraphPrintSourceManager; namespace llvm { template<> -struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : +struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not // work. static std::string getNodeAttributes(const ExplodedNode* N, void*) { @@ -2888,15 +2833,14 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : GraphPrintCheckerState->isBadCall(N) || GraphPrintCheckerState->isUndefArg(N)) return "color=\"red\",style=\"filled\""; -#endif if (GraphPrintCheckerState->isNoReturnCall(N)) return "color=\"blue\",style=\"filled\""; - +#endif return ""; } - static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){ + static std::string getNodeLabel(const ExplodedNode* N, void*){ std::string sbuf; llvm::raw_string_ostream Out(sbuf); diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp index 2fb7e9fa482f..33479b0cb7e5 100644 --- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp +++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp @@ -31,6 +31,8 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { // Note that this must be registered after ReturnStackAddresEngsChecker. RegisterReturnPointerRangeChecker(Eng); + + RegisterFixedAddressChecker(Eng); RegisterPointerSubChecker(Eng); RegisterPointerArithChecker(Eng); RegisterCastToStructChecker(Eng); diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp deleted file mode 100644 index d0f60fde5b1b..000000000000 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ /dev/null @@ -1,400 +0,0 @@ -//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- 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 the BugType classes used by GRExprEngine to report -// bugs derived from builtin checks in the path-sensitive engine. -// -//===----------------------------------------------------------------------===// - -#include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::bugreporter; - -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -template <typename ITERATOR> inline -ExplodedNode* GetNode(ITERATOR I) { - return *I; -} - -template <> inline -ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { - return I->first; -} - -//===----------------------------------------------------------------------===// -// Bug Descriptions. -//===----------------------------------------------------------------------===// -namespace clang { -class BuiltinBugReport : public RangedBugReport { -public: - BuiltinBugReport(BugType& bt, const char* desc, - ExplodedNode *n) - : RangedBugReport(bt, desc, n) {} - - BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n) - : RangedBugReport(bt, shortDesc, desc, n) {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N); -}; - -void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) { - static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this); -} - -template <typename ITER> -void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { - for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(), - GetNode(I))); -} - -class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug { -public: - NilReceiverStructRet(GRExprEngine* eng) : - BuiltinBug(eng, "'nil' receiver with struct return type") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::nil_receiver_struct_ret_iterator - I=Eng.nil_receiver_struct_ret_begin(), - E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) { - - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - PostStmt P = cast<PostStmt>((*I)->getLocation()); - const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt()); - os << "The receiver in the message expression is 'nil' and results in the" - " returned value (of type '" - << ME->getType().getAsString() - << "') to be garbage or otherwise undefined"; - - BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); - R->addRange(ME->getReceiver()->getSourceRange()); - BR.EmitReport(R); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug { -public: - NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) : - BuiltinBug(eng, - "'nil' receiver with return type larger than sizeof(void *)") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator - I=Eng.nil_receiver_larger_than_voidptr_ret_begin(), - E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) { - - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - PostStmt P = cast<PostStmt>((*I)->getLocation()); - const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt()); - os << "The receiver in the message expression is 'nil' and results in the" - " returned value (of type '" - << ME->getType().getAsString() - << "' and of size " - << Eng.getContext().getTypeSize(ME->getType()) / 8 - << " bytes) to be garbage or otherwise undefined"; - - BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); - R->addRange(ME->getReceiver()->getSourceRange()); - BR.EmitReport(R); - } - } - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN UndefResult : public BuiltinBug { -public: - UndefResult(GRExprEngine* eng) - : BuiltinBug(eng,"Undefined or garbage result", - "Result of operation is garbage or undefined") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(), - E = Eng.undef_results_end(); I!=E; ++I) { - - ExplodedNode *N = *I; - const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); - BuiltinBugReport *report = NULL; - - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { - llvm::SmallString<256> sbuf; - llvm::raw_svector_ostream OS(sbuf); - const GRState *ST = N->getState(); - const Expr *Ex = NULL; - bool isLeft = true; - - if (ST->getSVal(B->getLHS()).isUndef()) { - Ex = B->getLHS()->IgnoreParenCasts(); - isLeft = true; - } - else if (ST->getSVal(B->getRHS()).isUndef()) { - Ex = B->getRHS()->IgnoreParenCasts(); - isLeft = false; - } - - if (Ex) { - OS << "The " << (isLeft ? "left" : "right") - << " operand of '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' is a garbage value"; - } - else { - // Neither operand was undefined, but the result is undefined. - OS << "The result of the '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' expression is undefined"; - } - - // FIXME: Use StringRefs to pass string information. - report = new BuiltinBugReport(*this, OS.str().str().c_str(), N); - if (Ex) report->addRange(Ex->getSourceRange()); - } - else { - report = new BuiltinBugReport(*this, - "Expression evaluates to an uninitialized" - " or undefined value", N); - } - - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - - const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt(); - const Stmt *X = S; - - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { - const GRState *ST = N->getState(); - if (ST->getSVal(B->getLHS()).isUndef()) - X = B->getLHS(); - else if (ST->getSVal(B->getRHS()).isUndef()) - X = B->getRHS(); - } - - registerTrackNullOrUndefValue(BRC, X, N); - } -}; - -class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport { - const Stmt *Arg; -public: - ArgReport(BugType& bt, const char* desc, ExplodedNode *n, - const Stmt *arg) - : BuiltinBugReport(bt, desc, n), Arg(arg) {} - - ArgReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n, const Stmt *arg) - : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {} - - const Stmt *getArg() const { return Arg; } -}; - -class VISIBILITY_HIDDEN BadArg : public BuiltinBug { -public: - BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument", - "Pass-by-value argument in function call is undefined") {} - - BadArg(GRExprEngine* eng, const char* d) - : BuiltinBug(eng,"Uninitialized argument", d) {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(), - N); - } -}; - -class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg { -public: - BadMsgExprArg(GRExprEngine* eng) - : BadArg(eng,"Pass-by-value argument in message expression is undefined"){} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(), - E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) { - // Generate a report for this bug. - ArgReport *report = new ArgReport(*this, desc.c_str(), I->first, - I->second); - report->addRange(I->second->getSourceRange()); - BR.EmitReport(report); - } - } -}; - -class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug { -public: - BadReceiver(GRExprEngine* eng) - : BuiltinBug(eng,"Uninitialized receiver", - "Receiver in message expression is an uninitialized value") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(), - End = Eng.undef_receivers_end(); I!=End; ++I) { - - // Generate a report for this bug. - BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I); - ExplodedNode* N = *I; - const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt(); - const Expr* E = cast<ObjCMessageExpr>(S)->getReceiver(); - assert (E && "Receiver cannot be NULL"); - report->addRange(E->getSourceRange()); - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug { - struct VISIBILITY_HIDDEN FindUndefExpr { - GRStateManager& VM; - const GRState* St; - - FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} - - Expr* FindExpr(Expr* Ex) { - if (!MatchesCriteria(Ex)) - return 0; - - for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I) - if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) { - Expr* E2 = FindExpr(ExI); - if (E2) return E2; - } - - return Ex; - } - - bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); } - }; - -public: - UndefBranch(GRExprEngine *eng) - : BuiltinBug(eng,"Use of garbage value", - "Branch condition evaluates to an undefined or garbage value") - {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(), - E=Eng.undef_branches_end(); I!=E; ++I) { - - // What's going on here: we want to highlight the subexpression of the - // condition that is the most likely source of the "uninitialized - // branch condition." We do a recursive walk of the condition's - // subexpressions and roughly look for the most nested subexpression - // that binds to Undefined. We then highlight that expression's range. - BlockEdge B = cast<BlockEdge>((*I)->getLocation()); - Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition()); - assert (Ex && "Block must have a terminator."); - - // Get the predecessor node and check if is a PostStmt with the Stmt - // being the terminator condition. We want to inspect the state - // of that node instead because it will contain main information about - // the subexpressions. - assert (!(*I)->pred_empty()); - - // Note: any predecessor will do. They should have identical state, - // since all the BlockEdge did was act as an error sink since the value - // had to already be undefined. - ExplodedNode *N = *(*I)->pred_begin(); - ProgramPoint P = N->getLocation(); - const GRState* St = (*I)->getState(); - - if (PostStmt* PS = dyn_cast<PostStmt>(&P)) - if (PS->getStmt() == Ex) - St = N->getState(); - - FindUndefExpr FindIt(Eng.getStateManager(), St); - Ex = FindIt.FindExpr(Ex); - - ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex); - R->addRange(Ex->getSourceRange()); - BR.EmitReport(R); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(), - N); - } -}; - -} // end clang namespace - -//===----------------------------------------------------------------------===// -// Check registration. -//===----------------------------------------------------------------------===// - -void GRExprEngine::RegisterInternalChecks() { - // Register internal "built-in" BugTypes with the BugReporter. These BugTypes - // are different than what probably many checks will do since they don't - // create BugReports on-the-fly but instead wait until GRExprEngine finishes - // analyzing a function. Generation of BugReport objects is done via a call - // to 'FlushReports' from BugReporter. - BR.Register(new UndefBranch(this)); - BR.Register(new UndefResult(this)); - BR.Register(new BadMsgExprArg(this)); - BR.Register(new BadReceiver(this)); - BR.Register(new NilReceiverStructRet(this)); - BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); - - // The following checks do not need to have their associated BugTypes - // explicitly registered with the BugReporter. If they issue any BugReports, - // their associated BugType will get registered with the BugReporter - // automatically. Note that the check itself is owned by the GRExprEngine - // object. - registerCheck(new UndefinedAssignmentChecker()); - - RegisterAttrNonNullChecker(*this); - RegisterUndefinedArgChecker(*this); - RegisterBadCallChecker(*this); - RegisterDereferenceChecker(*this); - RegisterVLASizeChecker(*this); - RegisterDivZeroChecker(*this); - RegisterReturnStackAddressChecker(*this); - RegisterReturnUndefChecker(*this); - RegisterFixedAddressChecker(*this); - RegisterUndefinedArraySubscriptChecker(*this); -} diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h index a9077bf75715..5b7a7572ed7d 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.h +++ b/lib/Analysis/GRExprEngineInternalChecks.h @@ -20,7 +20,6 @@ namespace clang { class GRExprEngine; void RegisterAttrNonNullChecker(GRExprEngine &Eng); -void RegisterBadCallChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); @@ -31,9 +30,12 @@ void RegisterPointerSubChecker(GRExprEngine &Eng); void RegisterPointerArithChecker(GRExprEngine &Eng); void RegisterFixedAddressChecker(GRExprEngine &Eng); void RegisterCastToStructChecker(GRExprEngine &Eng); -void RegisterUndefinedArgChecker(GRExprEngine &Eng); +void RegisterCallAndMessageChecker(GRExprEngine &Eng); void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); +void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); +void RegisterUndefBranchChecker(GRExprEngine &Eng); +void RegisterUndefResultChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 23ee0b2258bd..a56859dde5bf 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -232,7 +232,7 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor { +class ScanReachableSymbols : public SubRegionMap::Visitor { typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy; VisitedRegionsTy visited; @@ -308,6 +308,27 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const { return S.scan(val); } +bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const { + ScanReachableSymbols S(this, visitor); + for ( ; I != E; ++I) { + if (S.scan(*I)) + return true; + } + return false; +} + +bool GRState::scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const { + ScanReachableSymbols S(this, visitor); + for ( ; I != E; ++I) { + if (S.scan(*I)) + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // Queries. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 2510445a7f31..84e268f3fdaa 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -19,9 +19,9 @@ #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" #include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -38,7 +38,7 @@ static const bool Dead = false; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RegisterDecls +class RegisterDecls : public CFGRecStmtDeclVisitor<RegisterDecls> { LiveVariables::AnalysisDataTy& AD; @@ -77,10 +77,12 @@ public: }; } // end anonymous namespace -LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) { +LiveVariables::LiveVariables(AnalysisContext &AC) { // Register all referenced VarDecls. + CFG &cfg = *AC.getCFG(); getAnalysisData().setCFG(cfg); - getAnalysisData().setContext(Ctx); + getAnalysisData().setContext(AC.getASTContext()); + getAnalysisData().AC = &AC; RegisterDecls R(getAnalysisData()); cfg.VisitBlockStmts(R); @@ -92,7 +94,7 @@ LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) { namespace { -class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{ +class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{ LiveVariables::AnalysisDataTy& AD; LiveVariables::ValTy LiveState; public: @@ -103,6 +105,7 @@ public: void VisitDeclRefExpr(DeclRefExpr* DR); void VisitBinaryOperator(BinaryOperator* B); + void VisitBlockExpr(BlockExpr *B); void VisitAssign(BinaryOperator* B); void VisitDeclStmt(DeclStmt* DS); void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); @@ -153,7 +156,17 @@ void TransferFuncs::VisitTerminator(CFGBlock* B) { void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl())) - LiveState(V,AD) = Alive; + LiveState(V, AD) = Alive; +} + +void TransferFuncs::VisitBlockExpr(BlockExpr *BE) { + AnalysisContext::referenced_decls_iterator I, E; + llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl()); + for ( ; I != E ; ++I) { + DeclBitVector_Types::Idx i = AD.getIdx(*I); + if (i.isValid()) + LiveState.getBit(i) = Alive; + } } void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 93e708332ed7..204c7b320e65 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -46,9 +46,9 @@ struct RefState { } }; -class VISIBILITY_HIDDEN RegionState {}; +class RegionState {}; -class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> { +class MallocChecker : public CheckerVisitor<MallocChecker> { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; IdentifierInfo *II_malloc; @@ -65,7 +65,7 @@ private: void MallocMem(CheckerContext &C, const CallExpr *CE); void FreeMem(CheckerContext &C, const CallExpr *CE); }; -} +} // end anonymous namespace namespace clang { template <> @@ -112,9 +112,7 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { SymbolRef Sym = CallVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - const GRState *AllocState - = state->set<RegionState>(Sym, RefState::getAllocated(CE)); - C.addTransition(C.GenerateNode(CE, AllocState)); + C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE))); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { @@ -128,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Check double free. if (RS->isReleased()) { - ExplodedNode *N = C.GenerateNode(CE, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_DoubleFree) BT_DoubleFree = new BuiltinBug("Double free", @@ -144,7 +142,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Normal free. const GRState *FreedState = state->set<RegionState>(Sym, RefState::getReleased(CE)); - C.addTransition(C.GenerateNode(CE, FreedState)); + C.addTransition(FreedState); } void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, @@ -158,7 +156,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, return; if (RS->isAllocated()) { - ExplodedNode *N = C.GenerateNode(S, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_Leak) BT_Leak = new BuiltinBug("Memory leak", @@ -173,6 +171,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) { + SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap; SymMap M = state->get<RegionState>(); @@ -212,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { if (RS->isAllocated()) state = state->set<RegionState>(Sym, RefState::getEscaped(S)); - ExplodedNode *N = C.GenerateNode(S, state); - if (N) - C.addTransition(N); + C.addTransition(state); } diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 8c0b85c0c729..af8bd16ee681 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -17,15 +17,25 @@ #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/ValueManager.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/AST/StmtVisitor.h" using namespace clang; //===----------------------------------------------------------------------===// -// Basic methods. +// Object destruction. //===----------------------------------------------------------------------===// MemRegion::~MemRegion() {} +MemRegionManager::~MemRegionManager() { + // All regions and their data are BumpPtrAllocated. No need to call + // their destructors. +} + +//===----------------------------------------------------------------------===// +// Basic methods. +//===----------------------------------------------------------------------===// + bool SubRegion::isSubRegionOf(const MemRegion* R) const { const MemRegion* r = getSuperRegion(); while (r != 0) { @@ -126,15 +136,39 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const { ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion); } -void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const FunctionDecl *FD, - const MemRegion*) { - ID.AddInteger(MemRegion::CodeTextRegionKind); +void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const FunctionDecl *FD, + const MemRegion*) { + ID.AddInteger(MemRegion::FunctionTextRegionKind); ID.AddPointer(FD); } -void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { - CodeTextRegion::ProfileRegion(ID, FD, superRegion); +void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { + FunctionTextRegion::ProfileRegion(ID, FD, superRegion); +} + +void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockDecl *BD, CanQualType, + const MemRegion*) { + ID.AddInteger(MemRegion::BlockTextRegionKind); + ID.AddPointer(BD); +} + +void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { + BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion); +} + +void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockTextRegion *BC, + const LocationContext *LC, + const MemRegion *) { + ID.AddInteger(MemRegion::BlockDataRegionKind); + ID.AddPointer(BC); + ID.AddPointer(LC); +} + +void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { + BlockDataRegion::ProfileRegion(ID, BC, LC, NULL); } //===----------------------------------------------------------------------===// @@ -160,10 +194,19 @@ void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const { os << "alloca{" << (void*) Ex << ',' << Cnt << '}'; } -void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const { +void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const { os << "code{" << getDecl()->getDeclName().getAsString() << '}'; } +void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "block_code{" << (void*) this << '}'; +} + +void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "block_data{" << BC << '}'; +} + + void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { // FIXME: More elaborate pretty-printing. os << "{ " << (void*) CL << " }"; @@ -259,6 +302,18 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, return getRegion<VarRegion>(D, LC); } +BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, + const LocationContext *LC) +{ + // FIXME: Once we implement scope handling, we will need to properly lookup + // 'D' to the proper LocationContext. For now, just strip down to the + // StackFrame. + while (!isa<StackFrameContext>(LC)) + LC = LC->getParent(); + + return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion()); +} + CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) { return getRegion<CompoundLiteralRegion>(CL); @@ -287,10 +342,17 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, return R; } -CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) { - return getRegion<CodeTextRegion>(FD); +FunctionTextRegion * +MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) { + return getRegion<FunctionTextRegion>(FD); +} + +BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy) { + return getRegion<BlockTextRegion>(BD, locTy); } + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) { return getRegion<SymbolicRegion>(sym); @@ -473,3 +535,53 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { return RegionRawOffset(superR, offset); } +//===----------------------------------------------------------------------===// +// BlockDataRegion +//===----------------------------------------------------------------------===// + +void BlockDataRegion::LazyInitializeReferencedVars() { + if (ReferencedVars) + return; + + AnalysisContext *AC = LC->getAnalysisContext(); + AnalysisContext::referenced_decls_iterator I, E; + llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); + + if (I == E) { + ReferencedVars = (void*) 0x1; + return; + } + + MemRegionManager &MemMgr = *getMemRegionManager(); + llvm::BumpPtrAllocator &A = MemMgr.getAllocator(); + BumpVectorContext BC(A); + + typedef BumpVector<const MemRegion*> VarVec; + VarVec *BV = (VarVec*) A.Allocate<VarVec>(); + new (BV) VarVec(BC, (E - I) / sizeof(*I)); + + for ( ; I != E; ++I) + BV->push_back(MemMgr.getVarRegion(*I, LC), BC); + + ReferencedVars = BV; +} + +BlockDataRegion::referenced_vars_iterator +BlockDataRegion::referenced_vars_begin() const { + const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars(); + + BumpVector<const MemRegion*> *Vec = + static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); + + return Vec == (void*) 0x1 ? NULL : Vec->begin(); +} + +BlockDataRegion::referenced_vars_iterator +BlockDataRegion::referenced_vars_end() const { + const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars(); + + BumpVector<const MemRegion*> *Vec = + static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); + + return Vec == (void*) 0x1 ? NULL : Vec->end(); +} diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp index e0a8d0dc5f73..2ff04878f7ab 100644 --- a/lib/Analysis/NSAutoreleasePoolChecker.cpp +++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp @@ -19,14 +19,13 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "BasicObjCFoundationChecks.h" -#include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN NSAutoreleasePoolChecker +class NSAutoreleasePoolChecker : public CheckerVisitor<NSAutoreleasePoolChecker> { Selector releaseS; @@ -65,6 +64,9 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, // the type of the expression. const ObjCObjectPointerType* PT = receiver->getType()->getAs<ObjCObjectPointerType>(); + + if (!PT) + return; const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); if (!OD) return; diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp index 93b617b115d9..e3cf57fd0c1b 100644 --- a/lib/Analysis/NSErrorChecker.cpp +++ b/lib/Analysis/NSErrorChecker.cpp @@ -20,7 +20,6 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" -#include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" @@ -28,7 +27,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN NSErrorChecker : public BugType { +class NSErrorChecker : public BugType { const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; @@ -117,7 +116,7 @@ void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { BR.EmitBasicReport(isNSErrorWarning ? "Bad return type when passing NSError**" : "Bad return type when passing CFError*", - getCategory().c_str(), os.str().c_str(), + getCategory(), os.str(), CodeDecl.getLocation()); } @@ -229,7 +228,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, os << Param->getNameAsString() << "' may be null."; - BugReport *report = new BugReport(*this, os.str().c_str(), *I); + BugReport *report = new BugReport(*this, os.str(), *I); // FIXME: Notable symbols are now part of the report. We should // add support for notable symbols in BugReport. // BR.addNotableSymbol(SV->getSymbol()); diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp index 93823484e1d0..370233ce38bd 100644 --- a/lib/Analysis/PointerArithChecker.cpp +++ b/lib/Analysis/PointerArithChecker.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PointerArithChecker +class PointerArithChecker : public CheckerVisitor<PointerArithChecker> { BuiltinBug *BT; public: @@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || isa<CompoundLiteralRegion>(LR)) { - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Dangerous pointer arithmetic", "Pointer arithmetic done on non-array variables " diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp index 4c7906f4beba..c597a2580751 100644 --- a/lib/Analysis/PointerSubChecker.cpp +++ b/lib/Analysis/PointerSubChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PointerSubChecker +class PointerSubChecker : public CheckerVisitor<PointerSubChecker> { BuiltinBug *BT; public: @@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Pointer subtraction", "Subtraction of two pointers that do not point to " diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp index 66206616b008..e95095c7975e 100644 --- a/lib/Analysis/PthreadLockChecker.cpp +++ b/lib/Analysis/PthreadLockChecker.cpp @@ -21,7 +21,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PthreadLockChecker +class PthreadLockChecker : public CheckerVisitor<PthreadLockChecker> { BugType *BT; public: @@ -42,7 +42,7 @@ public: } // end anonymous namespace // GDM Entry for tracking lock state. -namespace { class VISIBILITY_HIDDEN LockSet {}; } +namespace { class LockSet {}; } namespace clang { template <> struct GRStateTrait<LockSet> : public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { @@ -59,8 +59,8 @@ void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); - const CodeTextRegion *R = - dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion()); + const FunctionTextRegion *R = + dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); if (!R) return; diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index f5cae698f924..7330b6261479 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -17,7 +17,6 @@ #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Analysis/ManagerRegistry.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" #in |