diff options
338 files changed, 14006 insertions, 5659 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cd52d0d946b..7f4ab33b33a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ macro(add_clang_library name) set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag}) endif(MSVC) install(TARGETS ${name} - LIBRARY DESTINATION lib + LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) endmacro(add_clang_library) @@ -83,8 +83,12 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/include ) -install(DIRECTORY include - DESTINATION . +install(DIRECTORY include/ + DESTINATION include + FILES_MATCHING + PATTERN "*.def" + PATTERN "*.h" + PATTERN "*.td" PATTERN ".svn" EXCLUDE ) diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 24e1ac360f72..2b4aa04ca33c 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; }; 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; }; 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */; }; + 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; }; 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; }; 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; }; 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; }; @@ -399,6 +400,7 @@ 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; }; 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = "<group>"; tabWidth = 2; }; 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; }; @@ -515,6 +517,13 @@ 9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = "<group>"; }; 9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = "<group>"; }; 90129120104812F90083456D /* CIndex.exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CIndex.exports; path = tools/CIndex/CIndex.exports; sourceTree = "<group>"; }; + 904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = "<group>"; }; + 9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = "<group>"; }; + 9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = "<group>"; }; + 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = "<group>"; }; + 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = "<group>"; }; + 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = "<group>"; }; + 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = "<group>"; }; 9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = "<group>"; }; 9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; }; 9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = "<group>"; }; @@ -1257,6 +1266,7 @@ 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */, 35A3E7010DD3874400757F74 /* CGDebugInfo.h */, DE4264FB0C113592005A861D /* CGDecl.cpp */, + 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */, DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */, DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */, DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */, @@ -1298,6 +1308,13 @@ DEC8D98B0A9433BC00353FCA /* AST */ = { isa = PBXGroup; children = ( + 904753791096376F00CBDDDD /* CXXInheritance.h */, + 9047537A1096376F00CBDDDD /* Redeclarable.h */, + 9047537B1096376F00CBDDDD /* TypeLoc.h */, + 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */, + 9047537D1096376F00CBDDDD /* TypeLocNodes.def */, + 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */, + 9047537F1096376F00CBDDDD /* TypeVisitor.h */, DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */, DE613EF30E0E148D00B05B79 /* APValue.h */, DEC8D9A30A94346E00353FCA /* AST.h */, @@ -1901,6 +1918,7 @@ 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */, 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */, 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */, + 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 9ac35e1dc2dc..1c892fd23a5a 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -20,6 +20,7 @@ td { <ul> <li><a href="#intro">Introduction</a></li> <li><a href="#feature_check">Feature Checking Macros</a></li> +<li><a href="#has_include">Include File Checking Macros</a></li> <li><a href="#builtinmacros">Builtin Macros</a></li> <li><a href="#vectors">Vectors and Extended Vectors</a></li> <li><a href="#blocks">Blocks</a></li> @@ -112,6 +113,69 @@ can be used like this:</p> <p>The feature tag is described along with the language feature below.</p> +<!-- ======================================================================= --> +<h2 id="has_include">Include File Checking Macros</h2> +<!-- ======================================================================= --> + +<p>Not all developments systems have the same include files. +The <a href="#__has_include">__has_include</a> and +<a href="#__has_include_next">__has_include_next</a> macros allow you to +check for the existence of an include file before doing +a possibly failing #include directive.</p> + +<!-- ======================================================================= --> +<h3 id="__has_include">__has_include</h3> +<!-- ======================================================================= --> + +<p>This function-like macro takes a single file name string argument that +is the name of an include file. It evaluates to 1 if the file can +be found using the include paths, or 0 otherwise:</p> + +<blockquote> +<pre> +// Note the two possible file name string formats. +#if __has_include("myinclude.h") && __has_include(<stdint.h>) +# include "myinclude.h" +#endif + +// To avoid problem with non-clang compilers not having this macro. +#if defined(__has_include) && __has_include("myinclude.h") +# include "myinclude.h" +#endif +</pre> +</blockquote> + +<p>To test for this feature, use #if defined(__has_include).</p> + +<!-- ======================================================================= --> +<h3 id="__has_include_next">__has_include_next</h3> +<!-- ======================================================================= --> + +<p>This function-like macro takes a single file name string argument that +is the name of an include file. It is like __has_include except that it +looks for the second instance of the given file found in the include +paths. It evaluates to 1 if the second instance of the file can +be found using the include paths, or 0 otherwise:</p> + +<blockquote> +<pre> +// Note the two possible file name string formats. +#if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>) +# include_next "myinclude.h" +#endif + +// To avoid problem with non-clang compilers not having this macro. +#if defined(__has_include_next) && __has_include_next("myinclude.h") +# include_next "myinclude.h" +#endif +</pre> +</blockquote> + +<p>Note that __has_include_next, like the GNU extension +#include_next directive, is intended for use in headers only, +and will issue a warning if used in the top-level compilation +file. A warning will also be issued if an absolute path +is used in the file argument.</p> <!-- ======================================================================= --> <h2 id="builtinmacros">Builtin Macros</h2> diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod index daa738798930..42cf8fa2d711 100644 --- a/docs/tools/clang.pod +++ b/docs/tools/clang.pod @@ -424,6 +424,10 @@ Add the specified directory to the search path for framework include files. Do not search the standard system directories for include files. +=item B<-nobuiltininc> + +Do not search clang's builtin directory for include files. + =cut ## TODO, but do we really want people using this stuff? diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 44cbe0efff81..1a58f44ff4c2 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -16,10 +16,23 @@ #ifndef CLANG_C_INDEX_H #define CLANG_C_INDEX_H +#include <sys/stat.h> + #ifdef __cplusplus extern "C" { #endif +/* MSVC DLL import/export. */ +#ifdef _MSC_VER + #ifdef _CINDEX_LIB_ + #define CINDEX_LINKAGE __declspec(dllexport) + #else + #define CINDEX_LINKAGE __declspec(dllimport) + #endif +#else + #define CINDEX_LINKAGE +#endif + /* Clang indeX abstractions. The backing store for the following API's will be clangs AST file (currently based on PCH). AST files are created as follows: @@ -33,6 +46,7 @@ typedef void *CXIndex; /* An indexing instance. */ typedef void *CXTranslationUnit; /* A translation unit instance. */ +typedef void *CXFile; /* A source file */ typedef void *CXDecl; /* A specific declaration within a translation unit. */ typedef void *CXStmt; /* A specific statement within a function/method */ @@ -138,22 +152,22 @@ typedef void *CXEntity; * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks * (which gives the indexer the same performance benefit as the compiler). */ -CXIndex clang_createIndex(int excludeDeclarationsFromPCH, +CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics); -void clang_disposeIndex(CXIndex); +CINDEX_LINKAGE void clang_disposeIndex(CXIndex); -const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); +CINDEX_LINKAGE const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); /* * \brief Create a translation unit from an AST file (-emit-ast). */ -CXTranslationUnit clang_createTranslationUnit( +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( CXIndex, const char *ast_filename ); /** * \brief Destroy the specified CXTranslationUnit object. */ -void clang_disposeTranslationUnit(CXTranslationUnit); +CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); /** * \brief Return the CXTranslationUnit for a given source file and the provided @@ -170,7 +184,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit); * '-o <output file>' (both '-o' and '<output file>' are ignored) * */ -CXTranslationUnit clang_createTranslationUnitFromSourceFile( +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( CXIndex CIdx, const char *source_filename /* specify NULL if the source file is in clang_command_line_args */, int num_clang_command_line_args, @@ -197,7 +211,7 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile( typedef void *CXClientData; typedef void (*CXTranslationUnitIterator)(CXTranslationUnit, CXCursor, CXClientData); -void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator, +CINDEX_LINKAGE void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator, CXClientData); /* @@ -227,23 +241,30 @@ void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator, */ typedef void (*CXDeclIterator)(CXDecl, CXCursor, CXClientData); -void clang_loadDeclaration(CXDecl, CXDeclIterator, CXClientData); +CINDEX_LINKAGE void clang_loadDeclaration(CXDecl, CXDeclIterator, CXClientData); + +/* + * CXFile Operations. + */ +CINDEX_LINKAGE const char *clang_getFileName(CXFile SFile); +CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile); /* * CXEntity Operations. */ -const char *clang_getDeclarationName(CXEntity); -const char *clang_getURI(CXEntity); -CXEntity clang_getEntity(const char *URI); +CINDEX_LINKAGE const char *clang_getDeclarationName(CXEntity); +CINDEX_LINKAGE const char *clang_getURI(CXEntity); +CINDEX_LINKAGE CXEntity clang_getEntity(const char *URI); /* * CXDecl Operations. */ -CXCursor clang_getCursorFromDecl(CXDecl); -CXEntity clang_getEntityFromDecl(CXDecl); -const char *clang_getDeclSpelling(CXDecl); -unsigned clang_getDeclLine(CXDecl); -unsigned clang_getDeclColumn(CXDecl); -const char *clang_getDeclSource(CXDecl); +CINDEX_LINKAGE CXCursor clang_getCursorFromDecl(CXDecl); +CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXDecl); +CINDEX_LINKAGE const char *clang_getDeclSpelling(CXDecl); +CINDEX_LINKAGE unsigned clang_getDeclLine(CXDecl); +CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl); +CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */ +CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl); /* * CXCursor Operations. @@ -252,38 +273,24 @@ const char *clang_getDeclSource(CXDecl); Usage: clang_getCursor() will translate a source/line/column position into an AST cursor (to derive semantic information from the source code). */ -CXCursor clang_getCursor(CXTranslationUnit, const char *source_name, +CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, const char *source_name, unsigned line, unsigned column); -/** - Usage: clang_getCursorWithHint() provides the same functionality as - clang_getCursor() except that it takes an option 'hint' argument. - The 'hint' is a temporary CXLookupHint object (whose lifetime is managed by - the caller) that should be initialized with clang_initCXLookupHint(). - - FIXME: Add a better comment once getCursorWithHint() has more functionality. - */ -typedef CXCursor CXLookupHint; -CXCursor clang_getCursorWithHint(CXTranslationUnit, const char *source_name, - unsigned line, unsigned column, - CXLookupHint *hint); - -void clang_initCXLookupHint(CXLookupHint *hint); - -enum CXCursorKind clang_getCursorKind(CXCursor); -unsigned clang_isDeclaration(enum CXCursorKind); -unsigned clang_isReference(enum CXCursorKind); -unsigned clang_isDefinition(enum CXCursorKind); -unsigned clang_isInvalid(enum CXCursorKind); +CINDEX_LINKAGE enum CXCursorKind clang_getCursorKind(CXCursor); +CINDEX_LINKAGE unsigned clang_isDeclaration(enum CXCursorKind); +CINDEX_LINKAGE unsigned clang_isReference(enum CXCursorKind); +CINDEX_LINKAGE unsigned clang_isDefinition(enum CXCursorKind); +CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind); -unsigned clang_getCursorLine(CXCursor); -unsigned clang_getCursorColumn(CXCursor); -const char *clang_getCursorSource(CXCursor); -const char *clang_getCursorSpelling(CXCursor); +CINDEX_LINKAGE unsigned clang_getCursorLine(CXCursor); +CINDEX_LINKAGE unsigned clang_getCursorColumn(CXCursor); +CINDEX_LINKAGE const char *clang_getCursorSpelling(CXCursor); +CINDEX_LINKAGE const char *clang_getCursorSource(CXCursor); /* deprecate */ +CINDEX_LINKAGE CXFile clang_getCursorSourceFile(CXCursor); /* for debug/testing */ -const char *clang_getCursorKindSpelling(enum CXCursorKind Kind); -void clang_getDefinitionSpellingAndExtent(CXCursor, +CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind); +CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, const char **startBuf, const char **endBuf, unsigned *startLine, @@ -296,7 +303,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor, * declaration. * If CXCursorKind == Cursor_Declaration, then this will return the declaration. */ -CXDecl clang_getCursorDecl(CXCursor); +CINDEX_LINKAGE CXDecl clang_getCursorDecl(CXCursor); #ifdef __cplusplus } diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 30896c91a143..7392170be995 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -16,6 +16,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" @@ -301,22 +302,22 @@ public: const char *getCommentForDecl(const Decl *D); // Builtin Types. - QualType VoidTy; - QualType BoolTy; - QualType CharTy; - QualType WCharTy; // [C++ 3.9.1p5], integer type in C99. - QualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. - QualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. - QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; - QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; - QualType UnsignedLongLongTy, UnsignedInt128Ty; - QualType FloatTy, DoubleTy, LongDoubleTy; - QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; - QualType VoidPtrTy, NullPtrTy; - QualType OverloadTy; - QualType DependentTy; - QualType UndeducedAutoTy; - QualType ObjCBuiltinIdTy, ObjCBuiltinClassTy; + CanQualType VoidTy; + CanQualType BoolTy; + CanQualType CharTy; + CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. + CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. + CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; + CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; + CanQualType UnsignedLongLongTy, UnsignedInt128Ty; + CanQualType FloatTy, DoubleTy, LongDoubleTy; + CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; + CanQualType VoidPtrTy, NullPtrTy; + CanQualType OverloadTy; + CanQualType DependentTy; + CanQualType UndeducedAutoTy; + CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, @@ -387,10 +388,16 @@ public: /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); + CanQualType getComplexType(CanQualType T) { + return CanQualType::CreateUnsafe(getComplexType((QualType) T)); + } /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. QualType getPointerType(QualType T); + CanQualType getPointerType(CanQualType T) { + return CanQualType::CreateUnsafe(getPointerType((QualType) T)); + } /// getBlockPointerType - Return the uniqued reference to the type for a block /// of the specified type. @@ -525,6 +532,11 @@ public: unsigned NumArgs, QualType Canon = QualType()); + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + QualType Canon = QualType()); + QualType getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType); QualType getTypenameType(NestedNameSpecifier *NNS, @@ -728,6 +740,8 @@ public: TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name); + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator); enum GetBuiltinTypeError { GE_None, //< No error @@ -739,7 +753,7 @@ public: QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error); private: - QualType getFromTargetType(unsigned Type) const; + CanQualType getFromTargetType(unsigned Type) const; //===--------------------------------------------------------------------===// // Type Predicates. @@ -826,6 +840,8 @@ public: llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI); unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD); + void CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols); //===--------------------------------------------------------------------===// // Type Operators @@ -1013,7 +1029,9 @@ public: bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS); bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); - + QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + // Functions for calculating composite types QualType mergeTypes(QualType, QualType); QualType mergeFunctionTypes(QualType, QualType); @@ -1085,12 +1103,18 @@ public: /// should be calculated based on the type. DeclaratorInfo *CreateDeclaratorInfo(QualType T, unsigned Size = 0); + /// \brief Allocate a DeclaratorInfo where all locations have been + /// initialized to a given location, which defaults to the empty + /// location. + DeclaratorInfo * + getTrivialDeclaratorInfo(QualType T, SourceLocation Loc = SourceLocation()); + private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT void operator=(const ASTContext&); // DO NOT IMPLEMENT void InitBuiltinTypes(); - void InitBuiltinType(QualType &R, BuiltinType::Kind K); + void InitBuiltinType(CanQualType &R, BuiltinType::Kind K); // Return the ObjC type encoding for a given type. void getObjCEncodingForTypeImpl(QualType t, std::string &S, @@ -1103,6 +1127,18 @@ private: const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); }; + +/// @brief Utility function for constructing a nullary selector. +static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(0, &II); +} + +/// @brief Utility function for constructing an unary selector. +static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(1, &II); +} } // end namespace clang diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 8b84bc267997..a7750517090e 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -64,15 +64,6 @@ public: CanQual(const CanQual<U>& Other, typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0); - /// \brief Implicit conversion to the underlying pointer. - /// - /// Also provides the ability to use canonical types in a boolean context, - /// e.g., - /// @code - /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } - /// @endcode - operator const T*() const { return getTypePtr(); } - /// \brief Retrieve the underlying type pointer, which refers to a /// canonical type. T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); } @@ -80,6 +71,10 @@ public: /// \brief Implicit conversion to a qualified type. operator QualType() const { return Stored; } + bool isNull() const { + return Stored.isNull(); + } + /// \brief Retrieve a canonical type pointer with a different static type, /// upcasting or downcasting as needed. /// @@ -125,8 +120,10 @@ public: /// \brief Retrieve the unqualified form of this type. CanQual<T> getUnqualifiedType() const; - CanQual<T> getQualifiedType(unsigned TQs) const { - return CanQual<T>::CreateUnsafe(QualType(getTypePtr(), TQs)); + /// \brief Retrieves a version of this type with const applied. + /// Note that this does not always yield a canonical type. + QualType withConst() const { + return Stored.withConst(); } /// \brief Determines whether this canonical type is more qualified than diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 72ce0d852cfc..813e83accdb1 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -605,6 +605,9 @@ public: /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a static data member. bool isOutOfLine() const; + + /// \brief If this is a static data member, find its out-of-line definition. + VarDecl *getOutOfLineDefinition(); /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member @@ -768,7 +771,11 @@ public: Init = (UnparsedDefaultArgument *)0; } - QualType getOriginalType() const; + QualType getOriginalType() const { + if (getDeclaratorInfo()) + return getDeclaratorInfo()->getType(); + return getType(); + } /// setOwningFunction - Sets the function declaration that owns this /// ParmVarDecl. Since ParmVarDecls are often created before the @@ -778,41 +785,11 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { - return (D->getKind() == ParmVar || - D->getKind() == OriginalParmVar); + return (D->getKind() == ParmVar); } static bool classof(const ParmVarDecl *D) { return true; } }; -/// OriginalParmVarDecl - Represent a parameter to a function, when -/// the type of the parameter has been promoted. This node represents the -/// parameter to the function with its original type. -/// -class OriginalParmVarDecl : public ParmVarDecl { - friend class ParmVarDecl; -protected: - QualType OriginalType; -private: - OriginalParmVarDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo, - QualType OT, StorageClass S, - Expr *DefArg) - : ParmVarDecl(OriginalParmVar, DC, L, Id, T, DInfo, S, DefArg), - OriginalType(OT) {} -public: - static OriginalParmVarDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L,IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, - QualType OT, StorageClass S, Expr *DefArg); - - void setOriginalType(QualType T) { OriginalType = T; } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == OriginalParmVar; } - static bool classof(const OriginalParmVarDecl *D) { return true; } -}; - /// FunctionDecl - An instance of this class is created to represent a /// function declaration or definition. /// @@ -1067,9 +1044,18 @@ public: StorageClass getStorageClass() const { return StorageClass(SClass); } void setStorageClass(StorageClass SC) { SClass = SC; } - bool isInline() const { return IsInline; } - void setInline(bool I) { IsInline = I; } + /// \brief Determine whether the "inline" keyword was specified for this + /// function. + bool isInlineSpecified() const { return IsInline; } + + /// Set whether the "inline" keyword was specified for this function. + void setInlineSpecified(bool I) { IsInline = I; } + /// \brief Determine whether this function should be inlined, because it is + /// either marked "inline" or is a member function of a C++ class that + /// was defined in the class body. + bool isInlined() const; + bool isInlineDefinitionExternallyVisible() const; /// isOverloadedOperator - Whether this function declaration @@ -1146,7 +1132,17 @@ public: return TemplateOrSpecialization. dyn_cast<FunctionTemplateSpecializationInfo*>(); } - + + /// \brief Determines whether this function is a function template + /// specialization or a member of a class template specialization that can + /// be implicitly instantiated. + bool isImplicitlyInstantiable() const; + + /// \brief Retrieve the function declaration from which this function could + /// be instantiated, if it is an instantiation (rather than a non-template + /// or a specialization, for example). + FunctionDecl *getTemplateInstantiationPattern() const; + /// \brief Retrieve the primary template that this function template /// specialization either specializes or was instantiated from. /// @@ -1199,7 +1195,7 @@ public: /// instantiated from a template; otherwie, returns an invalid source /// location. SourceLocation getPointOfInstantiation() const; - + /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a member function. bool isOutOfLine() const; @@ -1337,20 +1333,29 @@ public: class TypedefDecl : public TypeDecl { /// UnderlyingType - This is the type the typedef is set to. - QualType UnderlyingType; + DeclaratorInfo *DInfo; + TypedefDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T) - : TypeDecl(Typedef, DC, L, Id), UnderlyingType(T) {} + IdentifierInfo *Id, DeclaratorInfo *DInfo) + : TypeDecl(Typedef, DC, L, Id), DInfo(DInfo) {} virtual ~TypedefDecl() {} public: static TypedefDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L,IdentifierInfo *Id, - QualType T); + SourceLocation L, IdentifierInfo *Id, + DeclaratorInfo *DInfo); + + DeclaratorInfo *getTypeDeclaratorInfo() const { + return DInfo; + } - QualType getUnderlyingType() const { return UnderlyingType; } - void setUnderlyingType(QualType newType) { UnderlyingType = newType; } + QualType getUnderlyingType() const { + return DInfo->getType(); + } + void setTypeDeclaratorInfo(DeclaratorInfo *newType) { + DInfo = newType; + } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == Typedef; } diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 790ea3ca0662..e1fae8f2ae67 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_AST_DECLGROUP_H #define LLVM_CLANG_AST_DECLGROUP_H -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <cassert> namespace clang { diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index 79a0d368288c..3ef3cc3f0975 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -103,7 +103,6 @@ ABSTRACT_DECL(Named, Decl) DECL(Var, DeclaratorDecl) DECL(ImplicitParam, VarDecl) DECL(ParmVar, VarDecl) - DECL(OriginalParmVar, ParmVarDecl) DECL(NonTypeTemplateParm, VarDecl) DECL(Template, NamedDecl) DECL(FunctionTemplate, TemplateDecl) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 729a2f138303..bcd28eab039f 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -347,6 +347,8 @@ public: ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; + ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const; // Marks the end of the container. SourceLocation getAtEndLoc() const { return AtEndLoc; } @@ -862,7 +864,7 @@ public: }; class ObjCImplDecl : public ObjCContainerDecl { - /// Class interface for this category implementation + /// Class interface for this class/category implementation ObjCInterfaceDecl *ClassInterface; protected: @@ -935,14 +937,20 @@ public: SourceLocation L, IdentifierInfo *Id, ObjCInterfaceDecl *classInterface); - /// getIdentifier - Get the identifier that names the class + /// getIdentifier - Get the identifier that names the category /// interface associated with this implementation. + /// FIXME: This is a bad API, we are overriding the NamedDecl::getIdentifier() + /// to mean something different. For example: + /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier() + /// returns the class interface name, whereas + /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier() + /// returns the category name. IdentifierInfo *getIdentifier() const { return Id; } void setIdentifier(IdentifierInfo *II) { Id = II; } - ObjCCategoryDecl *getCategoryClass() const; + ObjCCategoryDecl *getCategoryDecl() const; /// getName - Get the name of identifier for the class interface associated /// with this implementation as a StringRef. diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 8d44676124fb..f1a27933a1b3 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -15,8 +15,7 @@ #define LLVM_CLANG_AST_DECLTEMPLATE_H #include "clang/AST/DeclCXX.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/FoldingSet.h" +#include "clang/AST/TemplateBase.h" #include "llvm/ADT/PointerUnion.h" #include <limits> @@ -91,6 +90,13 @@ public: /// arguments or if there is a parameter pack. unsigned getMinRequiredArguments() const; + /// \brief Get the depth of this template parameter list in the set of + /// template parameter lists. + /// + /// The first template parameter list in a declaration will have depth 0, + /// the second template parameter list will have depth 1, etc. + unsigned getDepth() const; + SourceLocation getTemplateLoc() const { return TemplateLoc; } SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; } @@ -100,251 +106,6 @@ public: } }; -/// \brief Represents a template argument within a class template -/// specialization. -class TemplateArgument { - union { - uintptr_t TypeOrValue; - struct { - char Value[sizeof(llvm::APSInt)]; - void *Type; - } Integer; - struct { - TemplateArgument *Args; - unsigned NumArgs; - bool CopyArgs; - } Args; - }; - - /// \brief Location of the beginning of this template argument. - SourceLocation StartLoc; - -public: - /// \brief The type of template argument we're storing. - enum ArgKind { - Null = 0, - /// The template argument is a type. Its value is stored in the - /// TypeOrValue field. - Type = 1, - /// The template argument is a declaration - Declaration = 2, - /// The template argument is an integral value stored in an llvm::APSInt. - Integral = 3, - /// The template argument is a value- or type-dependent expression - /// stored in an Expr*. - Expression = 4, - - /// The template argument is actually a parameter pack. Arguments are stored - /// in the Args struct. - Pack = 5 - } Kind; - - /// \brief Construct an empty, invalid template argument. - TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { } - - /// \brief Construct a template type argument. - TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) { - TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); - StartLoc = Loc; - } - - /// \brief Construct a template argument that refers to a - /// declaration, which is either an external declaration or a - /// template declaration. - TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) { - // FIXME: Need to be sure we have the "canonical" declaration! - TypeOrValue = reinterpret_cast<uintptr_t>(D); - StartLoc = Loc; - } - - /// \brief Construct an integral constant template argument. - TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value, - QualType Type) - : Kind(Integral) { - new (Integer.Value) llvm::APSInt(Value); - Integer.Type = Type.getAsOpaquePtr(); - StartLoc = Loc; - } - - /// \brief Construct a template argument that is an expression. - /// - /// This form of template argument only occurs in template argument - /// lists used for dependent types and for expression; it will not - /// occur in a non-dependent, canonical template argument list. - TemplateArgument(Expr *E); - - /// \brief Copy constructor for a template argument. - TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { - if (Kind == Integral) { - new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); - Integer.Type = Other.Integer.Type; - } else if (Kind == Pack) { - Args.NumArgs = Other.Args.NumArgs; - Args.Args = new TemplateArgument[Args.NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = Other.Args.Args[I]; - } - else - TypeOrValue = Other.TypeOrValue; - StartLoc = Other.StartLoc; - } - - TemplateArgument& operator=(const TemplateArgument& Other) { - // FIXME: Does not provide the strong guarantee for exception - // safety. - using llvm::APSInt; - - // FIXME: Handle Packs - assert(Kind != Pack && "FIXME: Handle packs"); - assert(Other.Kind != Pack && "FIXME: Handle packs"); - - if (Kind == Other.Kind && Kind == Integral) { - // Copy integral values. - *this->getAsIntegral() = *Other.getAsIntegral(); - Integer.Type = Other.Integer.Type; - } else { - // Destroy the current integral value, if that's what we're holding. - if (Kind == Integral) - getAsIntegral()->~APSInt(); - - Kind = Other.Kind; - - if (Other.Kind == Integral) { - new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); - Integer.Type = Other.Integer.Type; - } else - TypeOrValue = Other.TypeOrValue; - } - StartLoc = Other.StartLoc; - - return *this; - } - - ~TemplateArgument() { - using llvm::APSInt; - - if (Kind == Integral) - getAsIntegral()->~APSInt(); - else if (Kind == Pack && Args.CopyArgs) - delete[] Args.Args; - } - - /// \brief Return the kind of stored template argument. - ArgKind getKind() const { return Kind; } - - /// \brief Determine whether this template argument has no value. - bool isNull() const { return Kind == Null; } - - /// \brief Retrieve the template argument as a type. - QualType getAsType() const { - if (Kind != Type) - return QualType(); - - return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue)); - } - - /// \brief Retrieve the template argument as a declaration. - Decl *getAsDecl() const { - if (Kind != Declaration) - return 0; - return reinterpret_cast<Decl *>(TypeOrValue); - } - - /// \brief Retrieve the template argument as an integral value. - llvm::APSInt *getAsIntegral() { - if (Kind != Integral) - return 0; - return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]); - } - - const llvm::APSInt *getAsIntegral() const { - return const_cast<TemplateArgument*>(this)->getAsIntegral(); - } - - /// \brief Retrieve the type of the integral value. - QualType getIntegralType() const { - if (Kind != Integral) - return QualType(); - - return QualType::getFromOpaquePtr(Integer.Type); - } - - void setIntegralType(QualType T) { - assert(Kind == Integral && - "Cannot set the integral type of a non-integral template argument"); - Integer.Type = T.getAsOpaquePtr(); - }; - - /// \brief Retrieve the template argument as an expression. - Expr *getAsExpr() const { - if (Kind != Expression) - return 0; - - return reinterpret_cast<Expr *>(TypeOrValue); - } - - /// \brief Iterator that traverses the elements of a template argument pack. - typedef const TemplateArgument * pack_iterator; - - /// \brief Iterator referencing the first argument of a template argument - /// pack. - pack_iterator pack_begin() const { - assert(Kind == Pack); - return Args.Args; - } - - /// \brief Iterator referencing one past the last argument of a template - /// argument pack. - pack_iterator pack_end() const { - assert(Kind == Pack); - return Args.Args + Args.NumArgs; - } - - /// \brief The number of template arguments in the given template argument - /// pack. - unsigned pack_size() const { - assert(Kind == Pack); - return Args.NumArgs; - } - - /// \brief Retrieve the location where the template argument starts. - SourceLocation getLocation() const { return StartLoc; } - - /// \brief Construct a template argument pack. - void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs); - - /// \brief Used to insert TemplateArguments into FoldingSets. - void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const { - ID.AddInteger(Kind); - switch (Kind) { - case Null: - break; - - case Type: - getAsType().Profile(ID); - break; - - case Declaration: - ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); - break; - - case Integral: - getAsIntegral()->Profile(ID); - getIntegralType().Profile(ID); - break; - - case Expression: - getAsExpr()->Profile(ID, Context, true); - break; - - case Pack: - ID.AddInteger(Args.NumArgs); - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I].Profile(ID, Context); - } - } -}; - /// \brief A helper class for making template argument lists. class TemplateArgumentListBuilder { TemplateArgument *StructuredArgs; @@ -811,11 +572,8 @@ class TemplateTypeParmDecl : public TypeDecl { /// \brief Whether this is a parameter pack. bool ParameterPack : 1; - /// \brief The location of the default argument, if any. - SourceLocation DefaultArgumentLoc; - /// \brief The default template argument, if any. - QualType DefaultArgument; + DeclaratorInfo *DefaultArgument; TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, bool Typename, QualType Type, bool ParameterPack) @@ -837,13 +595,16 @@ public: /// \brief Determine whether this template parameter has a default /// argument. - bool hasDefaultArgument() const { return !DefaultArgument.isNull(); } + bool hasDefaultArgument() const { return DefaultArgument != 0; } /// \brief Retrieve the default argument, if any. - QualType getDefaultArgument() const { return DefaultArgument; } + QualType getDefaultArgument() const { return DefaultArgument->getType(); } - /// \brief Retrieve the location of the default argument, if any. - SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; } + /// \brief Retrieves the default argument's source information, if any. + DeclaratorInfo *getDefaultArgumentInfo() const { return DefaultArgument; } + + /// \brief Retrieves the location of the default argument declaration. + SourceLocation getDefaultArgumentLoc() const; /// \brief Determines whether the default argument was inherited /// from a previous declaration of this template. @@ -852,13 +613,23 @@ public: /// \brief Set the default argument for this template parameter, and /// whether that default argument was inherited from another /// declaration. - void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc, - bool Inherited) { + void setDefaultArgument(DeclaratorInfo *DefArg, bool Inherited) { DefaultArgument = DefArg; - DefaultArgumentLoc = DefArgLoc; InheritedDefault = Inherited; } + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { + DefaultArgument = 0; + InheritedDefault = false; + } + + /// \brief Retrieve the depth of the template parameter. + unsigned getDepth() const; + + /// \brief Retrieve the index of the template parameter. + unsigned getIndex() const; + /// \brief Returns whether this is a parameter pack. bool isParameterPack() const { return ParameterPack; } @@ -1150,17 +921,32 @@ class ClassTemplatePartialSpecializationDecl /// \brief The list of template parameters TemplateParameterList* TemplateParams; + /// \brief The source info for the template arguments as written. + TemplateArgumentLoc *ArgsAsWritten; + unsigned NumArgsAsWritten; + + /// \brief The class template partial specialization from which this + /// class template partial specialization was instantiated. + /// + /// The boolean value will be true to indicate that this class template + /// partial specialization was specialized at this level. + llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool> + InstantiatedFromMember; + ClassTemplatePartialSpecializationDecl(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, DC, L, SpecializedTemplate, Builder, PrevDecl), - TemplateParams(Params) { } + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), InstantiatedFromMember(0, false) { } public: static ClassTemplatePartialSpecializationDecl * @@ -1168,6 +954,8 @@ public: TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl); /// Get the list of template parameters @@ -1175,6 +963,80 @@ public: return TemplateParams; } + /// Get the template arguments as written. + TemplateArgumentLoc *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// Get the number of template arguments as written. + unsigned getNumTemplateArgsAsWritten() const { + return NumArgsAsWritten; + } + + /// \brief Retrieve the member class template partial specialization from + /// which this particular class template partial specialization was + /// instantiated. + /// + /// \code + /// template<typename T> + /// struct Outer { + /// template<typename U> struct Inner; + /// template<typename U> struct Inner<U*> { }; // #1 + /// }; + /// + /// Outer<float>::Inner<int*> ii; + /// \endcode + /// + /// In this example, the instantiation of \c Outer<float>::Inner<int*> will + /// end up instantiating the partial specialization + /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class + /// template partial specialization \c Outer<T>::Inner<U*>. Given + /// \c Outer<float>::Inner<U*>, this function would return + /// \c Outer<T>::Inner<U*>. + ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *PartialSpec) { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + First->InstantiatedFromMember.setPointer(PartialSpec); + } + + /// \brief Determines whether this class template partial specialization + /// template was a specialization of a member partial specialization. + /// + /// In the following example, the member template partial specialization + /// \c X<int>::Inner<T*> is a member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> struct Inner; + /// template<typename U> struct Inner<U*>; + /// }; + /// + /// template<> template<typename T> + /// struct X<int>::Inner<T*> { /* ... */ }; + /// \endcode + bool isMemberSpecialization() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } + // FIXME: Add Profile support! static bool classof(const Decl *D) { diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 0d09ea325c31..2a87f5883588 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -34,6 +34,7 @@ namespace clang { class BlockDecl; class CXXOperatorCallExpr; class CXXMemberCallExpr; + class TemplateArgumentLoc; /// 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 @@ -134,7 +135,7 @@ public: /// with location to warn on and the source range[s] to report with the /// warning. bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, - SourceRange &R2) const; + SourceRange &R2, ASTContext &Ctx) const; /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or /// incomplete type other than void. Nonarray expressions that can be lvalues: @@ -241,6 +242,10 @@ public: /// in Result. bool Evaluate(EvalResult &Result, ASTContext &Ctx) const; + /// EvaluateAsAny - The same as Evaluate, except that it also succeeds on + /// stack based objects. + bool EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const; + /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. bool isEvaluatable(ASTContext &Ctx) const; @@ -322,47 +327,221 @@ public: // Primary Expressions. //===----------------------------------------------------------------------===// +/// \brief Represents the qualifier that may precede a C++ name, e.g., the +/// "std::" in "std::sort". +struct NameQualifier { + /// \brief The nested name specifier. + NestedNameSpecifier *NNS; + + /// \brief The source range covered by the nested name specifier. + SourceRange Range; +}; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +struct ExplicitTemplateArgumentList { + /// \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. + /// The actual template arguments (if any) are stored after the + /// ExplicitTemplateArgumentList structure. + unsigned NumTemplateArgs; + + /// \brief Retrieve the template arguments + TemplateArgumentLoc *getTemplateArgs() { + return reinterpret_cast<TemplateArgumentLoc *> (this + 1); + } + + /// \brief Retrieve the template arguments + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgumentLoc *> (this + 1); + } +}; + /// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function, /// enum, etc. class DeclRefExpr : public Expr { - NamedDecl *D; + enum { + // Flag on DecoratedD that specifies when this declaration reference + // expression has a C++ nested-name-specifier. + HasQualifierFlag = 0x01, + // Flag on DecoratedD that specifies when this declaration reference + // expression has an explicit C++ template argument list. + HasExplicitTemplateArgumentListFlag = 0x02 + }; + + // DecoratedD - The declaration that we are referencing, plus two bits to + // indicate whether (1) the declaration's name was explicitly qualified and + // (2) the declaration's name was followed by an explicit template + // argument list. + llvm::PointerIntPair<NamedDecl *, 2> DecoratedD; + + // Loc - The location of the declaration name itself. SourceLocation Loc; + /// \brief Retrieve the qualifier that preceded the declaration name, if any. + NameQualifier *getNameQualifier() { + if ((DecoratedD.getInt() & HasQualifierFlag) == 0) + return 0; + + return reinterpret_cast<NameQualifier *> (this + 1); + } + + /// \brief Retrieve the qualifier that preceded the member name, if any. + const NameQualifier *getNameQualifier() const { + return const_cast<DeclRefExpr *>(this)->getNameQualifier(); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { + if ((DecoratedD.getInt() & HasExplicitTemplateArgumentListFlag) == 0) + return 0; + + if ((DecoratedD.getInt() & HasQualifierFlag) == 0) + return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); + + return reinterpret_cast<ExplicitTemplateArgumentList *>( + getNameQualifier() + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { + return const_cast<DeclRefExpr *>(this)->getExplicitTemplateArgumentList(); + } + + 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); + 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), D(d), Loc(l) {} + Expr(SC, t), DecoratedD(d, 0), Loc(l) {} DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : - Expr(SC, t, TD, VD), D(d), Loc(l) {} + Expr(SC, t, TD, VD), DecoratedD(d, 0), Loc(l) {} 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), D(d), Loc(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), D(d), Loc(l) {} + Expr(DeclRefExprClass, t, TD, VD), DecoratedD(d, 0), Loc(l) {} /// \brief Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) { } - NamedDecl *getDecl() { return D; } - const NamedDecl *getDecl() const { return D; } - void setDecl(NamedDecl *NewD) { D = NewD; } + static DeclRefExpr *Create(ASTContext &Context, + NestedNameSpecifier *Qualifier, + 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); + + NamedDecl *getDecl() { return DecoratedD.getPointer(); } + const NamedDecl *getDecl() const { return DecoratedD.getPointer(); } + void setDecl(NamedDecl *NewD) { DecoratedD.setPointer(NewD); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + virtual SourceRange getSourceRange() const; + /// \brief Determine whether this declaration reference was preceded by a + /// C++ nested-name-specifier, e.g., \c N::foo. + bool hasQualifier() const { return DecoratedD.getInt() & HasQualifierFlag; } + + /// \brief If the name was qualified, retrieves the source range of + /// the nested-name-specifier that precedes the name. Otherwise, + /// returns an empty source range. + SourceRange getQualifierRange() const { + if (!hasQualifier()) + return SourceRange(); + + return getNameQualifier()->Range; + } + + /// \brief If the name was qualified, retrieves the nested-name-specifier + /// that precedes the name. Otherwise, returns NULL. + NestedNameSpecifier *getQualifier() const { + if (!hasQualifier()) + return 0; + + return getNameQualifier()->NNS; + } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgumentList() const { + return DecoratedD.getInt() & HasExplicitTemplateArgumentListFlag; + } + + /// \brief Retrieve the location of the left angle bracket following the + /// member name ('<'), if any. + SourceLocation getLAngleLoc() const { + if (!hasExplicitTemplateArgumentList()) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgumentList()) + return 0; + + return getExplicitTemplateArgumentList()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgumentList()) + return 0; + + return getExplicitTemplateArgumentList()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket following the + /// template arguments ('>'). + SourceLocation getRAngleLoc() const { + if (!hasExplicitTemplateArgumentList()) + return SourceLocation(); + + return getExplicitTemplateArgumentList()->RAngleLoc; + } + static bool classof(const Stmt *T) { return T->getStmtClass() == DeclRefExprClass || - T->getStmtClass() == CXXConditionDeclExprClass || - T->getStmtClass() == QualifiedDeclRefExprClass; + T->getStmtClass() == CXXConditionDeclExprClass; } static bool classof(const DeclRefExpr *) { return true; } @@ -797,7 +976,7 @@ class SizeOfAlignOfExpr : public Expr { bool isSizeof : 1; // true if sizeof, false if alignof. bool isType : 1; // true if operand is a type, false if an expression union { - void *Ty; + DeclaratorInfo *Ty; Stmt *Ex; } Argument; SourceLocation OpLoc, RParenLoc; @@ -806,15 +985,15 @@ protected: virtual void DoDestroy(ASTContext& C); public: - SizeOfAlignOfExpr(bool issizeof, QualType T, + SizeOfAlignOfExpr(bool issizeof, DeclaratorInfo *DInfo, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(SizeOfAlignOfExprClass, resultType, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. - T->isDependentType()), + DInfo->getType()->isDependentType()), isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) { - Argument.Ty = T.getAsOpaquePtr(); + Argument.Ty = DInfo; } SizeOfAlignOfExpr(bool issizeof, Expr *E, @@ -837,8 +1016,11 @@ public: bool isArgumentType() const { return isType; } QualType getArgumentType() const { + return getArgumentTypeInfo()->getType(); + } + DeclaratorInfo *getArgumentTypeInfo() const { assert(isArgumentType() && "calling getArgumentType() when arg is expr"); - return QualType::getFromOpaquePtr(Argument.Ty); + return Argument.Ty; } Expr *getArgumentExpr() { assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); @@ -849,8 +1031,8 @@ public: } void setArgument(Expr *E) { Argument.Ex = E; isType = false; } - void setArgument(QualType T) { - Argument.Ty = T.getAsOpaquePtr(); + void setArgument(DeclaratorInfo *DInfo) { + Argument.Ty = DInfo; isType = true; } @@ -1062,41 +1244,6 @@ public: virtual child_iterator child_end(); }; -/// \brief Represents the qualifier that may precede a C++ name, e.g., the -/// "std::" in "std::sort". -struct NameQualifier { - /// \brief The nested name specifier. - NestedNameSpecifier *NNS; - - /// \brief The source range covered by the nested name specifier. - SourceRange Range; -}; - -/// \brief Represents an explicit template argument list in C++, e.g., -/// the "<int>" in "sort<int>". -struct ExplicitTemplateArgumentList { - /// \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. - /// The actual template arguments (if any) are stored after the - /// ExplicitTemplateArgumentList structure. - unsigned NumTemplateArgs; - - /// \brief Retrieve the template arguments - TemplateArgument *getTemplateArgs() { - return reinterpret_cast<TemplateArgument *> (this + 1); - } - - /// \brief Retrieve the template arguments - const TemplateArgument *getTemplateArgs() const { - return reinterpret_cast<const TemplateArgument *> (this + 1); - } -}; - /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr : public Expr { @@ -1161,7 +1308,7 @@ class MemberExpr : public Expr { MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, unsigned numtargs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty); public: @@ -1183,7 +1330,7 @@ public: SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty); @@ -1240,7 +1387,7 @@ public: /// \brief Retrieve the template arguments provided as part of this /// template-id. - const TemplateArgument *getTemplateArgs() const { + const TemplateArgumentLoc *getTemplateArgs() const { if (!HasExplicitTemplateArgumentList) return 0; @@ -1388,6 +1535,10 @@ public: /// member pointer in derived class. CK_BaseToDerivedMemberPointer, + /// CK_DerivedToBaseMemberPointer - Member pointer in derived class to + /// member pointer in base class. + CK_DerivedToBaseMemberPointer, + /// CK_UserDefinedConversion - Conversion using a user defined type /// conversion function. CK_UserDefinedConversion, @@ -1687,7 +1838,9 @@ public: bool isAdditiveOp() const { return Opc == Add || Opc == Sub; } static bool isShiftOp(Opcode Opc) { return Opc == Shl || Opc == Shr; } bool isShiftOp() const { return isShiftOp(Opc); } - bool isBitwiseOp() const { return Opc >= And && Opc <= Or; } + + static bool isBitwiseOp(Opcode Opc) { return Opc >= And && Opc <= Or; } + bool isBitwiseOp() const { return isBitwiseOp(Opc); } static bool isRelationalOp(Opcode Opc) { return Opc >= LT && Opc <= GE; } bool isRelationalOp() const { return isRelationalOp(Opc); } @@ -1695,6 +1848,9 @@ public: static bool isEqualityOp(Opcode Opc) { return Opc == EQ || Opc == NE; } bool isEqualityOp() const { return isEqualityOp(Opc); } + static bool isComparisonOp(Opcode Opc) { return Opc >= LT && Opc <= NE; } + bool isComparisonOp() const { return isComparisonOp(Opc); } + static bool isLogicalOp(Opcode Opc) { return Opc == LAnd || Opc == LOr; } bool isLogicalOp() const { return isLogicalOp(Opc); } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 3f66b1f40bfc..5931a3fcf984 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1061,46 +1061,11 @@ public: virtual child_iterator child_end(); }; -/// QualifiedDeclRefExpr - A reference to a declared variable, -/// function, enum, etc., that includes a qualification, e.g., -/// "N::foo". -class QualifiedDeclRefExpr : public DeclRefExpr { - /// QualifierRange - The source range that covers the - /// nested-name-specifier. - SourceRange QualifierRange; - - /// \brief The nested-name-specifier that qualifies this declaration - /// name. - NestedNameSpecifier *NNS; - -public: - QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, - bool VD, SourceRange R, NestedNameSpecifier *NNS) - : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), - QualifierRange(R), NNS(NNS) { } - - /// \brief Retrieve the source range of the nested-name-specifier. - SourceRange getQualifierRange() const { return QualifierRange; } - - /// \brief Retrieve the nested-name-specifier that qualifies this - /// declaration. - NestedNameSpecifier *getQualifier() const { return NNS; } - - virtual SourceRange getSourceRange() const { - return SourceRange(QualifierRange.getBegin(), getLocation()); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == QualifiedDeclRefExprClass; - } - static bool classof(const QualifiedDeclRefExpr *) { return true; } -}; - /// \brief A qualified reference to a name whose declaration cannot /// yet be resolved. /// -/// UnresolvedDeclRefExpr is similar to QualifiedDeclRefExpr in that -/// it expresses a qualified reference to a declaration such as +/// UnresolvedDeclRefExpr is similar to eclRefExpr 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 /// the qualification (e.g., X<T>::) refers to a dependent type. In @@ -1108,8 +1073,8 @@ public: /// declaration will differ from on instantiation of X<T> to the /// next. Therefore, UnresolvedDeclRefExpr keeps track of the /// qualifier (X<T>::) and the name of the entity being referenced -/// ("value"). Such expressions will instantiate to -/// QualifiedDeclRefExprs. +/// ("value"). Such expressions will instantiate to a DeclRefExpr once the +/// declaration can be found. class UnresolvedDeclRefExpr : public Expr { /// The name of the entity we will be referencing. DeclarationName Name; @@ -1126,6 +1091,7 @@ class UnresolvedDeclRefExpr : public Expr { NestedNameSpecifier *NNS; /// \brief Whether this expr is an address of (&) operand. + /// FIXME: Stash this bit into NNS! bool IsAddressOfOperand; public: @@ -1195,7 +1161,7 @@ class TemplateIdRefExpr : public Expr { NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); @@ -1206,7 +1172,7 @@ public: Create(ASTContext &Context, QualType T, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, + SourceLocation LAngleLoc, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); /// \brief Retrieve the nested name specifier used to qualify the name of @@ -1232,8 +1198,8 @@ public: /// \brief Retrieve the template arguments provided as part of this /// template-id. - const TemplateArgument *getTemplateArgs() const { - return reinterpret_cast<const TemplateArgument *>(this + 1); + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgumentLoc *>(this + 1); } /// \brief Retrieve the number of template arguments provided as part of this @@ -1477,7 +1443,7 @@ class CXXUnresolvedMemberExpr : public Expr { SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); @@ -1508,7 +1474,7 @@ public: SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); @@ -1576,7 +1542,7 @@ public: /// \brief Retrieve the template arguments provided as part of this /// template-id. - const TemplateArgument *getTemplateArgs() const { + const TemplateArgumentLoc *getTemplateArgs() const { if (!HasExplicitTemplateArgumentList) return 0; diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 7490b1d66b3e..5f318ba0b33b 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_AST_LAYOUTINFO_H #define LLVM_CLANG_AST_LAYOUTINFO_H -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" namespace clang { class ASTContext; diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index 458af1f14423..1e6871ff3b9c 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -88,6 +88,11 @@ public: return D; } + /// \brief Returns the most recent (re)declaration of this declaration. + const decl_type *getMostRecentDeclaration() const { + return getFirstDeclaration()->RedeclLink.getNext(); + } + /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the /// first and only declaration. void setPreviousDeclaration(decl_type *PrevDecl) { diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h index 2d523fffce74..f1aa2cd50f0f 100644 --- a/include/clang/AST/StmtIterator.h +++ b/include/clang/AST/StmtIterator.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_AST_STMT_ITR_H #define LLVM_CLANG_AST_STMT_ITR_H -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <cassert> #include <iterator> diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 8d7e4b5fc0a3..034029a16971 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -127,7 +127,6 @@ EXPR(CXXDeleteExpr , Expr) EXPR(CXXPseudoDestructorExpr, Expr) EXPR(UnresolvedFunctionNameExpr , Expr) EXPR(UnaryTypeTraitExpr , Expr) -EXPR(QualifiedDeclRefExpr , DeclRefExpr) EXPR(UnresolvedDeclRefExpr , Expr) EXPR(TemplateIdRefExpr , Expr) EXPR(CXXConstructExpr , Expr) diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h new file mode 100644 index 000000000000..bb14c62d7770 --- /dev/null +++ b/include/clang/AST/TemplateBase.h @@ -0,0 +1,366 @@ +//===-- TemplateBase.h - Core classes for C++ templates ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definitions which are common for all kinds of +// template representation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H +#define LLVM_CLANG_AST_TEMPLATEBASE_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/Support/ErrorHandling.h" +#include "clang/AST/Type.h" + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + +class Decl; +class Expr; +class DeclaratorInfo; + +/// \brief Represents a template argument within a class template +/// specialization. +class TemplateArgument { + union { + uintptr_t TypeOrValue; + struct { + char Value[sizeof(llvm::APSInt)]; + void *Type; + } Integer; + struct { + TemplateArgument *Args; + unsigned NumArgs; + bool CopyArgs; + } Args; + }; + +public: + /// \brief The type of template argument we're storing. + enum ArgKind { + Null = 0, + /// The template argument is a type. Its value is stored in the + /// TypeOrValue field. + Type = 1, + /// The template argument is a declaration + Declaration = 2, + /// The template argument is an integral value stored in an llvm::APSInt. + Integral = 3, + /// The template argument is a value- or type-dependent expression + /// stored in an Expr*. + Expression = 4, + + /// The template argument is actually a parameter pack. Arguments are stored + /// in the Args struct. + Pack = 5 + } Kind; + + /// \brief Construct an empty, invalid template argument. + TemplateArgument() : TypeOrValue(0), Kind(Null) { } + + /// \brief Construct a template type argument. + TemplateArgument(QualType T) : Kind(Type) { + TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + } + + /// \brief Construct a template argument that refers to a + /// declaration, which is either an external declaration or a + /// template declaration. + TemplateArgument(Decl *D) : Kind(Declaration) { + // FIXME: Need to be sure we have the "canonical" declaration! + TypeOrValue = reinterpret_cast<uintptr_t>(D); + } + + /// \brief Construct an integral constant template argument. + TemplateArgument(const llvm::APSInt &Value, QualType Type) + : Kind(Integral) { + new (Integer.Value) llvm::APSInt(Value); + Integer.Type = Type.getAsOpaquePtr(); + } + + /// \brief Construct a template argument that is an expression. + /// + /// This form of template argument only occurs in template argument + /// lists used for dependent types and for expression; it will not + /// occur in a non-dependent, canonical template argument list. + TemplateArgument(Expr *E) : Kind(Expression) { + TypeOrValue = reinterpret_cast<uintptr_t>(E); + } + + /// \brief Copy constructor for a template argument. + TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { + if (Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else if (Kind == Pack) { + Args.NumArgs = Other.Args.NumArgs; + Args.Args = new TemplateArgument[Args.NumArgs]; + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I] = Other.Args.Args[I]; + } + else + TypeOrValue = Other.TypeOrValue; + } + + TemplateArgument& operator=(const TemplateArgument& Other) { + // FIXME: Does not provide the strong guarantee for exception + // safety. + using llvm::APSInt; + + // FIXME: Handle Packs + assert(Kind != Pack && "FIXME: Handle packs"); + assert(Other.Kind != Pack && "FIXME: Handle packs"); + + if (Kind == Other.Kind && Kind == Integral) { + // Copy integral values. + *this->getAsIntegral() = *Other.getAsIntegral(); + Integer.Type = Other.Integer.Type; + } else { + // Destroy the current integral value, if that's what we're holding. + if (Kind == Integral) + getAsIntegral()->~APSInt(); + + Kind = Other.Kind; + + if (Other.Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else + TypeOrValue = Other.TypeOrValue; + } + + return *this; + } + + ~TemplateArgument() { + using llvm::APSInt; + + if (Kind == Integral) + getAsIntegral()->~APSInt(); + else if (Kind == Pack && Args.CopyArgs) + delete[] Args.Args; + } + + /// \brief Return the kind of stored template argument. + ArgKind getKind() const { return Kind; } + + /// \brief Determine whether this template argument has no value. + bool isNull() const { return Kind == Null; } + + /// \brief Retrieve the template argument as a type. + QualType getAsType() const { + if (Kind != Type) + return QualType(); + + return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue)); + } + + /// \brief Retrieve the template argument as a declaration. + Decl *getAsDecl() const { + if (Kind != Declaration) + return 0; + return reinterpret_cast<Decl *>(TypeOrValue); + } + + /// \brief Retrieve the template argument as an integral value. + llvm::APSInt *getAsIntegral() { + if (Kind != Integral) + return 0; + return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]); + } + + const llvm::APSInt *getAsIntegral() const { + return const_cast<TemplateArgument*>(this)->getAsIntegral(); + } + + /// \brief Retrieve the type of the integral value. + QualType getIntegralType() const { + if (Kind != Integral) + return QualType(); + + return QualType::getFromOpaquePtr(Integer.Type); + } + + void setIntegralType(QualType T) { + assert(Kind == Integral && + "Cannot set the integral type of a non-integral template argument"); + Integer.Type = T.getAsOpaquePtr(); + }; + + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + if (Kind != Expression) + return 0; + + return reinterpret_cast<Expr *>(TypeOrValue); + } + + /// \brief Iterator that traverses the elements of a template argument pack. + typedef const TemplateArgument * pack_iterator; + + /// \brief Iterator referencing the first argument of a template argument + /// pack. + pack_iterator pack_begin() const { + assert(Kind == Pack); + return Args.Args; + } + + /// \brief Iterator referencing one past the last argument of a template + /// argument pack. + pack_iterator pack_end() const { + assert(Kind == Pack); + return Args.Args + Args.NumArgs; + } + + /// \brief The number of template arguments in the given template argument + /// pack. + unsigned pack_size() const { + assert(Kind == Pack); + return Args.NumArgs; + } + + /// \brief Construct a template argument pack. + void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs); + + /// \brief Used to insert TemplateArguments into FoldingSets. + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const; +}; + +/// Location information for a TemplateArgument. +struct TemplateArgumentLocInfo { +private: + union { + Expr *Expression; + DeclaratorInfo *Declarator; + }; + +#ifndef NDEBUG + enum Kind { + K_None, + K_DeclaratorInfo, + K_Expression + } Kind; +#endif + +public: + TemplateArgumentLocInfo() + : Expression(0) +#ifndef NDEBUG + , Kind(K_None) +#endif + {} + + TemplateArgumentLocInfo(DeclaratorInfo *DInfo) + : Declarator(DInfo) +#ifndef NDEBUG + , Kind(K_DeclaratorInfo) +#endif + {} + + TemplateArgumentLocInfo(Expr *E) + : Expression(E) +#ifndef NDEBUG + , Kind(K_Expression) +#endif + {} + + DeclaratorInfo *getAsDeclaratorInfo() const { + assert(Kind == K_DeclaratorInfo); + return Declarator; + } + + Expr *getAsExpr() const { + assert(Kind == K_Expression); + return Expression; + } + +#ifndef NDEBUG + void validateForArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Type: + assert(Kind == K_DeclaratorInfo); + break; + case TemplateArgument::Expression: + case TemplateArgument::Declaration: + assert(Kind == K_Expression); + break; + case TemplateArgument::Integral: + case TemplateArgument::Pack: + assert(Kind == K_None); + break; + case TemplateArgument::Null: + llvm::llvm_unreachable("source info for null template argument?"); + } + } +#endif +}; + +/// Location wrapper for a TemplateArgument. TemplateArgument is to +/// TemplateArgumentLoc as Type is to TypeLoc. +class TemplateArgumentLoc { + TemplateArgument Argument; + TemplateArgumentLocInfo LocInfo; + +public: + TemplateArgumentLoc() {} + + TemplateArgumentLoc(const TemplateArgument &Argument, + TemplateArgumentLocInfo Opaque) + : Argument(Argument), LocInfo(Opaque) { + } + + TemplateArgumentLoc(const TemplateArgument &Argument, DeclaratorInfo *DInfo) + : Argument(Argument), LocInfo(DInfo) { + assert(Argument.getKind() == TemplateArgument::Type); + } + + TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) + : Argument(Argument), LocInfo(E) { + assert(Argument.getKind() == TemplateArgument::Expression); + } + + /// \brief - Fetches the start location of the argument. + SourceLocation getLocation() const { + return getSourceRange().getBegin(); + } + + /// \brief - Fetches the full source range of the argument. + SourceRange getSourceRange() const; + + const TemplateArgument &getArgument() const { + return Argument; + } + + TemplateArgumentLocInfo getLocInfo() const { + return LocInfo; + } + + DeclaratorInfo *getSourceDeclaratorInfo() const { + assert(Argument.getKind() == TemplateArgument::Type); + return LocInfo.getAsDeclaratorInfo(); + } + + Expr *getSourceExpression() const { + assert(Argument.getKind() == TemplateArgument::Expression); + return LocInfo.getAsExpr(); + } + + Expr *getSourceDeclExpression() const { + assert(Argument.getKind() == TemplateArgument::Declaration); + return LocInfo.getAsExpr(); + } +}; + +} + +#endif diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 66ff34cf1e31..8ef8fb51416c 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -16,6 +16,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" +#include "clang/Basic/OperatorKinds.h" namespace llvm { class raw_ostream; @@ -224,10 +225,24 @@ public: class DependentTemplateName : public llvm::FoldingSetNode { /// \brief The nested name specifier that qualifies the template /// name. - NestedNameSpecifier *Qualifier; + /// + /// The bit stored in this qualifier describes whether the \c Name field + /// is interpreted as an IdentifierInfo pointer (when clear) or as an + /// overloaded operator kind (when set). + llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier; /// \brief The dependent template name. - const IdentifierInfo *Name; + union { + /// \brief The identifier template name. + /// + /// Only valid when the bit on \c Qualifier is clear. + const IdentifierInfo *Identifier; + + /// \brief The overloaded operator name. + /// + /// Only valid when the bit on \c Qualifier is set. + OverloadedOperatorKind Operator; + }; /// \brief The canonical template name to which this dependent /// template name refers. @@ -240,30 +255,70 @@ class DependentTemplateName : public llvm::FoldingSetNode { friend class ASTContext; DependentTemplateName(NestedNameSpecifier *Qualifier, - const IdentifierInfo *Name) - : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { } + const IdentifierInfo *Identifier) + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(this) { } DependentTemplateName(NestedNameSpecifier *Qualifier, - const IdentifierInfo *Name, + const IdentifierInfo *Identifier, TemplateName Canon) - : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { } + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(Canon) { } + DependentTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator) + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + TemplateName Canon) + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(Canon) { } + public: /// \brief Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier; } + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } - /// \brief Return the name to which this dependent template name - /// refers. - const IdentifierInfo *getName() const { return Name; } + /// \brief Determine whether this template name refers to an identifier. + bool isIdentifier() const { return !Qualifier.getInt(); } + /// \brief Returns the identifier to which this template name refers. + const IdentifierInfo *getIdentifier() const { + assert(isIdentifier() && "Template name isn't an identifier?"); + return Identifier; + } + + /// \brief Determine whether this template name refers to an overloaded + /// operator. + bool isOverloadedOperator() const { return Qualifier.getInt(); } + + /// \brief Return the overloaded operator to which this template name refers. + OverloadedOperatorKind getOperator() const { + assert(isOverloadedOperator() && + "Template name isn't an overloaded operator?"); + return Operator; + } + void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getQualifier(), getName()); + if (isIdentifier()) + Profile(ID, getQualifier(), getIdentifier()); + else + Profile(ID, getQualifier(), getOperator()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + const IdentifierInfo *Identifier) { + ID.AddPointer(NNS); + ID.AddBoolean(false); + ID.AddPointer(Identifier); } static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, - const IdentifierInfo *Name) { + OverloadedOperatorKind Operator) { ID.AddPointer(NNS); - ID.AddPointer(Name); + ID.AddBoolean(true); + ID.AddInteger(Operator); } }; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index db02a68a984d..daa814739182 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -81,6 +81,7 @@ namespace clang { class SourceLocation; class StmtIteratorBase; class TemplateArgument; + class TemplateArgumentLoc; class QualifiedNameType; struct PrintingPolicy; @@ -2275,12 +2276,19 @@ public: static bool anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, + unsigned NumArgs); + /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. static std::string PrintTemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs, const PrintingPolicy &Policy); + static std::string PrintTemplateArgumentList(const TemplateArgumentLoc *Args, + unsigned NumArgs, + const PrintingPolicy &Policy); + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 1d7181b531f8..da7857822e9c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_TYPELOC_H #include "clang/AST/Type.h" +#include "clang/AST/TemplateBase.h" namespace clang { class ParmVarDecl; @@ -82,6 +83,19 @@ public: return Data; } + /// \brief Get the full source range. + SourceRange getFullSourceRange() const { + SourceLocation End = getSourceRange().getEnd(); + TypeLoc Cur = *this; + while (true) { + TypeLoc Next = Cur.getNextTypeLoc(); + if (Next.isNull()) break; + Cur = Next; + } + return SourceRange(Cur.getSourceRange().getBegin(), End); + } + + /// \brief Get the local source range. SourceRange getSourceRange() const { return getSourceRangeImpl(*this); } @@ -761,6 +775,10 @@ public: getLocalData()->RBracketLoc = Loc; } + SourceRange getBracketsRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + Expr *getSizeExpr() const { return getLocalData()->Size; } @@ -810,6 +828,118 @@ class VariableArrayTypeLoc : VariableArrayType> { }; + +// Location information for a TemplateName. Rudimentary for now. +struct TemplateNameLocInfo { + SourceLocation NameLoc; +}; + +struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; +}; + +class TemplateSpecializationTypeLoc : + public ConcreteTypeLoc<UnqualTypeLoc, + TemplateSpecializationTypeLoc, + TemplateSpecializationType, + TemplateSpecializationLocInfo> { +public: + SourceLocation getLAngleLoc() const { + return getLocalData()->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return getLocalData()->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumArgs() const { + return getTypePtr()->getNumArgs(); + } + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { +#ifndef NDEBUG + AI.validateForArgument(getTypePtr()->getArg(i)); +#endif + getArgInfos()[i] = AI; + } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { + return getArgInfos()[i]; + } + + TemplateArgumentLoc getArgLoc(unsigned i) const { + return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + } + + SourceLocation getTemplateNameLoc() const { + return getLocalData()->NameLoc; + } + void setTemplateNameLoc(SourceLocation Loc) { + getLocalData()->NameLoc = Loc; + } + + /// \brief - Copy the location information from the given info. + void copy(TemplateSpecializationTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + + // We're potentially copying Expr references here. We don't + // bother retaining them because DeclaratorInfos live forever, so + // as long as the Expr was retained when originally written into + // the TypeLoc, we're okay. + memcpy(Data, Loc.Data, size); + } + + SourceRange getSourceRange() const { + return SourceRange(getTemplateNameLoc(), getRAngleLoc()); + } + + void initializeLocal(SourceLocation Loc) { + setLAngleLoc(Loc); + setRAngleLoc(Loc); + setTemplateNameLoc(Loc); + + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { + TemplateArgumentLocInfo Info; +#ifndef NDEBUG + // If asserts are enabled, be sure to initialize the argument + // loc with the right kind of pointer. + switch (getTypePtr()->getArg(i).getKind()) { + case TemplateArgument::Expression: + case TemplateArgument::Declaration: + Info = TemplateArgumentLocInfo((Expr*) 0); + break; + + case TemplateArgument::Type: + Info = TemplateArgumentLocInfo((DeclaratorInfo*) 0); + break; + + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + // K_None is fine. + break; + } +#endif + getArgInfos()[i] = Info; + } + } + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData()); + } +}; + // None of these types have proper implementations yet. class VectorTypeLoc : public TypeSpecTypeLoc<VectorTypeLoc, VectorType> { @@ -861,11 +991,6 @@ class ElaboratedTypeLoc : public TypeSpecTypeLoc<ElaboratedTypeLoc, ElaboratedType> { }; -class TemplateSpecializationTypeLoc - : public TypeSpecTypeLoc<TemplateSpecializationTypeLoc, - TemplateSpecializationType> { -}; - class QualifiedNameTypeLoc : public TypeSpecTypeLoc<QualifiedNameTypeLoc, QualifiedNameType> { }; diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h index fabeea38d597..5edfe6fea8db 100644 --- a/include/clang/Analysis/CallGraph.h +++ b/include/clang/Analysis/CallGraph.h @@ -17,7 +17,6 @@ #include "clang/Index/ASTLocation.h" #include "clang/Index/Entity.h" #include "clang/Index/Program.h" -#include "clang/Frontend/ASTUnit.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" @@ -87,7 +86,7 @@ public: CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; } - void addTU(ASTUnit &AST); + void addTU(ASTContext &AST); idx::Program &getProgram() { return Prog; } diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 8e02ccf38209..66e850a91444 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -80,6 +80,8 @@ protected: : Kind(k), Ctx(ctx), Parent(parent) {} public: + virtual ~LocationContext() {} + ContextKind getKind() const { return Kind; } AnalysisContext *getAnalysisContext() const { return Ctx; } @@ -102,7 +104,7 @@ public: return Ctx->getSelfDecl(); } - void Profile(llvm::FoldingSetNodeID &ID) { + virtual void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Kind, Ctx, Parent); } @@ -119,10 +121,13 @@ public: StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) : LocationContext(StackFrame, ctx, parent), CallSite(s) {} + + virtual ~StackFrameContext() {} + Stmt const *getCallSite() const { return CallSite; } - void Profile(llvm::FoldingSetNodeID &ID) { + virtual void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAnalysisContext(), getParent(), CallSite); } @@ -141,8 +146,10 @@ public: ScopeContext(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) : LocationContext(Scope, ctx, parent), Enter(s) {} + + virtual ~ScopeContext() {} - void Profile(llvm::FoldingSetNodeID &ID) { + virtual void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAnalysisContext(), getParent(), Enter); } diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index 1434fce811d1..914118cb430d 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -19,6 +19,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "clang/Analysis/PathSensitive/BugType.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -183,38 +184,6 @@ public: const_iterator end() const { return const_iterator(Reports.end()); } }; -class BugType { -private: - const std::string Name; - const std::string Category; - llvm::FoldingSet<BugReportEquivClass> EQClasses; - friend class BugReporter; - bool SuppressonSink; -public: - BugType(const char *name, const char* 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; } - - /// isSuppressOnSink - Returns true if bug reports associated with this bug - /// type should be suppressed if the end node of the report is post-dominated - /// by a sink node. - bool isSuppressOnSink() const { return SuppressonSink; } - void setSuppressOnSink(bool x) { SuppressonSink = x; } - - virtual void FlushReports(BugReporter& BR); - - typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator; - iterator begin() { return EQClasses.begin(); } - iterator end() { return EQClasses.end(); } - - typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator; - const_iterator begin() const { return EQClasses.begin(); } - const_iterator end() const { return EQClasses.end(); } -}; //===----------------------------------------------------------------------===// // Specialized subclasses of BugReport. diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h new file mode 100644 index 000000000000..46b3edd3172e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/BugType.h @@ -0,0 +1,86 @@ +//===--- BugType.h - Bug Information Desciption ----------------*- 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 BugType, a class representing a bug type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE +#define LLVM_CLANG_ANALYSIS_BUGTYPE + +#include <llvm/ADT/FoldingSet.h> +#include <string> + +namespace clang { + +class BugReportEquivClass; +class BugReporter; +class BuiltinBugReport; +class BugReporterContext; +class GRExprEngine; + +class BugType { +private: + const std::string Name; + const std::string Category; + llvm::FoldingSet<BugReportEquivClass> EQClasses; + friend class BugReporter; + bool SuppressonSink; +public: + BugType(const char *name, const char* 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; } + + /// isSuppressOnSink - Returns true if bug reports associated with this bug + /// type should be suppressed if the end node of the report is post-dominated + /// by a sink node. + bool isSuppressOnSink() const { return SuppressonSink; } + void setSuppressOnSink(bool x) { SuppressonSink = x; } + + virtual void FlushReports(BugReporter& BR); + + typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator; + iterator begin() { return EQClasses.begin(); } + iterator end() { return EQClasses.end(); } + + typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator; + const_iterator begin() const { return EQClasses.begin(); } + const_iterator end() const { return EQClasses.end(); } +}; + +class BuiltinBug : public BugType { + GRExprEngine &Eng; +protected: + const std::string desc; +public: + BuiltinBug(GRExprEngine *eng, const char* n, const char* d) + : BugType(n, "Logic errors"), Eng(*eng), desc(d) {} + + BuiltinBug(GRExprEngine *eng, const char* n) + : BugType(n, "Logic errors"), 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); +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index 4e00d69cdba1..3bef08d7545f 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -72,6 +72,10 @@ public: ASTContext &getASTContext() { return Eng.getContext(); } + + BugReporter &getBugReporter() { + return Eng.getBugReporter(); + } ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { return GenerateNode(S, getState(), markAsSink); @@ -104,16 +108,42 @@ private: GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *stmt, - ExplodedNode *Pred, bool isPrevisit) { - CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit); + ExplodedNode *Pred, void *tag, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit); assert(isPrevisit && "Only previsit supported for now."); _PreVisit(C, stmt); } + void GR_VisitBind(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, GRExprEngine &Eng, + const Stmt *stmt, ExplodedNode *Pred, void *tag, + SVal location, SVal val, + bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit); + assert(isPrevisit && "Only previsit supported for now."); + PreVisitBind(C, stmt, location, val); + } + public: virtual ~Checker() {} - virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0; - virtual const void *getTag() = 0; + virtual void _PreVisit(CheckerContext &C, const Stmt *ST) {} + + // This is a previsit which takes a node returns a node. + virtual ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred, + const GRState *state, SVal V, + GRExprEngine &Eng) { + return Pred; + } + + virtual void PreVisitBind(CheckerContext &C, const Stmt *ST, + SVal location, SVal val) {} + + virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, + GRExprEngine &Eng) { + return Pred; + } + }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h b/include/clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h new file mode 100644 index 000000000000..007ec093b2e0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h @@ -0,0 +1,28 @@ +//===--- AttrNonNullChecker.h - Undefined arguments 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 AttrNonNullChecker, a builtin check in GRExprEngine that +// performs checks for arguments declared to have nonnull attribute. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" + +namespace clang { + +class AttrNonNullChecker : public CheckerVisitor<AttrNonNullChecker> { + BugType *BT; + +public: + AttrNonNullChecker() : BT(0) {} + static void *getTag(); + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} diff --git a/include/clang/Analysis/PathSensitive/Checkers/BadCallChecker.h b/include/clang/Analysis/PathSensitive/Checkers/BadCallChecker.h new file mode 100644 index 000000000000..70f3c44165e0 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/BadCallChecker.h @@ -0,0 +1,30 @@ +//===--- 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" + +namespace clang { + +class BadCallChecker : public CheckerVisitor<BadCallChecker> { + BuiltinBug *BT; + +public: + BadCallChecker() : BT(0) {} + + static void *getTag(); + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} diff --git a/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h b/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h new file mode 100644 index 000000000000..688cf641491d --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h @@ -0,0 +1,53 @@ +//== NullDerefChecker.h - Null dereference 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 NullDerefChecker and UndefDerefChecker, two builtin checks +// in GRExprEngine that check for null and undefined pointers at loads +// and stores. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DEREFCHECKER +#define LLVM_CLANG_DEREFCHECKER + +#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Analysis/PathSensitive/BugType.h" + +namespace clang { + +class ExplodedNode; + +class NullDerefChecker : public Checker { + BuiltinBug *BT; + llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; + +public: + NullDerefChecker() : BT(0) {} + ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred, + const GRState *state, SVal V,GRExprEngine &Eng); + + static void *getTag(); + typedef llvm::SmallVectorImpl<ExplodedNode*>::iterator iterator; + iterator implicit_nodes_begin() { return ImplicitNullDerefNodes.begin(); } + iterator implicit_nodes_end() { return ImplicitNullDerefNodes.end(); } +}; + +class UndefDerefChecker : public Checker { + BuiltinBug *BT; +public: + UndefDerefChecker() : BT(0) {} + + ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred, + const GRState *state, SVal V, GRExprEngine &Eng); + + static void *getTag(); +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h b/include/clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h new file mode 100644 index 000000000000..317e43a0e62e --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h @@ -0,0 +1,28 @@ +//== DivZeroChecker.h - Division by zero 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 DivZeroChecker, a builtin check in GRExprEngine that performs +// checks for division by zeros. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" + +namespace clang { + +class DivZeroChecker : public CheckerVisitor<DivZeroChecker> { + BuiltinBug *BT; +public: + DivZeroChecker() : BT(0) {} + + static void *getTag(); + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; + +} diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h new file mode 100644 index 000000000000..7f4e7d524f6c --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h @@ -0,0 +1,34 @@ +//===--- UndefinedArgChecker.h - Undefined arguments 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 undefined arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_UNDEFARGCHECKER +#define LLVM_CLANG_UNDEFARGCHECKER + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" + +namespace clang { + +class UndefinedArgChecker : public CheckerVisitor<UndefinedArgChecker> { + BugType *BT; + +public: + UndefinedArgChecker() : BT(0) {} + + static void *getTag(); + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} +#endif diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h new file mode 100644 index 000000000000..7fee5011c46d --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h @@ -0,0 +1,32 @@ +//===--- 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 *S, SVal location, + SVal val); +}; +} +#endif + diff --git a/include/clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h b/include/clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h new file mode 100644 index 000000000000..b339b3d30141 --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h @@ -0,0 +1,39 @@ +//=== VLASizeChecker.h - Undefined dereference 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 two VLASizeCheckers, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of undefined or zero size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checker.h" + +namespace clang { + +class UndefSizedVLAChecker : public Checker { + BugType *BT; + +public: + UndefSizedVLAChecker() : BT(0) {} + static void *getTag(); + ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, GRExprEngine &Eng); +}; + +class ZeroSizedVLAChecker : public Checker { + BugType *BT; + +public: + ZeroSizedVLAChecker() : BT(0) {} + static void *getTag(); + ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, GRExprEngine &Eng); +}; + +} diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index e5c61e68c77c..2f2a11a83cea 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -75,7 +75,12 @@ class GRExprEngine : public GRSubEngine { Selector RaiseSel; llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor; - std::vector<Checker*> Checkers; + + typedef llvm::DenseMap<void *, unsigned> CheckerMap; + CheckerMap CheckerM; + + typedef std::vector<std::pair<void *, Checker*> >CheckersOrdered; + CheckersOrdered Checkers; /// BR - The BugReporter associated with this engine. It is important that // this object be placed at the very end of member variables so that its @@ -126,18 +131,6 @@ public: // calling a function with the attribute "noreturn". ErrorNodes NoReturnCalls; - /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from - /// taking a dereference on a symbolic pointer that MAY be NULL. - ErrorNodes ImplicitNullDeref; - - /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from - /// taking a dereference on a symbolic pointer that MUST be NULL. - ErrorNodes ExplicitNullDeref; - - /// UndefDeref - Nodes in the ExplodedGraph that result from - /// taking a dereference on an undefined value. - ErrorNodes UndefDeref; - /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from /// constructing a zero-sized VLA where the size may be zero. ErrorNodes ImplicitBadSizedVLA; @@ -158,10 +151,6 @@ public: /// ObjC message expressions where the receiver is undefined (uninitialized). ErrorNodes UndefReceivers; - /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions - /// where a pass-by-value argument has an undefined value. - UndefArgsTy UndefArgs; - /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from /// message expressions where a pass-by-value argument has an undefined /// value. @@ -195,6 +184,8 @@ public: BugReporter& getBugReporter() { return BR; } + GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; } + /// setTransferFunctions void setTransferFunctions(GRTransferFuncs* tf); @@ -217,8 +208,19 @@ public: void RegisterInternalChecks(); - void registerCheck(Checker *check) { - Checkers.push_back(check); + template <typename CHECKER> + void registerCheck(CHECKER *check) { + unsigned entry = Checkers.size(); + void *tag = CHECKER::getTag(); + Checkers.push_back(std::make_pair(tag, check)); + CheckerM[tag] = entry; + } + + Checker *lookupChecker(void *tag) const; + + template <typename CHECKER> + CHECKER *getChecker() const { + return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag())); } bool isRetStackAddr(const ExplodedNode* N) const { @@ -234,15 +236,15 @@ public: } bool isImplicitNullDeref(const ExplodedNode* N) const { - return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; + return false; } bool isExplicitNullDeref(const ExplodedNode* N) const { - return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0; + return false; } bool isUndefDeref(const ExplodedNode* N) const { - return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0; + return false; } bool isNoReturnCall(const ExplodedNode* N) const { @@ -254,13 +256,11 @@ public: } bool isBadCall(const ExplodedNode* N) const { - return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0; + return false; } bool isUndefArg(const ExplodedNode* N) const { - return N->isSink() && - (UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() || - MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end()); + return false; } bool isUndefReceiver(const ExplodedNode* N) const { @@ -279,17 +279,6 @@ public: undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } - typedef ErrorNodes::iterator null_deref_iterator; - null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); } - null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); } - - null_deref_iterator implicit_null_derefs_begin() { - return ImplicitNullDeref.begin(); - } - null_deref_iterator implicit_null_derefs_end() { - return ImplicitNullDeref.end(); - } - typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { @@ -312,10 +301,6 @@ public: return NilReceiverLargerThanVoidPtrRetExplicit.end(); } - typedef ErrorNodes::iterator undef_deref_iterator; - undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } - undef_deref_iterator undef_derefs_end() { return UndefDeref.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(); } @@ -325,9 +310,6 @@ public: bad_calls_iterator bad_calls_end() { return BadCalls.end(); } typedef UndefArgsTy::iterator undef_arg_iterator; - undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); } - undef_arg_iterator undef_arg_end() { return UndefArgs.end(); } - undef_arg_iterator msg_expr_undef_arg_begin() { return MsgExprUndefArgs.begin(); } @@ -427,7 +409,12 @@ public: protected: /// CheckerVisit - Dispatcher for performing checker-specific logic /// at specific statements. - void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); + void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + bool isPrevisit); + + void CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + SVal location, SVal val, bool isPrevisit); + /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. @@ -456,7 +443,8 @@ protected: ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. - void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitCall - Transfer function for function calls. @@ -578,8 +566,9 @@ protected: /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore, VisitDeclStmt, and others. - void EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, - const GRState* St, SVal location, SVal Val); + void EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, + const GRState* St, SVal location, SVal Val, + bool atDeclInit = false); public: void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index d8b9d560ccd8..8678ca9b5b9b 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -26,7 +26,7 @@ #include "clang/AST/ASTContext.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" @@ -219,11 +219,9 @@ public: const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; - const GRState *bindDecl(const VarDecl *VD, const LocationContext *LC, - SVal V) const; + const GRState *bindDecl(const VarRegion *VR, SVal V) const; - const GRState *bindDeclWithNoInit(const VarDecl *VD, - const LocationContext *LC) const; + const GRState *bindDeclWithNoInit(const VarRegion *VR) const; const GRState *bindLoc(Loc location, SVal V) const; @@ -602,15 +600,12 @@ inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V); } -inline const GRState *GRState::bindDecl(const VarDecl* VD, - const LocationContext *LC, - SVal IVal) const { - return getStateManager().StoreMgr->BindDecl(this, VD, LC, IVal); +inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { + return getStateManager().StoreMgr->BindDecl(this, VR, IVal); } -inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD, - const LocationContext *LC) const { - return getStateManager().StoreMgr->BindDeclWithNoInit(this, VD, LC); +inline const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const { + return getStateManager().StoreMgr->BindDeclWithNoInit(this, VR); } inline const GRState *GRState::bindLoc(Loc LV, SVal V) const { diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index 5f7b2cb0e327..40c1ed3224f4 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -23,7 +23,6 @@ namespace clang { class GRExprEngine; -class BugReporter; class ObjCMessageExpr; class GRStmtNodeBuilderRef; @@ -33,7 +32,7 @@ public: virtual ~GRTransferFuncs() {} virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} - virtual void RegisterChecks(BugReporter& BR) {} + virtual void RegisterChecks(GRExprEngine& Eng) {} // Calls. @@ -78,7 +77,7 @@ public: virtual const GRState* EvalAssume(const GRState *state, SVal Cond, bool Assumption) { return state; - } + } }; GRTransferFuncs *CreateCallInliner(ASTContext &ctx); diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 7a462c579f9f..6ca2e9e9aa68 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -134,12 +134,11 @@ public: SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0; - virtual const GRState *BindDecl(const GRState *ST, const VarDecl *VD, - const LocationContext *LC, SVal initVal) = 0; + virtual const GRState *BindDecl(const GRState *ST, const VarRegion *VR, + SVal initVal) = 0; virtual const GRState *BindDeclWithNoInit(const GRState *ST, - const VarDecl *VD, - const LocationContext *LC) = 0; + const VarRegion *VR) = 0; typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h index d3996c6330a2..167a102e94ec 100644 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -18,7 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/Support/Allocator.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseSet.h" diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 666e45b847cf..7aaae9c86653 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT #include "clang/Analysis/CFG.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index 3826d3a3acd6..afc63616e9fc 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -57,7 +57,6 @@ public: DISPATCH_CASE(Function,FunctionDecl) DISPATCH_CASE(Var,VarDecl) DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same) - DISPATCH_CASE(OriginalParmVar,OriginalParmVarDecl) // FIXME: (same) DISPATCH_CASE(ImplicitParam,ImplicitParamDecl) DISPATCH_CASE(EnumConstant,EnumConstantDecl) DISPATCH_CASE(Typedef,TypedefDecl) @@ -70,7 +69,6 @@ public: DEFAULT_DISPATCH(VarDecl) DEFAULT_DISPATCH(FunctionDecl) - DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl) DEFAULT_DISPATCH_VARDECL(ParmVarDecl) DEFAULT_DISPATCH(ImplicitParamDecl) DEFAULT_DISPATCH(EnumConstantDecl) diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 27997858c00c..98c703d94e92 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -329,7 +329,7 @@ BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:") BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:") BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") -BUILTIN(__builtin_expect, "iii" , "nc") +BUILTIN(__builtin_expect, "LiLiLi" , "nc") BUILTIN(__builtin_prefetch, "vvC*.", "nc") BUILTIN(__builtin_abort, "v", "Fnr") BUILTIN(__builtin_trap, "v", "nr") diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index cbf9cdbc1599..bb251ad73bd8 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -52,8 +52,4 @@ def warn_integer_too_large_for_signed : Warning< def note_invalid_subexpr_in_ice : Note< "subexpression not valid in an integer constant expression">; -// clang-cc -def err_pp_I_dash_not_supported : Error< - "-I- not supported, please use -iquote instead">; - } diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index dfdf0ff2e733..e2f11041dce2 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -55,6 +55,8 @@ def err_drv_command_signalled : Error< "%0 command failed due to signal %1 (use -v to see invocation)">; 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 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 e5c73270fdfc..ae8b92394443 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -12,6 +12,7 @@ let Component = "Frontend" in { def err_fe_unknown_triple : Error< "unknown target triple '%0', please use -triple or -arch">; def err_fe_unknown_target_abi : Error<"unknown target ABI '%0'">; +def err_fe_error_opening : Error<"error opening '%0': %1">; def err_fe_error_reading : Error<"error reading '%0'">; def err_fe_error_reading_stdin : Error<"error reading stdin">; def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; @@ -19,6 +20,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_dependency_file_requires_MT : Error< + "-dependency-file requires at least one -MT option">; def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; def note_fixit_in_macro : Note< diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 3f132c0dabfa..bbc551373d96 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -194,7 +194,8 @@ def err_pp_expected_eol : Error< "expected end of line in preprocessor expression">; def err_pp_defined_requires_identifier : Error< "operator 'defined' requires an identifier">; -def err_pp_missing_rparen : Error<"missing ')' after 'defined'">; +def err_pp_missing_lparen : Error<"missing '(' after '%0'">; +def err_pp_missing_rparen : Error<"missing ')' after '%0'">; def err_pp_colon_without_question : Error<"':' without preceding '?'">; def err_pp_division_by_zero : Error< "division by zero in preprocessor expression">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 19b0ea3932a5..db8d580a2cd7 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -117,6 +117,8 @@ def err_expected_semi_after_static_assert : Error< "expected ';' after static_assert">; def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; def err_expected_colon_after : Error<"expected ':' after %0">; +def err_pointer_to_member_type : Error< + "invalid use of pointer to member type after %0">; def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; def err_expected_string_literal : Error<"expected string literal">; @@ -124,6 +126,7 @@ def err_expected_asm_operand : Error< "expected string literal or '[' for asm operand">; def err_expected_selector_for_method : Error< "expected selector for Objective-C method">; +def err_expected_property_name : Error<"expected property name">; def err_unexpected_at : Error<"unexpected '@' in program">; @@ -213,7 +216,8 @@ def err_declaration_does_not_declare_param : Error< def err_no_matching_param : Error<"parameter named %0 is missing">; /// C++ parser diagnostics -def err_expected_unqualified_id : Error<"expected unqualified-id">; +def err_expected_unqualified_id : Error< + "expected %select{identifier|unqualified-id}0">; def err_func_def_no_params : Error< "function definition does not declare parameters">; def err_expected_lparen_after_type : Error< @@ -230,6 +234,8 @@ def err_expected_catch : Error<"expected catch">; def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; def err_using_namespace_in_class : Error< "'using namespace' in class not allowed">; +def err_ident_in_pseudo_dtor_not_a_type : Error< + "identifier %0 in pseudo-destructor expression does not name a type">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; @@ -279,6 +285,9 @@ def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-template">; def err_expected_type_name_after_typename : Error< "expected an identifier or template-id after '::'">; +def err_explicit_spec_non_template : Error< + "explicit %select{specialization|instantiation}0 of non-template " + "%select{class|struct|union}1 %2">; def err_variadic_templates : Error< "variadic templates are only allowed in C++0x">; @@ -286,7 +295,7 @@ def err_variadic_templates : Error< // C++ declarations def err_friend_decl_defines_class : Error< "cannot define a type in a friend declaration">; - + // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7a87e244f77c..99fddb581088 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -264,13 +264,19 @@ def warn_objc_property_copy_missing_on_block : Warning< "'copy' attribute must be specified for the block property " "when -fobjc-gc-only is specified">; def err_use_continuation_class : Error< - "attribute of property in continuation class of %0 can only be 'readwrite'">; + "property declaration in continuation class of %0 is to change a 'readonly' " + "property to 'readwrite'">; def err_continuation_class : Error<"continuation class has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< "missing context for property implementation declaration">; def error_bad_property_decl : Error< "property implementation must have its declaration in interface %0">; +def error_category_property : Error< + "property declared in category %0 cannot be implemented in " + "class implementation">; +def note_property_declare : Note< + "property declared here">; def error_synthesize_category_decl : Error< "@synthesize not allowed in a category's implementation">; def error_missing_property_interface : Error< @@ -613,6 +619,10 @@ def warn_attribute_wrong_decl_type : Warning< def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; +def err_cconv_knr : Error< + "function with no prototype cannot use '%0' calling convention">; +def err_cconv_varargs : Error< + "variadic function cannot use '%0' calling convention">; def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">; @@ -1014,7 +1024,11 @@ def note_partial_spec_unused_parameter : Note< def err_partial_spec_ordering_ambiguous : Error< "ambiguous partial specializations of %0">; def note_partial_spec_match : Note<"partial specialization matches %0">; - +def err_partial_spec_redeclared : Error< + "class template partial specialization %0 cannot be redeclared">; +def note_prev_partial_spec_here : Note< + "previous declaration of class template partial specialization %0 is here">; + // C++ Function template specializations def err_function_template_spec_no_match : Error< "no function template matches function template specialization %0">; @@ -1326,17 +1340,17 @@ def err_flexible_array_init_nonempty : Error< def err_flexible_array_init_needs_braces : Error< "flexible array requires brace-enclosed initializer">; def err_illegal_decl_array_of_functions : Error< - "'%0' declared as array of functions">; + "'%0' declared as array of functions of type %1">; def err_illegal_decl_array_incomplete_type : Error< "array has incomplete element type %0">; def err_illegal_decl_array_of_references : Error< - "'%0' declared as array of references">; + "'%0' declared as array of references of type %1">; def err_array_star_outside_prototype : Error< "star modifier used outside of function prototype">; def err_illegal_decl_pointer_to_reference : Error< - "'%0' declared as a pointer to a reference">; + "'%0' declared as a pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_reference : Error< - "'%0' declared as a member pointer to a reference">; + "'%0' declared as a member pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_void : Error< "'%0' declared as a member pointer to void">; def err_illegal_decl_mempointer_in_nonclass : Error< @@ -1368,6 +1382,8 @@ def err_alignof_incomplete_type : Error< "invalid application of '__alignof' to an incomplete type %0">; def err_sizeof_alignof_bitfield : Error< "invalid application of '%select{sizeof|__alignof}0' to bit-field">; +def err_offsetof_incomplete_type : Error< + "offsetof of incomplete type %0">; def err_offsetof_record_type : Error< "offsetof requires struct, union, or class type, %0 invalid">; def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; @@ -1385,6 +1401,10 @@ def warn_shift_negative : Warning< def warn_shift_gt_typewidth : Warning< "shift count >= width of type">; +def warn_precedence_bitwise_rel : Warning< + "%0 has lower precedence than %1; %1 will be evaluated first">, + InGroup<Parentheses>; + def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " "non-fragile ABI">; @@ -1661,7 +1681,9 @@ def err_bad_new_type : Error< def err_new_incomplete_type : Error< "allocation of incomplete type %0">; def err_new_array_nonconst : Error< - "only the first dimension of an allocated array may be non-const">; + "only the first dimension of an allocated array may have dynamic size">; +def err_new_paren_array_nonconst : Error< + "when type is in parentheses, array cannot have dynamic size">; def err_array_size_not_integral : Error< "array size expression must have integral or enumerated type, not %0">; def err_new_uninitialized_const : Error< @@ -1709,8 +1731,6 @@ def err_throw_incomplete_ptr : Error< def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; -def err_ident_in_pseudo_dtor_not_a_type : Error< - "identifier %0 in pseudo-destructor expression does not name a type">; def err_operator_arrow_circular : Error< "circular pointer delegation detected">; def err_pseudo_dtor_base_not_scalar : Error< @@ -2130,6 +2150,10 @@ def warn_ret_stack_addr : Warning< "address of stack memory associated with local variable %0 returned">; def warn_ret_stack_ref : Warning< "reference to stack memory associated with local variable %0 returned">; +def warn_ret_addr_label : Warning< + "returning address of label, which is local">; +def err_ret_local_block : Error< + "returning block that lives on the local stack">; // For non-floating point, expressions of the form x == x or x != x @@ -2153,8 +2177,6 @@ def err_return_in_block_expression : Error< def err_block_returns_array : Error< "block declared as returning an array">; -def err_ret_local_block : Error< - "returning block that lives on the local stack">; // CFString checking def err_cfstring_literal_not_string_constant : Error< diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 2184bf3c457c..6b60f2eec097 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -16,7 +16,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h index 790b75ba3af3..c0a95051a72d 100644 --- a/include/clang/Basic/OperatorKinds.h +++ b/include/clang/Basic/OperatorKinds.h @@ -26,7 +26,10 @@ enum OverloadedOperatorKind { NUM_OVERLOADED_OPERATORS }; - +/// \brief Retrieve the spelling of the given overloaded operator, without +/// the preceding "operator" keyword. +const char *getOperatorSpelling(OverloadedOperatorKind Operator); + } // end namespace clang #endif diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index e8cc564c8a20..9960d5beb5c1 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -109,7 +109,7 @@ public: // Add all arguments. for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], - (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); + (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); } // Add all ranges. @@ -129,13 +129,25 @@ public: PD.AddTaggedVal(I, Diagnostic::ak_uint); return PD; } - + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + int I) { + PD.AddTaggedVal(I, Diagnostic::ak_sint); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const char *S) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), Diagnostic::ak_c_string); + return PD; + } + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, const SourceRange &R) { PD.AddSourceRange(R); return PD; } - + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, DeclarationName N); }; diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 8a69cba066b3..7e9ac531017e 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -16,7 +16,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include <vector> #include <cassert> diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index b88e2aaba383..e61ef9265cfb 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -17,7 +17,7 @@ // FIXME: Daniel isn't smart enough to use a prototype for this. #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Triple.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <cassert> #include <vector> #include <string> @@ -103,9 +103,9 @@ public: /// enum. For example, SignedInt -> getIntWidth(). unsigned getTypeWidth(IntType T) const; - /// getTypeSigned - Return whether an integer types is signed. Returns true if + /// isTypeSigned - Return whether an integer types is signed. Returns true if /// the type is signed; false otherwise. - bool getTypeSigned(IntType T) const; + bool isTypeSigned(IntType T) const; /// getPointerWidth - Return the width of pointers on this target, for the /// specified address space. diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index 4084be6c0b42..5370114ee824 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -404,6 +404,7 @@ OPTION("-flax-vector-conversions", flax_vector_conversions, Flag, f_Group, INVAL OPTION("-flimited-precision=", flimited_precision_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-flto", flto, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fmath-errno", fmath_errno, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fmerge-all-constants", fmerge_all_constants, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fmessage-length=", fmessage_length_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fms-extensions", fms_extensions, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fmudflapth", fmudflapth, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -428,6 +429,7 @@ OPTION("-fno-inline-functions", fno_inline_functions, Flag, clang_ignored_f_Grou OPTION("-fno-inline", fno_inline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-keep-inline-functions", fno_keep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-math-errno", fno_math_errno, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-merge-all-constants", fno_merge_all_constants, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-omit-frame-pointer", fno_omit_frame_pointer, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-pascal-strings", fno_pascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-rtti", fno_rtti, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -559,6 +561,7 @@ OPTION("-m", m_Joined, Joined, m_Group, INVALID, "", 0, 0, 0) OPTION("-no-cpp-precomp", no_cpp_precomp, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-no-integrated-cpp", no_integrated_cpp, Flag, INVALID, INVALID, "d", 0, 0, 0) OPTION("-no_dead_strip_inits_and_terms", no__dead__strip__inits__and__terms, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-nobuiltininc", nobuiltininc, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nodefaultlibs", nodefaultlibs, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nofixprebinding", nofixprebinding, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nolibc", nolibc, Flag, INVALID, INVALID, "", 0, 0, 0) @@ -566,7 +569,6 @@ OPTION("-nomultidefs", nomultidefs, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-noprebind", noprebind, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-noseglinkedit", noseglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostartfiles", nostartfiles, Flag, INVALID, INVALID, "", 0, 0, 0) -OPTION("-nostdclanginc", nostdclanginc, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostdinc", nostdinc, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-nostdlib", nostdlib, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-object", object, Flag, INVALID, INVALID, "", 0, 0, 0) diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 9573777b5f6f..7dfabbadd8fd 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -18,6 +18,7 @@ #include "llvm/ADT/OwningPtr.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Basic/FileManager.h" +#include "clang/Index/ASTLocation.h" #include <string> namespace clang { @@ -32,6 +33,8 @@ namespace clang { class ASTContext; class Decl; +using namespace idx; + /// \brief Utility class for loading a ASTContext from a PCH file. /// class ASTUnit { @@ -50,9 +53,11 @@ class ASTUnit { // FIXME: This is temporary; eventually, CIndex will always do this. bool OnlyLocalDecls; + // Critical optimization when using clang_getCursor(). + ASTLocation LastLoc; + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT - ASTUnit(); public: ASTUnit(DiagnosticClient *diagClient = NULL); @@ -80,6 +85,9 @@ public: bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } + ASTLocation getLastASTLocation() const { return LastLoc; } + /// \brief Create a ASTUnit from a PCH file. /// /// \param Filename - The PCH file to load. diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h index 508af537b1fa..ad53a8d592ba 100644 --- a/include/clang/Frontend/CompileOptions.h +++ b/include/clang/Frontend/CompileOptions.h @@ -43,7 +43,8 @@ public: unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. - + unsigned MergeAllConstants : 1; // Merge identical constants. + /// Inlining - The kind of inlining to perform. InliningMethod Inlining; @@ -67,6 +68,7 @@ public: Inlining = NoInlining; DisableRedZone = 0; NoImplicitFloat = 0; + MergeAllConstants = 1; } }; diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index 36323c260c9a..8b80d1dc11d8 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -99,7 +99,7 @@ NODE_XML(FunctionDecl, "Function") ENUM_XML(FunctionDecl::Static, "static") ENUM_XML(FunctionDecl::PrivateExtern, "__private_extern__") END_ENUM_XML - ATTRIBUTE_OPT_XML(isInline(), "inline") + ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") //ATTRIBUTE_OPT_XML(isVariadic(), "variadic") // in the type reference ATTRIBUTE_XML(getNumParams(), "num_args") SUB_NODE_SEQUENCE_XML(ParmVarDecl) @@ -113,7 +113,7 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl") ATTRIBUTE_XML(getNameAsString(), "name") TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType()) ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type") - ATTRIBUTE_OPT_XML(isInline(), "inline") + ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") ATTRIBUTE_OPT_XML(isStatic(), "static") ATTRIBUTE_OPT_XML(isVirtual(), "virtual") ATTRIBUTE_XML(getNumParams(), "num_args") diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h new file mode 100644 index 000000000000..58673e4dad6b --- /dev/null +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -0,0 +1,49 @@ +//===--- DiagnosticOptions.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_DIAGNOSTICOPTIONS_H +#define LLVM_CLANG_FRONTEND_DIAGNOSTICOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// DiagnosticOptions - Options for controlling the compiler diagnostics +/// engine. +class DiagnosticOptions { +public: + unsigned ShowColumn : 1; /// Show column number on diagnostics. + unsigned ShowLocation : 1; /// Show source location information. + unsigned ShowCarets : 1; /// Show carets in diagnostics. + unsigned ShowFixits : 1; /// Show fixit information. + unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form. + unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable + /// diagnostics. + unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences. + + /// Column limit for formatting message diagnostics, or 0 if unused. + unsigned MessageLength; + +public: + DiagnosticOptions() { + ShowColumn = 1; + ShowLocation = 1; + ShowCarets = 1; + ShowFixits = 1; + ShowSourceRanges = 0; + ShowOptionNames = 0; + ShowColors = 0; + MessageLength = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/InitHeaderSearch.h b/include/clang/Frontend/InitHeaderSearch.h index a90b4eaf9e2b..48c426825262 100644 --- a/include/clang/Frontend/InitHeaderSearch.h +++ b/include/clang/Frontend/InitHeaderSearch.h @@ -73,6 +73,16 @@ public: /// variables such as CPATH. void AddDefaultEnvVarPaths(const LangOptions &Lang); + // AddDefaultCIncludePaths - Add paths that should always be searched. + void AddDefaultCIncludePaths(const llvm::Triple &triple); + + // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when + // compiling c++. + void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple); + + // AddDefaultFrameworkIncludePaths - Add the framework paths. Used on darwin. + void AddDefaultFrameworkIncludePaths(const llvm::Triple &triple); + /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. void AddDefaultSystemIncludePaths(const LangOptions &Lang, diff --git a/include/clang/Frontend/InitPreprocessor.h b/include/clang/Frontend/InitPreprocessor.h index eb03602dc57b..b29ee2728a86 100644 --- a/include/clang/Frontend/InitPreprocessor.h +++ b/include/clang/Frontend/InitPreprocessor.h @@ -63,7 +63,8 @@ public: /// environment ready to process a single file. This returns true on error. /// bool InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions& InitOptions); + const PreprocessorInitOptions& InitOptions, + bool undef_macros); } // end namespace clang diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 1e953d671226..b2bb9a13771d 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -18,7 +18,7 @@ #define LLVM_CLANG_FRONTEND_PCHBITCODES_H #include "llvm/Bitcode/BitCodes.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" namespace clang { namespace pch { @@ -496,8 +496,6 @@ namespace clang { DECL_IMPLICIT_PARAM, /// \brief A ParmVarDecl record. DECL_PARM_VAR, - /// \brief An OriginalParmVarDecl record. - DECL_ORIGINAL_PARM_VAR, /// \brief A FileScopeAsmDecl record. DECL_FILE_SCOPE_ASM, /// \brief A BlockDecl record. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index cc16970b0040..cc8b3a03e3e8 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -19,6 +19,7 @@ #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Type.h" +#include "clang/AST/TemplateBase.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" @@ -29,7 +30,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <deque> #include <map> #include <string> @@ -542,6 +543,12 @@ public: /// comments in the source code. virtual void ReadComments(std::vector<SourceRange> &Comments); + /// \brief Reads a TemplateArgumentLocInfo appropriate for the + /// given TemplateArgument kind. + TemplateArgumentLocInfo + GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const RecordData &Record, unsigned &Idx); + /// \brief Reads a declarator info from the given record. virtual DeclaratorInfo *GetDeclaratorInfo(const RecordData &Record, unsigned &Idx); diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 728e138d9e7c..22427eb67103 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -275,6 +275,10 @@ public: /// \brief Emits a reference to a declarator info. void AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record); + /// \brief Emits a template argument location. + void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordData &Record); + /// \brief Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordData &Record); diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index 0fd8d44f72bc..98e5a75c65b9 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -23,42 +23,21 @@ namespace llvm { } namespace clang { -class SourceManager; +class DiagnosticOptions; class LangOptions; +class SourceManager; class TextDiagnosticPrinter : public DiagnosticClient { llvm::raw_ostream &OS; const LangOptions *LangOpts; + const DiagnosticOptions *DiagOpts; + SourceLocation LastWarningLoc; FullSourceLoc LastLoc; bool LastCaretDiagnosticWasNote; - bool ShowColumn; - bool CaretDiagnostics; - bool ShowLocation; - bool PrintRangeInfo; - bool PrintDiagnosticOption; - bool PrintFixItInfo; - unsigned MessageLength; - bool UseColors; - public: - TextDiagnosticPrinter(llvm::raw_ostream &os, - bool showColumn = true, - bool caretDiagnistics = true, bool showLocation = true, - bool printRangeInfo = true, - bool printDiagnosticOption = true, - bool printFixItInfo = true, - unsigned messageLength = 0, - bool useColors = false) - : OS(os), LangOpts(0), - LastCaretDiagnosticWasNote(false), ShowColumn(showColumn), - CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation), - PrintRangeInfo(printRangeInfo), - PrintDiagnosticOption(printDiagnosticOption), - PrintFixItInfo(printFixItInfo), - MessageLength(messageLength), - UseColors(useColors) {} + TextDiagnosticPrinter(llvm::raw_ostream &os, const DiagnosticOptions &diags); void setLangOptions(const LangOptions *LO) { LangOpts = LO; diff --git a/include/clang/Index/Utils.h b/include/clang/Index/Utils.h index 36cf56dea203..f8e01f728648 100644 --- a/include/clang/Index/Utils.h +++ b/include/clang/Index/Utils.h @@ -18,7 +18,6 @@ namespace clang { class ASTContext; class SourceLocation; - class Decl; namespace idx { class ASTLocation; @@ -28,7 +27,7 @@ namespace idx { /// \returns the resolved ASTLocation or an invalid ASTLocation if the source /// location could not be resolved. ASTLocation ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, - Decl *RelativeToDecl = 0); + ASTLocation *LastLoc = 0); } // end namespace idx diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index 97656f7d39d6..c4ab5aebf721 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -17,7 +17,7 @@ #include <string> #include "llvm/ADT/SmallString.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" namespace llvm { class APInt; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 0765ac391be3..35960ff328a6 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -75,6 +75,8 @@ class Preprocessor { IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_include; // __has_include + IdentifierInfo *Ident__has_include_next; // __has_include_next SourceLocation DATELoc, TIMELoc; unsigned CounterValue; // Next __COUNTER__ value. @@ -244,7 +246,12 @@ public: return CurPPLexer == L; } - /// getCurrentLexer - Return the current file lexer being lexed from. Note + /// getCurrentLexer - Return the current lexer being lexed from. Note + /// that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; } + + /// getCurrentFileLexer - Return the current file lexer being lexed from. Note /// that this ignores any potentially active macro expansions and _Pragma /// expansions going on at the time. PreprocessorLexer *getCurrentFileLexer() const; @@ -622,6 +629,43 @@ public: /// SourceLocation. MacroInfo* AllocateMacroInfo(SourceLocation L); + /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully + /// checked and spelled filename, e.g. as an operand of #include. This returns + /// true if the input filename was in <>'s or false if it were in ""'s. The + /// caller is expected to provide a buffer that is large enough to hold the + /// spelling of the filename, but is also expected to handle the case when + /// this method decides to use a different buffer. + bool GetIncludeFilenameSpelling(SourceLocation Loc, + const char *&BufStart, const char *&BufEnd); + + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, + /// return null on failure. isAngled indicates whether the file reference is + /// for system #include's or not (i.e. using <> instead of ""). + const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd, + bool isAngled, const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir); + + /// GetCurLookup - The DirectoryLookup structure used to find the current + /// FileEntry, if CurLexer is non-null and if applicable. This allows us to + /// implement #include_next and find directory-specific properties. + const DirectoryLookup *GetCurDirLookup() { return CurDirLookup; } + + /// isInPrimaryFile - Return true if we're in the top-level file, not in a + /// #include. + bool isInPrimaryFile() const; + + /// ConcatenateIncludeName - Handle cases where the #include name is expanded + /// from a macro as multiple tokens, which need to be glued together. This + /// occurs for code like: + /// #define FOO <a/b.h> + /// #include FOO + /// because in this case, "<a/b.h>" is returned as 7 tokens, not one. + /// + /// This code concatenates and consumes tokens up to the '>' token. It returns + /// false if the > was found, otherwise it returns true if it finds and consumes + /// the EOM marker. + bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer); + private: void PushIncludeMacroStack() { @@ -646,10 +690,6 @@ private: /// be reused for allocating new MacroInfo objects. void ReleaseMacroInfo(MacroInfo* MI); - /// isInPrimaryFile - Return true if we're in the top-level file, not in a - /// #include. - bool isInPrimaryFile() const; - /// ReadMacroName - Lex and validate a macro name, which occurs after a /// #define or #undef. This emits a diagnostic, sets the token kind to eom, /// and discards the rest of the macro line if the macro name is invalid. @@ -722,24 +762,6 @@ private: /// start getting tokens from it using the PTH cache. void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); - /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully - /// checked and spelled filename, e.g. as an operand of #include. This returns - /// true if the input filename was in <>'s or false if it were in ""'s. The - /// caller is expected to provide a buffer that is large enough to hold the - /// spelling of the filename, but is also expected to handle the case when - /// this method decides to use a different buffer. - bool GetIncludeFilenameSpelling(SourceLocation Loc, - const char *&BufStart, const char *&BufEnd); - - /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, - /// return null on failure. isAngled indicates whether the file reference is - /// for system #include's or not (i.e. using <> instead of ""). - const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd, - bool isAngled, const DirectoryLookup *FromDir, - const DirectoryLookup *&CurDir); - - - /// IsFileLexer - Returns true if we are lexing from a file and not a /// pragma or a macro. static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) { diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 8acdb30cc705..8d910959b9fa 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -17,6 +17,7 @@ #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/OperatorKinds.h" #include <cstdlib> namespace clang { @@ -62,12 +63,12 @@ class Token { /// Kind - The actual flavor of token this is. /// - unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind'; + unsigned char Kind; // DON'T make Kind a 'tok::TokenKind'; // MSVC will treat it as a signed char and // TokenKinds > 127 won't be handled correctly. /// Flags - Bits we track about this token, members of the TokenFlags enum. - unsigned Flags : 8; + unsigned char Flags; public: // Various flags set per token: @@ -261,6 +262,9 @@ struct TemplateIdAnnotation { /// FIXME: Temporarily stores the name of a specialization IdentifierInfo *Name; + /// FIXME: Temporarily stores the overloaded operator kind. + OverloadedOperatorKind Operator; + /// The declaration of the template corresponding to the /// template-name. This is an Action::DeclTy*. void *Template; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 050b3f42e4cd..073365dcede3 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -161,6 +161,23 @@ public: // Declaration Tracking Callbacks. //===--------------------------------------------------------------------===// + typedef uintptr_t ParsingDeclStackState; + + /// PushParsingDeclaration - Notes that the parser has begun + /// processing a declaration of some sort. Guaranteed to be matched + /// by a call to PopParsingDeclaration with the value returned by + /// this method. + virtual ParsingDeclStackState PushParsingDeclaration() { + return ParsingDeclStackState(); + } + + /// PopParsingDeclaration - Notes that the parser has completed + /// processing a declaration of some sort. The decl will be empty + /// if the declaration didn't correspond to a full declaration (or + /// if the actions module returned an empty decl for it). + virtual void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D) { + } + /// ConvertDeclToDeclGroup - If the parser has one decl in a context where it /// needs a decl group, it calls this to convert between the two /// representations. @@ -236,30 +253,36 @@ public: virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = 0) = 0; - /// \brief Determine whether the given identifier refers to the name of a + /// \brief Determine whether the given name refers to a template. + /// + /// This callback is used by the parser after it has seen a '<' to determine + /// whether the given name refers to a template and, if so, what kind of /// template. /// - /// \param S the scope in which name lookup occurs + /// \param S the scope in which the name occurs. /// - /// \param II the identifier that we are querying to determine whether it - /// is a template. + /// \param SS the C++ nested-name-specifier that precedes the template name, + /// if any. /// - /// \param IdLoc the source location of the identifier + /// \param Name the name that we are querying to determine whether it is + /// a template. /// - /// \param SS the C++ scope specifier that precedes the template name, if - /// any. + /// \param ObjectType if we are determining whether the given name is a + /// template name in the context of a member access expression (e.g., + /// \c p->X<int>), this is the type of the object referred to by the + /// member access (e.g., \c p). /// /// \param EnteringContext whether we are potentially entering the context - /// referred to by the scope specifier \p SS + /// referred to by the nested-name-specifier \p SS, which allows semantic + /// analysis to look into uninstantiated templates. /// /// \param Template if the name does refer to a template, the declaration /// of the template that the name refers to. /// /// \returns the kind of template that this name refers to. virtual TemplateNameKind isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template) = 0; @@ -854,47 +877,33 @@ public: virtual SourceRange getExprRange(ExprTy *E) const { return SourceRange(); } - - /// ActOnIdentifierExpr - Parse an identifier in expression context. - /// 'HasTrailingLParen' indicates whether or not the identifier has a '(' - /// token immediately after it. - /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or - /// namespace) that the identifier must be a member of. - /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". - virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS = 0, - bool isAddressOfOperand = false){ - return ExprEmpty(); - } - - /// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator - /// name (e.g., @c operator+ ) as an expression. This is very - /// similar to ActOnIdentifierExpr, except that instead of providing - /// an identifier the parser provides the kind of overloaded - /// operator that was parsed. - virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( - Scope *S, SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, const CXXScopeSpec &SS, - bool isAddressOfOperand = false) { - return ExprEmpty(); - } - - /// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function - /// name (e.g., @c operator void const *) as an expression. This is - /// very similar to ActOnIdentifierExpr, except that instead of - /// providing an identifier the parser provides the type of the - /// conversion function. - virtual OwningExprResult ActOnCXXConversionFunctionExpr( - Scope *S, SourceLocation OperatorLoc, - TypeTy *Type, bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand = false) { + + /// \brief Parsed an id-expression (C++) or identifier (C) in expression + /// context, e.g., the expression "x" that refers to a variable named "x". + /// + /// \param S the scope in which this id-expression or identifier occurs. + /// + /// \param SS the C++ nested-name-specifier that qualifies the name of the + /// value, e.g., "std::" in "std::sort". + /// + /// \param Name the name to which the id-expression refers. In C, this will + /// always be an identifier. In C++, it may also be an overloaded operator, + /// destructor name (if there is a nested-name-specifier), or template-id. + /// + /// \param HasTrailingLParen whether the next token following the + /// id-expression or identifier is a left parentheses ('('). + /// + /// \param IsAddressOfOperand whether the token that precedes this + /// id-expression or identifier was an ampersand ('&'), indicating that + /// we will be taking the address of this expression. + virtual OwningExprResult ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Name, + bool HasTrailingLParen, + bool IsAddressOfOperand) { return ExprEmpty(); } - + virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { return ExprEmpty(); @@ -936,16 +945,42 @@ public: SourceLocation RLoc) { return ExprEmpty(); } - virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl, - const CXXScopeSpec *SS = 0) { + + /// \brief Parsed a member access expresion (C99 6.5.2.3, C++ [expr.ref]) + /// of the form \c x.m or \c p->m. + /// + /// \param S the scope in which the member access expression occurs. + /// + /// \param Base the class or pointer to class into which this member + /// access expression refers, e.g., \c x in \c x.m. + /// + /// \param OpLoc the location of the "." or "->" operator. + /// + /// \param OpKind the kind of member access operator, which will be either + /// tok::arrow ("->") or tok::period ("."). + /// + /// \param SS in C++, the nested-name-specifier that precedes the member + /// name, if any. + /// + /// \param Member the name of the member that we are referring to. In C, + /// this will always store an identifier; in C++, we may also have operator + /// names, conversion function names, destructors, and template names. + /// + /// \param ObjCImpDecl the Objective-C implementation declaration. + /// FIXME: Do we really need this? + /// + /// \param HasTrailingLParen whether this member name is immediately followed + /// by a left parentheses ('('). + virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &Member, + DeclPtrTy ObjCImpDecl, + bool HasTrailingLParen) { return ExprEmpty(); } - + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. There are guaranteed to be one fewer commas than arguments, @@ -1245,8 +1280,7 @@ public: } /// ActOnFriendTypeDecl - Parsed a friend type declaration. - virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S, - const DeclSpec &DS, + virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TParams) { return DeclPtrTy(); } @@ -1376,123 +1410,6 @@ public: return ExprEmpty(); } - /// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example: - /// - /// t->~T(); - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - IdentifierInfo *ClassName, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - return ExprEmpty(); - } - - /// \brief Parsed a C++ destructor reference that refers to a type. - /// - /// This action is used when parsing a destructor reference that uses a - /// template-id, e.g., - /// - /// \code - /// t->~Tmpl<T1, T2> - /// \endcode - /// - /// \param S the scope in which the destructor reference occurs. - /// \param Base the base object of the destructor reference expression. - /// \param OpLoc the location of the operator ('.' or '->'). - /// \param OpKind the kind of the destructor reference operator ('.' or '->'). - /// \param TypeRange the source range that covers the destructor type. - /// \param Type the type that is being destroyed. - /// \param SS the scope specifier that precedes the destructor name. - /// \param HasTrailingLParen whether the destructor name is followed by a '('. - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceRange TypeRange, - TypeTy *Type, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - return ExprEmpty(); - } - - /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator - /// reference, for example: - /// - /// t.operator++(); - virtual OwningExprResult - ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - OverloadedOperatorKind OverOpKind, - const CXXScopeSpec *SS = 0) { - return ExprEmpty(); - } - - /// ActOnConversionOperatorReferenceExpr - Parsed an overloaded conversion - /// function reference, for example: - /// - /// t.operator int(); - virtual OwningExprResult - ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - TypeTy *Ty, - const CXXScopeSpec *SS = 0) { - return ExprEmpty(); - } - - /// \brief Parsed a reference to a member template-id. - /// - /// This callback will occur instead of ActOnMemberReferenceExpr() when the - /// member in question is a template for which the code provides an - /// explicitly-specified template argument list, e.g., - /// - /// \code - /// x.f<int>() - /// \endcode - /// - /// \param S the scope in which the member reference expression occurs - /// - /// \param Base the expression to the left of the "." or "->". - /// - /// \param OpLoc the location of the "." or "->". - /// - /// \param OpKind the kind of operator, which will be "." or "->". - /// - /// \param SS the scope specifier that precedes the template-id in, e.g., - /// \c x.Base::f<int>(). - /// - /// \param Template the declaration of the template that is being referenced. - /// - /// \param TemplateNameLoc the location of the template name referred to by - /// \p Template. - /// - /// \param LAngleLoc the location of the left angle bracket ('<') - /// - /// \param TemplateArgs the (possibly-empty) template argument list provided - /// as part of the member reference. - /// - /// \param RAngleLoc the location of the right angle bracket ('>') - virtual OwningExprResult - ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - // FIXME: "template" keyword? - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { - return ExprEmpty(); - } - /// ActOnFinishFullExpr - Called whenever a full expression has been parsed. /// (C++ [intro.execution]p12). virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr) { @@ -1712,40 +1629,6 @@ public: return TypeResult(); } - /// \brief Form a reference to a template-id (that will refer to a function) - /// from a template and a list of template arguments. - /// - /// This action forms an expression that references the given template-id, - /// possibly checking well-formedness of the template arguments. It does not - /// imply the declaration of any entity. - /// - /// \param SS The scope specifier that may precede the template name. - /// - /// \param Template A template whose specialization results in a - /// function or a dependent template. - /// - /// \param TemplateNameLoc The location of the template name. - /// - /// \param LAngleLoc The location of the left angle bracket ('<') that starts - /// the template argument list. - /// - /// \param TemplateArgs The template arguments in the template argument list, - /// which may be empty. - /// - /// \param TemplateArgLocs The locations of the template arguments. - /// - /// \param RAngleLoc The location of the right angle bracket ('>') that - /// closes the template argument list. - virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { - return ExprError(); - } - /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template @@ -1756,22 +1639,19 @@ public: /// /// \param TemplateKWLoc the location of the "template" keyword (if any). /// - /// \param Name the name of the template (an identifier) - /// - /// \param NameLoc the location of the identifier - /// /// \param SS the nested-name-specifier that precedes the "template" keyword - /// or the template name. FIXME: If the dependent template name occurs in + /// or the template name. If the dependent template name occurs in /// a member access expression, e.g., "x.template f<T>", this /// nested-name-specifier will be empty. /// + /// \param Name the name of the template. + /// /// \param ObjectType if this dependent template name occurs in the /// context of a member access expression, the type of the object being /// accessed. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType) { return TemplateTy(); } @@ -2473,13 +2353,12 @@ public: const CXXScopeSpec *SS); virtual TemplateNameKind isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); - + /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is /// popped. diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 51970f1867d9..dccb8bcfeb9a 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -390,17 +390,20 @@ public: }; - ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), - GetterName(0), SetterName(0) { } + ObjCDeclSpec() + : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), + GetterName(0), SetterName(0) { } ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } - void setObjCDeclQualifier(ObjCDeclQualifier DQVal) - { objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); } + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); + } - ObjCPropertyAttributeKind getPropertyAttributes() const - { return ObjCPropertyAttributeKind(PropertyAttributes); } + ObjCPropertyAttributeKind getPropertyAttributes() const { + return ObjCPropertyAttributeKind(PropertyAttributes); + } void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { PropertyAttributes = - (ObjCPropertyAttributeKind) (PropertyAttributes | PRVal); + (ObjCPropertyAttributeKind)(PropertyAttributes | PRVal); } const IdentifierInfo *getGetterName() const { return GetterName; } @@ -456,6 +459,193 @@ public: } }; +/// \brief Represents a C++ unqualified-id that has been parsed. +class UnqualifiedId { +private: + const UnqualifiedId &operator=(const UnqualifiedId &); // DO NOT IMPLEMENT + +public: + /// \brief Describes the kind of unqualified-id parsed. + enum IdKind { + /// \brief An identifier. + IK_Identifier, + /// \brief An overloaded operator name, e.g., operator+. + IK_OperatorFunctionId, + /// \brief A conversion function name, e.g., operator int. + IK_ConversionFunctionId, + /// \brief A constructor name. + IK_ConstructorName, + /// \brief A destructor name. + IK_DestructorName, + /// \brief A template-id, e.g., f<int>. + IK_TemplateId + } Kind; + + /// \brief Anonymous union that holds extra data associated with the + /// parsed unqualified-id. + union { + /// \brief When Kind == IK_Identifier, the parsed identifier. + IdentifierInfo *Identifier; + + /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator + /// that we parsed. + struct { + /// \brief The kind of overloaded operator. + OverloadedOperatorKind Operator; + + /// \brief The source locations of the individual tokens that name + /// the operator, e.g., the "new", "[", and "]" tokens in + /// operator new []. + /// + /// Different operators have different numbers of tokens in their name, + /// up to three. Any remaining source locations in this array will be + /// set to an invalid value for operators with fewer than three tokens. + unsigned SymbolLocations[3]; + } OperatorFunctionId; + + /// \brief When Kind == IK_ConversionFunctionId, the type that the + /// conversion function names. + ActionBase::TypeTy *ConversionFunctionId; + + /// \brief When Kind == IK_ConstructorName, the class-name of the type + /// whose constructor is being referenced. + ActionBase::TypeTy *ConstructorName; + + /// \brief When Kind == IK_DestructorName, the type referred to by the + /// class-name. + ActionBase::TypeTy *DestructorName; + + /// \brief When Kind == IK_TemplateId, the template-id annotation that + /// contains the template name and template arguments. + TemplateIdAnnotation *TemplateId; + }; + + /// \brief The location of the first token that describes this unqualified-id, + /// which will be the location of the identifier, "operator" keyword, + /// tilde (for a destructor), or the template name of a template-id. + SourceLocation StartLocation; + + /// \brief The location of the last token that describes this unqualified-id. + SourceLocation EndLocation; + + UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { } + + /// \brief Do not use this copy constructor. It is temporary, and only + /// exists because we are holding FieldDeclarators in a SmallVector when we + /// don't actually need them. + /// + /// FIXME: Kill this copy constructor. + UnqualifiedId(const UnqualifiedId &Other) + : Kind(IK_Identifier), Identifier(Other.Identifier), + StartLocation(Other.StartLocation), EndLocation(Other.EndLocation) { + assert(Other.Kind == IK_Identifier && "Cannot copy non-identifiers"); + } + + /// \brief Destroy this unqualified-id. + ~UnqualifiedId() { clear(); } + + /// \brief Clear out this unqualified-id, setting it to default (invalid) + /// state. + void clear(); + + /// \brief Determine whether this unqualified-id refers to a valid name. + bool isValid() const { return StartLocation.isValid(); } + + /// \brief Determine whether this unqualified-id refers to an invalid name. + bool isInvalid() const { return !isValid(); } + + /// \brief Determine what kind of name we have. + IdKind getKind() const { return Kind; } + + /// \brief Specify that this unqualified-id was parsed as an identifier. + /// + /// \param Id the parsed identifier. + /// \param IdLoc the location of the parsed identifier. + void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { + Kind = IK_Identifier; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = EndLocation = IdLoc; + } + + /// \brief Specify that this unqualified-id was parsed as an + /// operator-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Op the overloaded operator. + /// + /// \param SymbolLocations the locations of the individual operator symbols + /// in the operator. + void setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]); + + /// \brief Specify that this unqualified-id was parsed as a + /// conversion-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Ty the type to which this conversion function is converting. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConversionFunctionId(SourceLocation OperatorLoc, + ActionBase::TypeTy *Ty, + SourceLocation EndLoc) { + Kind = IK_ConversionFunctionId; + StartLocation = OperatorLoc; + EndLocation = EndLoc; + ConversionFunctionId = Ty; + } + + /// \brief Specify that this unqualified-id was parsed as a constructor name. + /// + /// \param ClassType the class type referred to by the constructor name. + /// + /// \param ClassNameLoc the location of the class name. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConstructorName(ActionBase::TypeTy *ClassType, + SourceLocation ClassNameLoc, + SourceLocation EndLoc) { + Kind = IK_ConstructorName; + StartLocation = ClassNameLoc; + EndLocation = EndLoc; + ConstructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a destructor name. + /// + /// \param TildeLoc the location of the '~' that introduces the destructor + /// name. + /// + /// \param ClassType the name of the class referred to by the destructor name. + void setDestructorName(SourceLocation TildeLoc, ActionBase::TypeTy *ClassType, + SourceLocation EndLoc) { + Kind = IK_DestructorName; + StartLocation = TildeLoc; + EndLocation = EndLoc; + DestructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a template-id. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; + } + + /// \brief Return the source range that covers this unqualified-id. + SourceRange getSourceRange() const { + return SourceRange(StartLocation, EndLocation); + } +}; + /// CachedTokens - A set of tokens that has been cached for later /// parsing. typedef llvm::SmallVector<Token, 4> CachedTokens; @@ -790,33 +980,16 @@ public: BlockLiteralContext // Block literal declarator. }; - /// DeclaratorKind - The kind of declarator this represents. - enum DeclaratorKind { - DK_Abstract, // An abstract declarator (has no identifier) - DK_Normal, // A normal declarator (has an identifier). - DK_Constructor, // A C++ constructor (identifier is the class name) - DK_Destructor, // A C++ destructor (identifier is ~class name) - DK_Operator, // A C++ overloaded operator name - DK_Conversion, // A C++ conversion function (identifier is - // "operator " then the type name) - DK_TemplateId // A C++ template-id naming a function template - // specialization. - }; - private: const DeclSpec &DS; CXXScopeSpec SS; - IdentifierInfo *Identifier; - SourceLocation IdentifierLoc; + UnqualifiedId Name; SourceRange Range; /// Context - Where we are parsing this declarator. /// TheContext Context; - /// Kind - What kind of declarator this is. - DeclaratorKind Kind; - /// DeclTypeInfo - This holds each type that the declarator includes as it is /// parsed. This is pushed from the identifier out, which means that element /// #0 will be the most closely bound to the identifier, and @@ -835,21 +1008,6 @@ private: /// AsmLabel - The asm label, if specified. ActionBase::ExprTy *AsmLabel; - union { - // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the - // type associated with the constructor, destructor, or conversion - // operator. - ActionBase::TypeTy *Type; - - /// When Kind is DK_Operator, this is the actual overloaded - /// operator that this declarator names. - OverloadedOperatorKind OperatorKind; - - /// When Kind is DK_TemplateId, this is the template-id annotation that - /// contains the template and its template arguments. - TemplateIdAnnotation *TemplateId; - }; - /// InlineParams - This is a local array used for the first function decl /// chunk to avoid going to the heap for the common case when we have one /// function chunk in the declarator. @@ -863,10 +1021,9 @@ private: public: Declarator(const DeclSpec &ds, TheContext C) - : DS(ds), Identifier(0), Range(ds.getSourceRange()), Context(C), - Kind(DK_Abstract), + : DS(ds), Range(ds.getSourceRange()), Context(C), InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), - GroupingParens(false), AttrList(0), AsmLabel(0), Type(0), + GroupingParens(false), AttrList(0), AsmLabel(0), InlineParamsUsed(false), Extension(false) { } @@ -890,8 +1047,10 @@ public: const CXXScopeSpec &getCXXScopeSpec() const { return SS; } CXXScopeSpec &getCXXScopeSpec() { return SS; } + /// \brief Retrieve the name specified by this declarator. + UnqualifiedId &getName() { return Name; } + TheContext getContext() const { return Context; } - DeclaratorKind getKind() const { return Kind; } /// getSourceRange - Get the source range that spans this declarator. const SourceRange &getSourceRange() const { return Range; } @@ -922,22 +1081,15 @@ public: /// clear - Reset the contents of this Declarator. void clear() { SS.clear(); - Identifier = 0; - IdentifierLoc = SourceLocation(); + Name.clear(); Range = DS.getSourceRange(); - if (Kind == DK_TemplateId) - TemplateId->Destroy(); - - Kind = DK_Abstract; - for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) DeclTypeInfo[i].destroy(); DeclTypeInfo.clear(); delete AttrList; AttrList = 0; AsmLabel = 0; - Type = 0; InlineParamsUsed = false; } @@ -968,84 +1120,28 @@ public: /// isPastIdentifier - Return true if we have parsed beyond the point where /// the - bool isPastIdentifier() const { return IdentifierLoc.isValid(); } + bool isPastIdentifier() const { return Name.isValid(); } /// hasName - Whether this declarator has a name, which might be an /// identifier (accessible via getIdentifier()) or some kind of /// special C++ name (constructor, destructor, etc.). - bool hasName() const { return getKind() != DK_Abstract; } - - IdentifierInfo *getIdentifier() const { return Identifier; } - SourceLocation getIdentifierLoc() const { return IdentifierLoc; } - - void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) { - Identifier = ID; - IdentifierLoc = Loc; - if (ID) - Kind = DK_Normal; - else - Kind = DK_Abstract; - SetRangeEnd(Loc); - } - - /// setConstructor - Set this declarator to be a C++ constructor - /// declarator. Also extends the range. - void setConstructor(ActionBase::TypeTy *Ty, SourceLocation Loc) { - IdentifierLoc = Loc; - Kind = DK_Constructor; - Type = Ty; - SetRangeEnd(Loc); - } - - /// setDestructor - Set this declarator to be a C++ destructor - /// declarator. Also extends the range to End, which should be the identifier - /// token. - void setDestructor(ActionBase::TypeTy *Ty, SourceLocation Loc, - SourceLocation EndLoc) { - IdentifierLoc = Loc; - Kind = DK_Destructor; - Type = Ty; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); - } - - /// setConversionFunction - Set this declarator to be a C++ - /// conversion function declarator (e.g., @c operator int const *). - /// Also extends the range to EndLoc, which should be the last token of the - /// type name. - void setConversionFunction(ActionBase::TypeTy *Ty, SourceLocation Loc, - SourceLocation EndLoc) { - Identifier = 0; - IdentifierLoc = Loc; - Kind = DK_Conversion; - Type = Ty; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); + bool hasName() const { + return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier; } - /// setOverloadedOperator - Set this declaration to be a C++ - /// overloaded operator declarator (e.g., @c operator+). - /// Also extends the range to EndLoc, which should be the last token of the - /// operator. - void setOverloadedOperator(OverloadedOperatorKind Op, SourceLocation Loc, - SourceLocation EndLoc) { - IdentifierLoc = Loc; - Kind = DK_Operator; - OperatorKind = Op; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); + IdentifierInfo *getIdentifier() const { + if (Name.getKind() == UnqualifiedId::IK_Identifier) + return Name.Identifier; + + return 0; } + SourceLocation getIdentifierLoc() const { return Name.StartLocation; } - /// \brief Set this declaration to be a C++ template-id, which includes the - /// template (or set of function templates) along with template arguments. - void setTemplateId(TemplateIdAnnotation *TemplateId) { - assert(TemplateId && "NULL template-id provided to declarator?"); - IdentifierLoc = TemplateId->TemplateNameLoc; - Kind = DK_TemplateId; - SetRangeEnd(TemplateId->RAngleLoc); - this->TemplateId = TemplateId; + /// \brief Set the name of this declarator to be the given identifier. + void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + Name.setIdentifier(Id, IdLoc); } - + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { @@ -1069,6 +1165,13 @@ public: return DeclTypeInfo[i]; } + void DropFirstTypeObject() + { + assert(!DeclTypeInfo.empty() && "No type chunks to drop."); + DeclTypeInfo.front().destroy(); + DeclTypeInfo.erase(DeclTypeInfo.begin()); + } + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, /// this method returns true if the identifier is a function declarator. bool isFunctionDeclarator() const { @@ -1108,22 +1211,6 @@ public: void setExtension(bool Val = true) { Extension = Val; } bool getExtension() const { return Extension; } - ActionBase::TypeTy *getDeclaratorIdType() const { - assert((Kind == DK_Constructor || Kind == DK_Destructor || - Kind == DK_Conversion) && "Declarator kind does not have a type"); - return Type; - } - - OverloadedOperatorKind getOverloadedOperator() const { - assert(Kind == DK_Operator && "Declarator is not an overloaded operator"); - return OperatorKind; - } - - TemplateIdAnnotation *getTemplateId() { - assert(Kind == DK_TemplateId && "Declarator is not a template-id"); - return TemplateId; - } - void setInvalidType(bool Val = true) { InvalidType = Val; } bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; @@ -1142,7 +1229,7 @@ struct FieldDeclarator { BitfieldSize = 0; } }; - + } // end namespace clang #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9cb4677f6637..f34d469d9823 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -571,6 +571,99 @@ private: return *ClassStack.top(); } + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Action &Actions; + Action::ParsingDeclStackState State; + bool Popped; + + public: + ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { + push(); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(DeclPtrTy()); + } + + void complete(DeclPtrTy D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + private: + void push() { + State = Actions.PushParsingDeclaration(); + Popped = false; + } + + void pop(DeclPtrTy D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) : ParsingRAII(P) { + } + + void complete(DeclPtrTy D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(DeclPtrTy D) { + ParsingRAII.complete(D); + } + }; + /// \brief RAII object used to class ParsingClassDefinition { Parser &P; @@ -603,14 +696,17 @@ private: : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } ParsedTemplateInfo(TemplateParameterLists *TemplateParams, - bool isSpecialization) + bool isSpecialization, + bool lastParameterListWasEmpty = false) : Kind(isSpecialization? ExplicitSpecialization : Template), - TemplateParams(TemplateParams) { } + TemplateParams(TemplateParams), + LastParameterListWasEmpty(lastParameterListWasEmpty) { } explicit ParsedTemplateInfo(SourceLocation ExternLoc, SourceLocation TemplateLoc) : Kind(ExplicitInstantiation), TemplateParams(0), - ExternLoc(ExternLoc), TemplateLoc(TemplateLoc) { } + ExternLoc(ExternLoc), TemplateLoc(TemplateLoc), + LastParameterListWasEmpty(false){ } /// \brief The kind of template we are parsing. enum { @@ -635,6 +731,9 @@ private: /// \brief The location of the 'template' keyword, for an explicit /// instantiation. SourceLocation TemplateLoc; + + /// \brief Whether the last template parameter list was empty. + bool LastParameterListWasEmpty; }; void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); @@ -658,7 +757,7 @@ private: DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( AccessSpecifier AS = AS_none); - DeclPtrTy ParseFunctionDefinition(Declarator &D, + DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseKNRParamDeclarations(Declarator &D); // EndLoc, if non-NULL, is filled with the location of the last token of @@ -944,11 +1043,12 @@ private: DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd, - bool RequireSemi = true); + SourceLocation &DeclEnd); + DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd = 0); DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); - DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl); DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl); @@ -973,8 +1073,16 @@ private: void ParseEnumBody(SourceLocation StartLoc, DeclPtrTy TagDecl); void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); - void ParseStructDeclaration(DeclSpec &DS, - llvm::SmallVectorImpl<FieldDeclarator> &Fields); + + struct FieldCallback { + virtual DeclPtrTy invoke(FieldDeclarator &Field) = 0; + virtual ~FieldCallback() {} + + private: + virtual void _anchor(); + }; + + void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback); bool isDeclarationSpecifier(); bool isTypeSpecifierQualifier(); @@ -1197,6 +1305,21 @@ private: BaseResult ParseBaseSpecifier(DeclPtrTy ClassDecl); AccessSpecifier getAccessSpecifierIfPresent() const; + bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Id); + bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Result); + bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + TypeTy *ObjectType, + UnqualifiedId &Result); + //===--------------------------------------------------------------------===// // C++ 13.5: Overloaded operators [over.oper] // EndLoc, if non-NULL, is filled with the location of the last token of @@ -1247,6 +1370,7 @@ private: bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, + UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc = SourceLocation(), bool AllowTypeAnnotation = true); void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0); diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index d2f509df7b2c..5b3522c9eb49 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -26,6 +26,7 @@ namespace clang { class FunctionDecl; class FunctionType; class FunctionTemplateDecl; +class IdentifierInfo; class NamedDecl; class NestedNameSpecifier; class Sema; @@ -150,7 +151,8 @@ public: /// \brief Describes the kind of result generated. enum ResultKind { RK_Declaration = 0, //< Refers to a declaration - RK_Keyword //< Refers to a keyword or symbol. + RK_Keyword, //< Refers to a keyword or symbol. + RK_Macro //< Refers to a macro }; /// \brief The kind of result stored here. @@ -164,6 +166,9 @@ public: /// \brief When Kind == RK_Keyword, the string representing the keyword /// or symbol's spelling. const char *Keyword; + + /// \brief When Kind == RK_Macro, the identifier that refers to a macro. + IdentifierInfo *Macro; }; /// \brief Describes how good this result is, with zero being the best @@ -199,6 +204,12 @@ public: QualifierIsInformative(0), StartsNestedNameSpecifier(false), Qualifier(0) { } + /// \brief Build a result that refers to a macro. + Result(IdentifierInfo *Macro, unsigned Rank) + : Kind(RK_Macro), Macro(Macro), Rank(Rank), Hidden(false), + QualifierIsInformative(0), StartsNestedNameSpecifier(false), + Qualifier(0) { } + /// \brief Retrieve the declaration stored in this result. NamedDecl *getDeclaration() const { assert(Kind == RK_Declaration && "Not a declaration result"); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7f5fa35842af..aef3d2989415 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -22,9 +22,10 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "RecordLayoutBuilder.h" using namespace clang; @@ -138,9 +139,9 @@ void ASTContext::PrintStats() const { } -void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { +void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); - R = QualType(Ty, 0); + R = CanQualType::CreateUnsafe(QualType(Ty, 0)); Types.push_back(Ty); } @@ -872,6 +873,55 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, } } +/// CollectInheritedProtocols - Collect all protocols in current class and +/// those inherited by it. +void ASTContext::CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) { + if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), + PE = OI->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + + // Categories of this Interface. + for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); + CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) + CollectInheritedProtocols(CDeclChain, Protocols); + if (ObjCInterfaceDecl *SD = OI->getSuperClass()) + while (SD) { + CollectInheritedProtocols(SD, Protocols); + SD = SD->getSuperClass(); + } + return; + } + if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), + PE = OC->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + return; + } + if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), + PE = OP->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + return; + } +} + unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { unsigned count = 0; for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(), @@ -955,6 +1005,13 @@ DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, return DInfo; } +DeclaratorInfo *ASTContext::getTrivialDeclaratorInfo(QualType T, + SourceLocation L) { + DeclaratorInfo *DI = CreateDeclaratorInfo(T); + DI->getTypeLoc().initialize(L); + return DI; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -1757,6 +1814,19 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + QualType Canon) { + llvm::SmallVector<TemplateArgument, 4> ArgVec; + ArgVec.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ArgVec.push_back(Args[i].getArgument()); + + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon); +} + +QualType +ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { @@ -2235,7 +2305,7 @@ CanQualType ASTContext::getCanonicalType(QualType T) { DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), DSAT->getIndexTypeCVRQualifiers(), - DSAT->getBracketsRange())); + DSAT->getBracketsRange())->getCanonicalTypeInternal()); VariableArrayType *VAT = cast<VariableArrayType>(AT); return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, @@ -2290,17 +2360,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { return Arg; case TemplateArgument::Declaration: - return TemplateArgument(SourceLocation(), - Arg.getAsDecl()->getCanonicalDecl()); + return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); case TemplateArgument::Integral: - return TemplateArgument(SourceLocation(), - *Arg.getAsIntegral(), + return TemplateArgument(*Arg.getAsIntegral(), getCanonicalType(Arg.getIntegralType())); case TemplateArgument::Type: - return TemplateArgument(SourceLocation(), - getCanonicalType(Arg.getAsType())); + return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { // FIXME: Allocate in ASTContext @@ -2847,12 +2914,13 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { bool HasCopyAndDispose = BlockRequiresCopying(Ty); // FIXME: Move up - static int UniqueBlockByRefTypeID = 0; - char Name[36]; - sprintf(Name, "__Block_byref_%d_%s", ++UniqueBlockByRefTypeID, DeclName); + static unsigned int UniqueBlockByRefTypeID = 0; + llvm::SmallString<36> Name; + llvm::raw_svector_ostream(Name) << "__Block_byref_" << + ++UniqueBlockByRefTypeID << '_' << DeclName; RecordDecl *T; T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name)); + &Idents.get(Name.str())); T->startDefinition(); QualType Int32Ty = IntTy; assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); @@ -2896,12 +2964,13 @@ QualType ASTContext::getBlockParmType( bool BlockHasCopyDispose, llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { // FIXME: Move up - static int UniqueBlockParmTypeID = 0; - char Name[36]; - sprintf(Name, "__block_literal_%u", ++UniqueBlockParmTypeID); + static unsigned int UniqueBlockParmTypeID = 0; + llvm::SmallString<36> Name; + llvm::raw_svector_ostream(Name) << "__block_literal_" + << ++UniqueBlockParmTypeID; RecordDecl *T; T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name)); + &Idents.get(Name.str())); QualType FieldTypes[] = { getPointerType(VoidPtrTy), IntTy, @@ -3409,7 +3478,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - if (OPT->isObjCClassType()) { + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + // FIXME: Consider if we need to output qualifiers for 'Class<p>'. + // Since this is a binary compatibility issue, need to consult with runtime + // folks. Fortunately, this is a *very* obsure construct. S += '#'; return; } @@ -3447,9 +3519,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } S += '@'; - if (FD || EncodingProperty) { + if (OPT->getInterfaceDecl() && (FD || EncodingProperty)) { S += '"'; - S += OPT->getInterfaceDecl()->getNameAsCString(); + S += OPT->getInterfaceDecl()->getIdentifier()->getName(); for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) { S += '<'; @@ -3590,12 +3662,42 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +/// \brief Retrieve the template name that represents a dependent +/// template name such as \c MetaFun::template operator+. +TemplateName +ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) { + assert((!NNS || NNS->isDependent()) && + "Nested name specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateName::Profile(ID, NNS, Operator); + + void *InsertPos = 0; + DependentTemplateName *QTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + + if (QTN) + return TemplateName(QTN); + + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + if (CanonNNS == NNS) { + QTN = new (*this,4) DependentTemplateName(NNS, Operator); + } else { + TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); + QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. -QualType ASTContext::getFromTargetType(unsigned Type) const { +CanQualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { - case TargetInfo::NoInt: return QualType(); + case TargetInfo::NoInt: return CanQualType(); case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -3607,7 +3709,7 @@ QualType ASTContext::getFromTargetType(unsigned Type) const { } assert(false && "Unhandled TargetInfo::IntType value"); - return QualType(); + return CanQualType(); } //===----------------------------------------------------------------------===// @@ -3836,6 +3938,79 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, return false; } +/// getIntersectionOfProtocols - This routine finds the intersection of set +/// of protocols inherited from two distinct objective-c pointer objects. +/// It is used to build composite qualifier list of the composite type of +/// the conditional expression involving two objective-c pointer objects. +static +void getIntersectionOfProtocols(ASTContext &Context, + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; + unsigned LHSNumProtocols = LHS->getNumProtocols(); + if (LHSNumProtocols > 0) + InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); + else { + llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); + InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), + LHSInheritedProtocols.end()); + } + + unsigned RHSNumProtocols = RHS->getNumProtocols(); + if (RHSNumProtocols > 0) { + ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin(); + for (unsigned i = 0; i < RHSNumProtocols; ++i) + if (InheritedProtocolSet.count(RHSProtocols[i])) + IntersectionOfProtocols.push_back(RHSProtocols[i]); + } + else { + llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols; + Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols); + // FIXME. This may cause duplication of protocols in the list, but should + // be harmless. + for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i) + if (InheritedProtocolSet.count(RHSInheritedProtocols[i])) + IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]); + } +} + +/// areCommonBaseCompatible - Returns common base class of the two classes if +/// one found. Note that this is O'2 algorithm. But it will be called as the +/// last type comparison in a ?-exp of ObjC pointer types before a +/// warning is issued. So, its invokation is extremely rare. +QualType ASTContext::areCommonBaseCompatible( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (!LHS || !RHS) + return QualType(); + + while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) { + QualType LHSTy = getObjCInterfaceType(LHSIDecl); + LHS = LHSTy->getAs<ObjCInterfaceType>(); + if (canAssignObjCInterfaces(LHS, RHS)) { + llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols; + getIntersectionOfProtocols(*this, + LHSOPT, RHSOPT, IntersectionOfProtocols); + if (IntersectionOfProtocols.empty()) + LHSTy = getObjCObjectPointerType(LHSTy); + else + LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0], + IntersectionOfProtocols.size()); + return LHSTy; + } + } + + return QualType(); +} + bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS) { // Verify that the base decls are compatible: the RHS must be a subclass of diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 20e1150b22c2..e541406790a6 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangAST StmtPrinter.cpp StmtProfile.cpp StmtViz.cpp + TemplateBase.cpp TemplateName.cpp Type.cpp TypeLoc.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d270a958f0ae..a6996a4bfe5c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -91,13 +91,6 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); } -QualType ParmVarDecl::getOriginalType() const { - if (const OriginalParmVarDecl *PVD = - dyn_cast<OriginalParmVarDecl>(this)) - return PVD->OriginalType; - return getType(); -} - SourceRange ParmVarDecl::getDefaultArgRange() const { if (const Expr *E = getInit()) return E->getSourceRange(); @@ -140,14 +133,6 @@ bool VarDecl::isExternC() const { return false; } -OriginalParmVarDecl *OriginalParmVarDecl::Create( - ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, - QualType OT, StorageClass S, Expr *DefArg) { - return new (C) OriginalParmVarDecl(DC, L, Id, T, DInfo, OT, S, DefArg); -} - FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, @@ -193,9 +178,9 @@ void EnumConstantDecl::Destroy(ASTContext& C) { } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - IdentifierInfo *Id, QualType T) { - return new (C) TypedefDecl(DC, L, Id, T); + SourceLocation L, IdentifierInfo *Id, + DeclaratorInfo *DInfo) { + return new (C) TypedefDecl(DC, L, Id, DInfo); } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -398,6 +383,19 @@ bool VarDecl::isOutOfLine() const { return false; } +VarDecl *VarDecl::getOutOfLineDefinition() { + if (!isStaticDataMember()) + return 0; + + for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) + return *RD; + } + + return 0; +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -644,7 +642,34 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -/// \brief For an inline function definition in C, determine whether the +bool FunctionDecl::isInlined() const { + if (isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine())) + return true; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // Handle below. + break; + } + + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(PatternDecl); + + if (Pattern && PatternDecl) + return PatternDecl->isInlined(); + + return false; +} + +/// \brief For an inline function definition in C or C++, determine whether the /// definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. @@ -663,9 +688,10 @@ unsigned FunctionDecl::getMinRequiredArguments() const { /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { assert(isThisDeclarationADefinition() && "Must have the function definition"); - assert(isInline() && "Function must be inline"); + assert(isInlined() && "Function must be inline"); + ASTContext &Context = getASTContext(); - if (!getASTContext().getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { + if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { // GNU inline semantics. Based on a number of examples, we came up with the // following heuristic: if the "inline" keyword is present on a // declaration of the function but "extern" is not present on that @@ -675,7 +701,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); Redecl != RedeclEnd; ++Redecl) { - if (Redecl->isInline() && Redecl->getStorageClass() != Extern) + if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != Extern) return true; } @@ -694,7 +720,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) continue; - if (!Redecl->isInline() || Redecl->getStorageClass() == Extern) + if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == Extern) return true; // Not an inline definition } @@ -755,6 +781,59 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, TemplateOrSpecialization = Info; } +bool FunctionDecl::isImplicitlyInstantiable() const { + // If this function already has a definition or is invalid, it can't be + // implicitly instantiated. + if (isInvalidDecl() || getBody()) + return false; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDefinition: + return false; + + case TSK_ImplicitInstantiation: + return true; + + case TSK_ExplicitInstantiationDeclaration: + // Handled below. + break; + } + + // Find the actual template from which we will instantiate. + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(PatternDecl); + + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (!Pattern || !PatternDecl) + return true; + + return PatternDecl->isInlined(); +} + +FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { + while (Primary->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (Primary->isMemberSpecialization()) + break; + + Primary = Primary->getInstantiatedFromMemberTemplate(); + } + + return Primary->getTemplatedDecl(); + } + + return getInstantiatedFromMemberFunction(); +} + FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 224bf877ad24..6cfdcdd3e50e 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -199,7 +199,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Var: case ImplicitParam: case ParmVar: - case OriginalParmVar: case NonTypeTemplateParm: case Using: case UnresolvedUsing: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 457f4c85a047..b4c0c59733e5 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -189,7 +189,10 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, // A user-declared copy assignment operator is a non-static non-template // member function of class X with exactly one parameter of type X, X&, // const X&, volatile X& or const volatile X&. - const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); + const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); + if (!Method) + continue; + if (Method->isStatic()) continue; if (Method->getPrimaryTemplate()) @@ -364,34 +367,36 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, } } } - + if (getNumBases() == 0 && getNumVBases() == 0) return; - + llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; if (!inTopClass) collectConversionFunctions(ConversionFunctions); - + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), E = vbases_end(); VBase != E; ++VBase) { - CXXRecordDecl *VBaseClassDecl - = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - VBaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - + if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) { + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(RT->getDecl()); + VBaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + } } for (CXXRecordDecl::base_class_iterator Base = bases_begin(), E = bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - BaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - + if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(RT->getDecl()); + + BaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + } } } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 7f38ac1d9ad0..7b48b724c0eb 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -118,6 +118,27 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property +/// with name 'PropertyId' in the primary class; including those in protocols +/// (direct or indirect) used by the promary class. +/// FIXME: Convert to DeclContext lookup... +/// +ObjCPropertyDecl * +ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const { + assert(isa<ObjCInterfaceDecl>(this) && "FindPropertyVisibleInPrimaryClass"); + for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) + if ((*I)->getIdentifier() == PropertyId) + return *I; + const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this); + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), + E = OID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + return 0; +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) @@ -288,7 +309,7 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { } else if (ObjCCategoryImplDecl *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); } @@ -306,7 +327,7 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { } else if (ObjCCategoryImplDecl *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), isInstanceMethod())) return MD; @@ -635,7 +656,7 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); } -ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryClass() const { +ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { return getClassInterface()->FindCategoryDeclaration(getIdentifier()); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 9d0d836cf62b..d9d195016bf3 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -52,7 +52,6 @@ namespace { void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitParmVarDecl(ParmVarDecl *D); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); @@ -324,7 +323,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; } - if (D->isInline()) Out << "inline "; + if (D->isInlineSpecified()) Out << "inline "; if (D->isVirtualAsWritten()) Out << "virtual "; } @@ -489,7 +488,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { std::string Name = D->getNameAsString(); QualType T = D->getType(); - if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D)) + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) T = Parm->getOriginalType(); T.getAsStringInternal(Name, Policy); Out << Name; @@ -508,10 +507,6 @@ void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); } -void DeclPrinter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - VisitVarDecl(D); -} - void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Out << "__asm ("; D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 9a1c65416f71..9ebc91afe142 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -1,4 +1,4 @@ -//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// +//===--- DeclTemplate.cpp - Template Declaration AST Node Implementation --===// // // The LLVM Compiler Infrastructure // @@ -15,6 +15,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -67,6 +68,21 @@ unsigned TemplateParameterList::getMinRequiredArguments() const { return NumRequiredArgs; } +unsigned TemplateParameterList::getDepth() const { + if (size() == 0) + return 0; + + const NamedDecl *FirstParm = getParam(0); + if (const TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(FirstParm)) + return TTP->getDepth(); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(FirstParm)) + return NTTP->getDepth(); + else + return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth(); +} + //===----------------------------------------------------------------------===// // TemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -194,8 +210,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { Param != ParamEnd; ++Param) { if (isa<TemplateTypeParmDecl>(*Param)) { QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); - TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), - ParamType)); + TemplateArgs.push_back(TemplateArgument(ParamType)); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), @@ -205,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); - TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); + TemplateArgs.push_back(TemplateArgument(TTP)); } } @@ -229,6 +244,18 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack); } +SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument->getTypeLoc().getFullSourceRange().getBegin(); +} + +unsigned TemplateTypeParmDecl::getDepth() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth(); +} + +unsigned TemplateTypeParmDecl::getIndex() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex(); +} + //===----------------------------------------------------------------------===// // NonTypeTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// @@ -264,34 +291,6 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { } //===----------------------------------------------------------------------===// -// TemplateArgument Implementation -//===----------------------------------------------------------------------===// - -TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { - TypeOrValue = reinterpret_cast<uintptr_t>(E); - StartLoc = E->getSourceRange().getBegin(); -} - -/// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, - bool CopyArgs) { - assert(isNull() && "Must call setArgumentPack on a null argument"); - - Kind = Pack; - Args.NumArgs = NumArgs; - Args.CopyArgs = CopyArgs; - if (!Args.CopyArgs) { - Args.Args = args; - return; - } - - // FIXME: Allocate in ASTContext - Args.Args = new TemplateArgument[NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = args[I]; -} - -//===----------------------------------------------------------------------===// // TemplateArgumentListBuilder Implementation //===----------------------------------------------------------------------===// @@ -459,12 +458,19 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, + TemplateArgumentLoc *ArgInfos, unsigned N, ClassTemplatePartialSpecializationDecl *PrevDecl) { + TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; + for (unsigned I = 0; I != N; ++I) + ClonedArgs[I] = ArgInfos[I]; + ClassTemplatePartialSpecializationDecl *Result = new (Context)ClassTemplatePartialSpecializationDecl(Context, DC, L, Params, SpecializedTemplate, - Builder, PrevDecl); + Builder, + ClonedArgs, N, + PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getTypeDeclType(Result, PrevDecl); return Result; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index a4de3e5b0f7a..a8ea752a4a7e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; @@ -30,6 +31,91 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// +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), + DecoratedD(D, + (Qualifier? HasQualifierFlag : 0) | + (HasExplicitTemplateArgumentList? + HasExplicitTemplateArgumentListFlag : 0)), + Loc(NameLoc) { + 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]); + } +} + +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); +} + +DeclRefExpr *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) { + std::size_t Size = sizeof(DeclRefExpr); + if (Qualifier != 0) + Size += sizeof(NameQualifier); + + if (HasExplicitTemplateArgumentList) + Size += sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs; + + void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>()); + return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc, + HasExplicitTemplateArgumentList, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc, + T, TD, VD); +} + +SourceRange DeclRefExpr::getSourceRange() const { + // FIXME: Does not handle multi-token names well, e.g., operator[]. + SourceRange R(Loc); + + if (hasQualifier()) + R.setBegin(getQualifierRange().getBegin()); + if (hasExplicitTemplateArgumentList()) + R.setEnd(getRAngleLoc()); + return R; +} + // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, @@ -343,7 +429,7 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, unsigned numtargs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent() || (qual && qual->isDependent()), @@ -365,9 +451,9 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, ETemplateArgs->RAngleLoc = rangle; ETemplateArgs->NumTemplateArgs = numtargs; - TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs(); + TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); for (unsigned I = 0; I < numtargs; ++I) - new (TemplateArgs + I) TemplateArgument(targs[I]); + new (TemplateArgs + I) TemplateArgumentLoc(targs[I]); } } @@ -378,7 +464,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty) { @@ -388,7 +474,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, if (has_explicit) Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgument) * numtargs; + sizeof(TemplateArgumentLoc) * numtargs; void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, @@ -418,6 +504,8 @@ const char *CastExpr::getCastKindName() const { return "NullToMemberPointer"; case CastExpr::CK_BaseToDerivedMemberPointer: return "BaseToDerivedMemberPointer"; + case CastExpr::CK_DerivedToBaseMemberPointer: + return "DerivedToBaseMemberPointer"; case CastExpr::CK_UserDefinedConversion: return "UserDefinedConversion"; case CastExpr::CK_ConstructorConversion: @@ -610,7 +698,7 @@ Stmt *BlockExpr::getBody() { /// with location to warn on and the source range[s] to report with the /// warning. bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, - SourceRange &R2) const { + SourceRange &R2, ASTContext &Ctx) const { // Don't warn if the expr is type dependent. The type could end up // instantiating to void. if (isTypeDependent()) @@ -623,7 +711,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return true; case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr()-> - isUnusedResultAWarning(Loc, R1, R2); + isUnusedResultAWarning(Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); @@ -636,17 +724,18 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return false; // Not a warning. case UnaryOperator::Deref: // Dereferencing a volatile pointer is a side-effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; break; case UnaryOperator::Real: case UnaryOperator::Imag: // accessing a piece of a volatile complex is a side-effect. - if (UO->getSubExpr()->getType().isVolatileQualified()) + if (Ctx.getCanonicalType(UO->getSubExpr()->getType()) + .isVolatileQualified()) return false; break; case UnaryOperator::Extension: - return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } Loc = UO->getOperatorLoc(); R1 = UO->getSubExpr()->getSourceRange(); @@ -656,8 +745,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, const BinaryOperator *BO = cast<BinaryOperator>(this); // Consider comma to have side effects if the LHS or RHS does. if (BO->getOpcode() == BinaryOperator::Comma) - return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || - BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); + return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); if (BO->isAssignmentOp()) return false; @@ -674,15 +763,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // warning, warn about them. const ConditionalOperator *Exp = cast<ConditionalOperator>(this); if (Exp->getLHS() && - Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) + Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) return true; - return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); + return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } case MemberExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; Loc = cast<MemberExpr>(this)->getMemberLoc(); R1 = SourceRange(Loc, Loc); @@ -692,7 +781,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case ArraySubscriptExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc(); R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange(); @@ -750,7 +839,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt(); if (!CS->body_empty()) if (const Expr *E = dyn_cast<Expr>(CS->body_back())) - return E->isUnusedResultAWarning(Loc, R1, R2); + return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); Loc = cast<StmtExpr>(this)->getLParenLoc(); R1 = getSourceRange(); @@ -768,20 +857,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // If this is a cast to void, check the operand. Otherwise, the result of // the cast is unused. if (getType()->isVoidType()) - return cast<CastExpr>(this)->getSubExpr() - ->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CastExpr>(this)->getSubExpr() + ->isUnusedResultAWarning(Loc, R1, R2, Ctx)); Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); return true; case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema - return cast<ImplicitCastExpr>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<ImplicitCastExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXDefaultArgExprClass: - return cast<CXXDefaultArgExpr>(this) - ->getExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXDefaultArgExpr>(this) + ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side @@ -789,11 +878,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXDeleteExprClass: return false; case CXXBindTemporaryExprClass: - return cast<CXXBindTemporaryExpr>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXBindTemporaryExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXExprWithTemporariesClass: - return cast<CXXExprWithTemporaries>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXExprWithTemporaries>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } } @@ -855,8 +944,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx); return LV_Valid; - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { // C99 6.5.1p2 + case DeclRefExprClass: { // C99 6.5.1p2 const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl(); if (DeclCanBeLvalue(RefdDecl, Ctx)) return LV_Valid; @@ -1042,6 +1130,18 @@ 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; } @@ -1133,8 +1233,7 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { + case DeclRefExprClass: { const Decl *D = cast<DeclRefExpr>(this)->getDecl(); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasGlobalStorage()) @@ -1432,7 +1531,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return ICEDiag(2, E->getLocStart()); } case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && @@ -1442,16 +1540,35 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // type initialized by an ICE can be used in ICEs. if (const VarDecl *Dcl = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { - if (Dcl->isInitKnownICE()) { - // We have already checked whether this subexpression is an - // integral constant expression. - if (Dcl->isInitICE()) - return NoDiag(); - else - return ICEDiag(2, E->getLocStart()); - } + Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); + if (Quals.hasVolatile() || !Quals.hasConst()) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // Look for the definition of this variable, which will actually have + // an initializer. + const VarDecl *Def = 0; + const Expr *Init = Dcl->getDefinition(Def); + if (Init) { + if (Def->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (Def->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } - if (const Expr *Init = Dcl->getInit()) { + // C++ [class.static.data]p4: + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. + if (Def->isOutOfLine()) { + Dcl->setInitKnownICE(Ctx, false); + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + ICEDiag Result = CheckICE(Init, Ctx); // Cache the result of the ICE test. Dcl->setInitKnownICE(Ctx, Result.Val == 0); @@ -1654,7 +1771,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, } EvalResult EvalResult; if (!Evaluate(EvalResult, Ctx)) - assert(0 && "ICE cannot be evaluated!"); + llvm::llvm_unreachable("ICE cannot be evaluated!"); assert(!EvalResult.HasSideEffects && "ICE with side effects!"); assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); Result = EvalResult.Val.getInt(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index cba0e220952e..7c6fc41ef12b 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -151,7 +151,7 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(TemplateIdRefExprClass, T, @@ -164,10 +164,10 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { - TemplateArgument *StoredTemplateArgs - = reinterpret_cast<TemplateArgument *> (this+1); + TemplateArgumentLoc *StoredTemplateArgs + = reinterpret_cast<TemplateArgumentLoc *> (this+1); for (unsigned I = 0; I != NumTemplateArgs; ++I) - new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); } TemplateIdRefExpr * @@ -176,19 +176,19 @@ TemplateIdRefExpr::Create(ASTContext &Context, QualType T, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + - sizeof(TemplateArgument) * NumTemplateArgs); + sizeof(TemplateArgumentLoc) * NumTemplateArgs); return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template, TemplateNameLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc); } void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { - const TemplateArgument *TemplateArgs = getTemplateArgs(); + const TemplateArgumentLoc *TemplateArgs = getTemplateArgs(); for (unsigned I = 0; I != NumTemplateArgs; ++I) - if (Expr *E = TemplateArgs[I].getAsExpr()) + if (Expr *E = TemplateArgs[I].getArgument().getAsExpr()) E->Destroy(Context); this->~TemplateIdRefExpr(); Context.Deallocate(this); @@ -528,7 +528,7 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), @@ -545,9 +545,9 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, ETemplateArgs->RAngleLoc = RAngleLoc; ETemplateArgs->NumTemplateArgs = NumTemplateArgs; - TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); + TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); for (unsigned I = 0; I < NumTemplateArgs; ++I) - new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); } } @@ -562,7 +562,7 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { if (!HasExplicitTemplateArgs) @@ -573,7 +573,7 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgument) * NumTemplateArgs, + sizeof(TemplateArgumentLoc) * NumTemplateArgs, llvm::alignof<CXXUnresolvedMemberExpr>()); return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 94d22998ebbe..7862c57c2d47 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -58,7 +58,8 @@ struct EvalInfo { static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); -static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, + EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); @@ -151,6 +152,67 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, return Result; } +namespace { +class VISIBILITY_HIDDEN HasSideEffect + : public StmtVisitor<HasSideEffect, bool> { + EvalInfo &Info; +public: + + HasSideEffect(EvalInfo &info) : Info(info) {} + + // Unhandled nodes conservatively default to having side effects. + bool VisitStmt(Stmt *S) { + return true; + } + + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + // We don't want to evaluate BlockExprs multiple times, as they generate + // a ton of code. + bool VisitBlockExpr(BlockExpr *E) { return true; } + bool VisitPredefinedExpr(PredefinedExpr *E) { return false; } + bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E) + { return Visit(E->getInitializer()); } + bool VisitMemberExpr(MemberExpr *E) { return Visit(E->getBase()); } + bool VisitIntegerLiteral(IntegerLiteral *E) { return false; } + bool VisitFloatingLiteral(FloatingLiteral *E) { return false; } + bool VisitStringLiteral(StringLiteral *E) { return false; } + bool VisitCharacterLiteral(CharacterLiteral *E) { return false; } + bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; } + bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitChooseExpr(ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + bool VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); } + bool VisitBinAssign(BinaryOperator *E) { return true; } + bool VisitCompoundAssignOperator(BinaryOperator *E) { return true; } + bool VisitBinaryOperator(BinaryOperator *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitUnaryPreInc(UnaryOperator *E) { return true; } + bool VisitUnaryPostInc(UnaryOperator *E) { return true; } + bool VisitUnaryPreDec(UnaryOperator *E) { return true; } + bool VisitUnaryPostDec(UnaryOperator *E) { return true; } + bool VisitUnaryDeref(UnaryOperator *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return Visit(E->getSubExpr()); + } + bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } +}; + +bool HasSideEffects(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult Result; + EvalInfo Info(Ctx, Result); + + return HasSideEffect(Info).Visit(const_cast<Expr*>(E)); +} + +} // end anonymous namespace + //===----------------------------------------------------------------------===// // LValue Evaluation //===----------------------------------------------------------------------===// @@ -208,8 +270,9 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (!VD->getType()->isReferenceType()) return APValue(E, 0); // FIXME: Check whether VD might be overridden! - if (VD->getInit()) - return Visit(VD->getInit()); + const VarDecl *Def = 0; + if (const Expr *Init = VD->getDefinition(Def)) + return Visit(const_cast<Expr *>(Init)); } return APValue(); @@ -793,11 +856,14 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. - if (E->getType().getCVRQualifiers() == Qualifiers::Const) { + if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() + == Qualifiers::Const) { if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) { - if (APValue *V = D->getEvaluatedValue()) - return Success(V->getInt(), E); - if (const Expr *Init = D->getInit()) { + const VarDecl *Def = 0; + if (const Expr *Init = D->getDefinition(Def)) { + if (APValue *V = D->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); @@ -873,6 +939,40 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + + case Builtin::BI__builtin_object_size: { + const Expr *Arg = E->getArg(0)->IgnoreParens(); + Expr::EvalResult Base; + if (Arg->EvaluateAsAny(Base, Info.Ctx) + && Base.Val.getKind() == APValue::LValue + && !Base.HasSideEffects) + if (const Expr *LVBase = Base.Val.getLValueBase()) + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVBase)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (!VD->getType()->isIncompleteType() + && VD->getType()->isObjectType() + && !VD->getType()->isVariablyModifiedType() + && !VD->getType()->isDependentType()) { + uint64_t Size = Info.Ctx.getTypeSize(VD->getType()) / 8; + uint64_t Offset = Base.Val.getLValueOffset(); + if (Offset <= Size) + Size -= Base.Val.getLValueOffset(); + else + Size = 0; + return Success(Size, E); + } + } + } + + if (HasSideEffects(E->getArg(0), Info.Ctx)) { + if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2) + return Success(-1ULL, E); + return Success(0, E); + } + + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); @@ -1801,6 +1901,33 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { return true; } +bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result, true); + + if (getType()->isVectorType()) { + if (!EvaluateVector(this, Result.Val, Info)) + return false; + } else if (getType()->isIntegerType()) { + if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this))) + return false; + } else if (getType()->hasPointerRepresentation()) { + if (!EvaluatePointer(this, Result.Val, Info)) + return false; + } else if (getType()->isRealFloatingType()) { + llvm::APFloat f(0.0); + if (!EvaluateFloat(this, f, Info)) + return false; + + Result.Val = APValue(f); + } else if (getType()->isAnyComplexType()) { + if (!EvaluateComplex(this, Result.Val, Info)) + return false; + } else + return false; + + return true; +} + bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index c79cc3c1dbb1..0b159c3a7bd8 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -47,6 +47,8 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { if (!i->isVirtual()) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); // Skip the PrimaryBase here, as it is laid down first. @@ -82,6 +84,8 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { // Now traverse all bases and find primary bases for them. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); @@ -97,6 +101,8 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, const CXXRecordDecl *&FirstPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); if (!i->isVirtual()) { @@ -123,6 +129,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // indirect bases, and record all their primary virtual base classes. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); IdentifyPrimaryBases(Base); @@ -173,6 +181,8 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); #if 0 @@ -235,6 +245,8 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; @@ -305,6 +317,8 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 6e4cdd2fe2ee..b57b37d0df4d 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -12,7 +12,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <map> namespace clang { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 2af19765dfaa..4bd7f964be6c 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -473,14 +473,14 @@ void StmtPrinter::VisitExpr(Expr *Node) { } void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); OS << Node->getDecl()->getNameAsString(); -} - -void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { - NamedDecl *D = Node->getDecl(); - - Node->getQualifier()->print(OS, Policy); - OS << D->getNameAsString(); + if (Node->hasExplicitTemplateArgumentList()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index c4d42f6be228..02e0c74bb63a 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -60,7 +60,10 @@ namespace { /// \brief Visit template arguments that occur within an expression or /// statement. - void VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + void VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); + + /// \brief Visit a single template argument. + void VisitTemplateArgument(const TemplateArgument &Arg); }; } @@ -206,7 +209,9 @@ void StmtProfiler::VisitExpr(Expr *S) { void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) { VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); VisitDecl(S->getDecl()); + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) { @@ -521,11 +526,6 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { VisitType(S->getQueriedType()); } -void StmtProfiler::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *S) { - VisitDeclRefExpr(S); - VisitNestedNameSpecifier(S->getQualifier()); -} - void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { VisitExpr(S); VisitName(S->getDeclName()); @@ -677,39 +677,42 @@ void StmtProfiler::VisitTemplateName(TemplateName Name) { Name.Profile(ID); } -void StmtProfiler::VisitTemplateArguments(const TemplateArgument *Args, +void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs) { ID.AddInteger(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - const TemplateArgument &Arg = Args[I]; - - // Mostly repetitive with TemplateArgument::Profile! - ID.AddInteger(Arg.getKind()); - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - - case TemplateArgument::Type: - VisitType(Arg.getAsType()); - break; - - case TemplateArgument::Declaration: - VisitDecl(Arg.getAsDecl()); - break; - - case TemplateArgument::Integral: - Arg.getAsIntegral()->Profile(ID); - VisitType(Arg.getIntegralType()); - break; - - case TemplateArgument::Expression: - Visit(Arg.getAsExpr()); - break; - - case TemplateArgument::Pack: - VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size()); - break; - } + for (unsigned I = 0; I != NumArgs; ++I) + VisitTemplateArgument(Args[I].getArgument()); +} + +void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { + // Mostly repetitive with TemplateArgument::Profile! + ID.AddInteger(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Declaration: + VisitDecl(Arg.getAsDecl()); + break; + + case TemplateArgument::Integral: + Arg.getAsIntegral()->Profile(ID); + VisitType(Arg.getIntegralType()); + break; + + case TemplateArgument::Expression: + Visit(Arg.getAsExpr()); + break; + + case TemplateArgument::Pack: + const TemplateArgument *Pack = Arg.pack_begin(); + for (unsigned i = 0, e = Arg.pack_size(); i != e; ++i) + VisitTemplateArgument(Pack[i]); + break; } } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp new file mode 100644 index 000000000000..94e1ca1e06e7 --- /dev/null +++ b/lib/AST/TemplateBase.cpp @@ -0,0 +1,97 @@ +//===--- TemplateBase.cpp - Common template AST class implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements common classes used throughout C++ template +// representations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/FoldingSet.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// TemplateArgument Implementation +//===----------------------------------------------------------------------===// + +/// \brief Construct a template argument pack. +void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, + bool CopyArgs) { + assert(isNull() && "Must call setArgumentPack on a null argument"); + + Kind = Pack; + Args.NumArgs = NumArgs; + Args.CopyArgs = CopyArgs; + if (!Args.CopyArgs) { + Args.Args = args; + return; + } + + // FIXME: Allocate in ASTContext + Args.Args = new TemplateArgument[NumArgs]; + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I] = args[I]; +} + +void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context) const { + ID.AddInteger(Kind); + switch (Kind) { + case Null: + break; + + case Type: + getAsType().Profile(ID); + break; + + case Declaration: + ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); + break; + + case Integral: + getAsIntegral()->Profile(ID); + getIntegralType().Profile(ID); + break; + + case Expression: + getAsExpr()->Profile(ID, Context, true); + break; + + case Pack: + ID.AddInteger(Args.NumArgs); + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I].Profile(ID, Context); + } +} + +//===----------------------------------------------------------------------===// +// TemplateArgumentLoc Implementation +//===----------------------------------------------------------------------===// + +SourceRange TemplateArgumentLoc::getSourceRange() const { + switch (Argument.getKind()) { + case TemplateArgument::Expression: + return getSourceExpression()->getSourceRange(); + case TemplateArgument::Declaration: + return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::Type: + return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return SourceRange(); + } + + // Silence bonus gcc warning. + return SourceRange(); +} diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 24588bc5f11f..5b4cf0ad94f6 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -56,7 +56,7 @@ void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) - OS << Template->getIdentifier()->getName(); + OS << Template->getNameAsString(); else if (OverloadedFunctionDecl *Ovl = Storage.dyn_cast<OverloadedFunctionDecl *>()) OS << Ovl->getNameAsString(); @@ -70,8 +70,11 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); OS << "template "; - // FIXME: Shouldn't we have a more general kind of name? - OS << DTN->getName()->getName(); + + if (DTN->isIdentifier()) + OS << DTN->getIdentifier()->getName(); + else + OS << "operator " << getOperatorSpelling(DTN->getOperator()); } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5fb0178834ff..3608d34c691d 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -224,6 +224,8 @@ QualType Type::getPointeeType() const { return OPT->getPointeeType(); if (const BlockPointerType *BPT = getAs<BlockPointerType>()) return BPT->getPointeeType(); + if (const ReferenceType *RT = getAs<ReferenceType>()) + return RT->getPointeeType(); return QualType(); } @@ -791,40 +793,48 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } -bool -TemplateSpecializationType:: -anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { - switch (Args[Idx].getKind()) { - case TemplateArgument::Null: - assert(false && "Should not have a NULL template argument"); - break; - - case TemplateArgument::Type: - if (Args[Idx].getAsType()->isDependentType()) - return true; - break; - - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - // Never dependent - break; - - case TemplateArgument::Expression: - if (Args[Idx].getAsExpr()->isTypeDependent() || - Args[Idx].getAsExpr()->isValueDependent()) - return true; - break; - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } +static bool isDependent(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Should not have a NULL template argument"); + return false; + + case TemplateArgument::Type: + return Arg.getAsType()->isDependentType(); + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // Never dependent + return false; + + case TemplateArgument::Expression: + return (Arg.getAsExpr()->isTypeDependent() || + Arg.getAsExpr()->isValueDependent()); + + case TemplateArgument::Pack: + assert(0 && "FIXME: Implement!"); + return false; } return false; } +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (isDependent(Args[i].getArgument())) + return true; + return false; +} + +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (isDependent(Args[i])) + return true; + return false; +} + TemplateSpecializationType:: TemplateSpecializationType(ASTContext &Context, TemplateName T, const TemplateArgument *Args, @@ -1260,6 +1270,38 @@ void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, co getReplacementType().getAsStringInternal(InnerString, Policy); } +static void PrintTemplateArgument(std::string &Buffer, + const TemplateArgument &Arg, + const PrintingPolicy &Policy) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Null template argument"); + break; + + case TemplateArgument::Type: + Arg.getAsType().getAsStringInternal(Buffer, Policy); + break; + + case TemplateArgument::Declaration: + Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString(); + break; + + case TemplateArgument::Integral: + Buffer = Arg.getAsIntegral()->toString(10, true); + break; + + case TemplateArgument::Expression: { + llvm::raw_string_ostream s(Buffer); + Arg.getAsExpr()->printPretty(s, 0, Policy); + break; + } + + case TemplateArgument::Pack: + assert(0 && "FIXME: Implement!"); + break; + } +} + std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, @@ -1273,32 +1315,41 @@ TemplateSpecializationType::PrintTemplateArgumentList( // Print the argument into a string. std::string ArgString; - switch (Args[Arg].getKind()) { - case TemplateArgument::Null: - assert(false && "Null template argument"); - break; - - case TemplateArgument::Type: - Args[Arg].getAsType().getAsStringInternal(ArgString, Policy); - break; - - case TemplateArgument::Declaration: - ArgString = cast<NamedDecl>(Args[Arg].getAsDecl())->getNameAsString(); - break; - - case TemplateArgument::Integral: - ArgString = Args[Arg].getAsIntegral()->toString(10, true); - break; - - case TemplateArgument::Expression: { - llvm::raw_string_ostream s(ArgString); - Args[Arg].getAsExpr()->printPretty(s, 0, Policy); - break; - } - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } + PrintTemplateArgument(ArgString, Args[Arg], Policy); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + SpecString += ' '; + + SpecString += ArgString; + } + + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. We don't *have* to do this in + // C++0x, but it's still good hygiene. + if (SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + SpecString += '>'; + + return SpecString; +} + +// Sadly, repeat all that with TemplateArgLoc. +std::string TemplateSpecializationType:: +PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy); // If this is the first argument and its string representation // begins with the global scope specifier ('::foo'), add a space diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp new file mode 100644 index 000000000000..1cf5d0c4af2d --- /dev/null +++ b/lib/Analysis/AttrNonNullChecker.cpp @@ -0,0 +1,100 @@ +//===--- AttrNonNullChecker.h - Undefined arguments 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 AttrNonNullChecker, a builtin check in GRExprEngine that +// performs checks for arguments declared to have nonnull attribute. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *AttrNonNullChecker::getTag() { + static int x = 0; + return &x; +} + +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()); + + const FunctionDecl* FD = X.getAsFunctionDecl(); + if (!FD) + return; + + const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); + if (!Att) + return; + + // Iterate through the arguments of CE and check them for null. + unsigned idx = 0; + + for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; + ++I, ++idx) { + + if (!Att->isNonNull(idx)) + continue; + + const SVal &V = state->getSVal(*I); + const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); + + if (!DV) + continue; + + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotNull, *stateNull; + llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); + + 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)) { + + // Lazily allocate the BugType object if it hasn't already been + // created. Ownership is transferred to the BugReporter object once + // the BugReport is passed to 'EmitWarning'. + if (!BT) + BT = new BugType("Argument with 'nonnull' attribute passed null", + "API"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, + "Null pointer passed as an argument to a " + "'nonnull' parameter", errorNode); + + // Highlight the range of the argument that was null. + const Expr *arg = *I; + R->addRange(arg->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg); + + // Emit the bug report. + C.EmitReport(R); + } + + // Always return. Either we cached out or we just emitted an error. + return; + } + + // If a pointer value passed the check we should assume that it is + // indeed not null from this point forward. + assert(stateNotNull); + state = stateNotNull; + } + + // 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)); +} diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp new file mode 100644 index 000000000000..33bb5158d2b9 --- /dev/null +++ b/lib/Analysis/BadCallChecker.cpp @@ -0,0 +1,44 @@ +//===--- 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/Checkers/BadCallChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *BadCallChecker::getTag() { + static int x = 0; + return &x; +} + +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(0, "Invalid function call", + "Called function pointer is a null or undefined pointer value"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetCalleeExpr(N)); + + C.EmitReport(R); + } + } +} diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index aa2d0ab5a763..4781d5ec243e 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -535,4 +535,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); RegisterNSErrorChecks(BR, Eng, D); + RegisterNSAutoreleasePoolChecks(Eng); } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h index 1271ae4ab1c0..ea4d3ecfcaee 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Analysis/BasicObjCFoundationChecks.h @@ -42,6 +42,7 @@ GRSimpleAPICheck *CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR); void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D); +void RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng); } // end clang namespace diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index d81d83c7bfa2..888af9bd57a4 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -92,19 +92,17 @@ public: void iterBindings(Store store, BindingsHandler& f); - const GRState *BindDecl(const GRState *state, const VarDecl *VD, - const LocationContext *LC, SVal InitVal) { - return state->makeWithStore(BindDeclInternal(state->getStore(),VD, LC, + const GRState *BindDecl(const GRState *state, const VarRegion *VR, + SVal InitVal) { + return state->makeWithStore(BindDeclInternal(state->getStore(), VR, &InitVal)); } - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl *VD, - const LocationContext *LC) { - return state->makeWithStore(BindDeclInternal(state->getStore(), VD, LC, 0)); + const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) { + return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0)); } - Store BindDeclInternal(Store store, const VarDecl *VD, - const LocationContext *LC, SVal *InitVal); + Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal); static inline BindingsTy GetBindings(Store store) { return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store)); @@ -532,11 +530,11 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { return St; } -Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, - const LocationContext *LC, +Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, SVal* InitVal) { BasicValueFactory& BasicVals = StateMgr.getBasicVals(); + const VarDecl *VD = VR->getDecl(); // BasicStore does not model arrays and structs. if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) @@ -564,16 +562,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, if (!InitVal) { QualType T = VD->getType(); if (Loc::IsLocType(T)) - store = BindInternal(store, getLoc(VD, LC), + store = BindInternal(store, loc::MemRegionVal(VR), loc::ConcreteInt(BasicVals.getValue(0, T))); else if (T->isIntegerType()) - store = BindInternal(store, getLoc(VD, LC), + store = BindInternal(store, loc::MemRegionVal(VR), nonloc::ConcreteInt(BasicVals.getValue(0, T))); else { // assert(0 && "ignore other types of variables"); } } else { - store = BindInternal(store, getLoc(VD, LC), *InitVal); + store = BindInternal(store, loc::MemRegionVal(VR), *InitVal); } } } else { @@ -581,7 +579,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, QualType T = VD->getType(); if (ValMgr.getSymbolManager().canSymbolicate(T)) { SVal V = InitVal ? *InitVal : UndefinedVal(); - store = BindInternal(store, getLoc(VD, LC), V); + store = BindInternal(store, loc::MemRegionVal(VR), V); } } diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index c629ad1d9612..03614e83398f 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -193,20 +193,6 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// -// Selector creation functions. -//===----------------------------------------------------------------------===// - -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(0, &II); -} - -static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(1, &II); -} - -//===----------------------------------------------------------------------===// // Type querying functions. //===----------------------------------------------------------------------===// @@ -1031,11 +1017,25 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Eventually this can be improved by recognizing that the pixel // buffer passed to CVPixelBufferCreateWithBytes is released via // a callback and doing full IPA to make sure this is done correctly. + // FIXME: This function has an out parameter that returns an + // allocated object. ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; + + case 29: + if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) { + // FIXES: <rdar://problem/7358899> + // Eventually this can be improved by recognizing that 'releaseInfo' + // passed to CGBitmapContextCreateWithData is released via + // a callback and doing full IPA to make sure this is done correctly. + ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking); + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + DoNothing,DoNothing); + } + break; case 32: if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) { @@ -1899,7 +1899,7 @@ public: virtual ~CFRefCount() {} - void RegisterChecks(BugReporter &BR); + void RegisterChecks(GRExprEngine &Eng); virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) { Printers.push_back(new BindingsPrinter()); @@ -2193,7 +2193,9 @@ namespace { }; } // end anonymous namespace -void CFRefCount::RegisterChecks(BugReporter& BR) { +void CFRefCount::RegisterChecks(GRExprEngine& Eng) { + BugReporter &BR = Eng.getBugReporter(); + useAfterRelease = new UseAfterRelease(this); BR.Register(useAfterRelease); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 89c1783cc2f5..cd4697f2f324 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -3,6 +3,8 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis AnalysisContext.cpp AnalysisManager.cpp + AttrNonNullChecker.cpp + BadCallChecker.cpp BasicConstraintManager.cpp BasicObjCFoundationChecks.cpp BasicStore.cpp @@ -14,11 +16,12 @@ add_clang_library(clangAnalysis CallGraph.cpp CallInliner.cpp CheckDeadStores.cpp - CheckNSError.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp + DereferenceChecker.cpp + DivZeroChecker.cpp Environment.cpp ExplodedGraph.cpp GRBlockCounter.cpp @@ -28,6 +31,8 @@ add_clang_library(clangAnalysis GRState.cpp LiveVariables.cpp MemRegion.cpp + NSAutoreleasePoolChecker.cpp + NSErrorChecker.cpp PathDiagnostic.cpp RangeConstraintManager.cpp RegionStore.cpp @@ -37,8 +42,11 @@ add_clang_library(clangAnalysis SimpleSValuator.cpp Store.cpp SymbolManager.cpp + UndefinedArgChecker.cpp + UndefinedAssignmentChecker.cpp UninitializedValues.cpp ValueManager.cpp + VLASizeChecker.cpp ) add_dependencies(clangAnalysis ClangDiagnosticAnalysis) diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index ae8845db63ae..17dc0685f82f 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -68,10 +68,8 @@ CallGraph::~CallGraph() { } } -void CallGraph::addTU(ASTUnit &AST) { - ASTContext &Ctx = AST.getASTContext(); +void CallGraph::addTU(ASTContext& Ctx) { DeclContext *DC = Ctx.getTranslationUnitDecl(); - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 1a900f897678..2d9b53163f6a 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -62,6 +62,29 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { I->second = Used; } +static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { + // Scan the methods for accesses. + for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); I!=E; ++I) + Scan(M, (*I)->getBody()); + + if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) { + // Scan for @synthesized property methods that act as setters/getters + // to an ivar. + for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), + E = ID->propimpl_end(); I!=E; ++I) + Scan(M, *I); + + // Scan the associated categories as well. + for (const ObjCCategoryDecl *CD = + ID->getClassInterface()->getCategoryList(); CD ; + CD = CD->getNextClassCategory()) { + if (const ObjCCategoryImplDecl *CID = CD->getImplementation()) + Scan(M, CID); + } + } +} + void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { @@ -88,16 +111,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (M.empty()) return; - // Now scan the methods for accesses. - for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) - Scan(M, (*I)->getBody()); - - // Scan for @synthesized property methods that act as setters/getters - // to an ivar. - for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(), - E = D->propimpl_end(); I!=E; ++I) - Scan(M, *I); + // Now scan the implementation declaration. + Scan(M, D); // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp new file mode 100644 index 000000000000..33c85d507463 --- /dev/null +++ b/lib/Analysis/DereferenceChecker.cpp @@ -0,0 +1,112 @@ +//== NullDerefChecker.cpp - Null dereference 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 NullDerefChecker, a builtin check in GRExprEngine that performs +// checks for null pointers at loads and stores. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *NullDerefChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred, + const GRState *state, SVal V, + GRExprEngine &Eng) { + Loc *LV = dyn_cast<Loc>(&V); + + // If the value is not a location, don't touch the node. + if (!LV) + return Pred; + + const GRState *NotNullState = state->Assume(*LV, true); + const GRState *NullState = state->Assume(*LV, false); + + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + // The explicit NULL case. + if (NullState) { + // Use the GDM to mark in the state what lval was null. + const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV); + NullState = NullState->set<GRState::NullDerefTag>(PersistentLV); + + ExplodedNode *N = Builder.generateNode(S, NullState, Pred, + ProgramPoint::PostNullCheckFailedKind); + if (N) { + N->markAsSink(); + + if (!NotNullState) { // Explicit null case. + if (!BT) + BT = new BuiltinBug(NULL, "Null dereference", + "Dereference of null pointer"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + + BR.EmitReport(R); + + return 0; + } else // Implicit null case. + ImplicitNullDerefNodes.push_back(N); + } + } + + if (!NotNullState) + return 0; + + return Builder.generateNode(S, NotNullState, Pred, + ProgramPoint::PostLocationChecksSucceedKind); +} + + +void *UndefDerefChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S, + ExplodedNode *Pred, + const GRState *state, SVal V, + GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (V.isUndef()) { + ExplodedNode *N = Builder.generateNode(S, state, Pred, + ProgramPoint::PostUndefLocationCheckFailedKind); + if (N) { + N->markAsSink(); + + if (!BT) + BT = new BuiltinBug(0, "Undefined dereference", + "Dereference of undefined pointer value"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + BR.EmitReport(R); + } + return 0; + } + + return Pred; +} + diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp new file mode 100644 index 000000000000..9c2359f3b075 --- /dev/null +++ b/lib/Analysis/DivZeroChecker.cpp @@ -0,0 +1,70 @@ +//== DivZeroChecker.cpp - Division by zero 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 DivZeroChecker, a builtin check in GRExprEngine that performs +// checks for division by zeros. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" + +using namespace clang; + +void *DivZeroChecker::getTag() { + static int x; + return &x; +} + +void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + BinaryOperator::Opcode Op = B->getOpcode(); + if (Op != BinaryOperator::Div && + Op != BinaryOperator::Rem && + Op != BinaryOperator::DivAssign && + Op != BinaryOperator::RemAssign) + return; + + if (!B->getRHS()->getType()->isIntegerType() || + !B->getRHS()->getType()->isScalarType()) + return; + + SVal Denom = C.getState()->getSVal(B->getRHS()); + const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom); + + // Divide-by-undefined handled in the generic checking for uses of + // undefined values. + if (!DV) + return; + + // Check for divide by zero. + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotZero, *stateZero; + llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); + + if (stateZero && !stateNotZero) { + if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (!BT) + BT = new BuiltinBug(0, "Division by zero"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDenomExpr(N)); + + C.EmitReport(R); + } + return; + } + + // 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)); +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index ea0255ded8a9..c71882e4d888 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/StringSwitch.h" #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" @@ -117,17 +118,18 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - for (std::vector<Checker*>::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst : (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); - Checker *checker = *I; + 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, isPrevisit); + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -137,6 +139,41 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, // automatically. } +// FIXME: This is largely copy-paste from CheckerVisit(). Need to +// unify. +void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, + SVal location, SVal val, bool isPrevisit) { + + if (Checkers.empty()) { + Dst = Src; + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + : (PrevSet == &Tmp) ? &Src : &Tmp; + + CurrSet->clear(); + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_VisitBind(*CurrSet, *Builder, *this, S, *NI, tag, location, + val, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -165,9 +202,8 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr) GRExprEngine::~GRExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; - for (std::vector<Checker*>::iterator I=Checkers.begin(), E=Checkers.end(); - I!=E; ++I) - delete *I; + for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) + delete I->second; } //===----------------------------------------------------------------------===// @@ -177,7 +213,7 @@ GRExprEngine::~GRExprEngine() { void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { StateMgr.TF = tf; - tf->RegisterChecks(getBugReporter()); + tf->RegisterChecks(*this); tf->RegisterPrinters(getStateManager().Printers); } @@ -369,11 +405,11 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S)); } else - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false); break; } @@ -395,7 +431,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false); break; case Stmt::CompoundLiteralExprClass: @@ -409,7 +445,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false); break; @@ -522,7 +557,6 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; @@ -565,6 +599,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + return; + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -1078,8 +1117,7 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, SVal L = state->getLValue(Field, state->getSVal(Base)); if (asLValue) - MakeNode(Dst, M, *I, state->BindExpr(M, L), - ProgramPoint::PostLValueKind); + MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); else EvalLoad(Dst, M, *I, state, L); } @@ -1087,30 +1125,52 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val) { +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, + const GRState* state, SVal location, SVal Val, + bool atDeclInit) { + + + // Do a previsit of the bind. + ExplodedNodeSet CheckedSet, Src; + Src.Add(Pred); + CheckerVisitBind(Ex, CheckedSet, Src, location, Val, true); + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I!=E; ++I) { + + if (Pred != *I) + state = GetState(*I); + + const GRState* newState = 0; - const GRState* newState = 0; + if (atDeclInit) { + const VarRegion *VR = + cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion()); - if (location.isUnknown()) { - // We know that the new state will be the same as the old state since - // the location of the binding is "unknown". Consequently, there - // is no reason to just create a new node. - newState = state; - } - else { - // We are binding to a value other than 'unknown'. Perform the binding - // using the StoreManager. - newState = state->bindLoc(cast<Loc>(location), Val); - } + newState = state->bindDecl(VR, Val); + } + else { + if (location.isUnknown()) { + // We know that the new state will be the same as the old state since + // the location of the binding is "unknown". Consequently, there + // is no reason to just create a new node. + newState = state; + } + else { + // We are binding to a value other than 'unknown'. Perform the binding + // using the StoreManager. + newState = state->bindLoc(cast<Loc>(location), Val); + } + } - // The next thing to do is check if the GRTransferFuncs object wants to - // update the state based on the new binding. If the GRTransferFunc object - // doesn't do anything, just auto-propagate the current state. - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex, - newState != state); + // The next thing to do is check if the GRTransferFuncs object wants to + // update the state based on the new binding. If the GRTransferFunc object + // doesn't do anything, just auto-propagate the current state. + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, Ex, + newState != state); - getTF().EvalBind(BuilderRef, location, Val); + getTF().EvalBind(BuilderRef, location, Val); + } } /// EvalStore - Handle the semantics of a store via an assignment. @@ -1189,58 +1249,18 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, SaveAndRestore<const void*> OldTag(Builder->Tag); Builder->Tag = tag; - // Check for loads/stores from/to undefined values. - if (location.isUndef()) { - ExplodedNode* N = - Builder->generateNode(Ex, state, Pred, - ProgramPoint::PostUndefLocationCheckFailedKind); - - if (N) { - N->markAsSink(); - UndefDeref.insert(N); - } - - return 0; - } - - // Check for loads/stores from/to unknown locations. Treat as No-Ops. - if (location.isUnknown()) + if (location.isUnknown() || Checkers.empty()) return Pred; - // During a load, one of two possible situations arise: - // (1) A crash, because the location (pointer) was NULL. - // (2) The location (pointer) is not NULL, and the dereference works. - // - // We add these assumptions. - - Loc LV = cast<Loc>(location); - - // "Assume" that the pointer is not NULL. - const GRState *StNotNull = state->Assume(LV, true); - - // "Assume" that the pointer is NULL. - const GRState *StNull = state->Assume(LV, false); - - if (StNull) { - // Use the Generic Data Map to mark in the state what lval was null. - const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV); - StNull = StNull->set<GRState::NullDerefTag>(PersistentLV); - - // We don't use "MakeNode" here because the node will be a sink - // and we have no intention of processing it later. - ExplodedNode* NullNode = - Builder->generateNode(Ex, StNull, Pred, - ProgramPoint::PostNullCheckFailedKind); - - if (NullNode) { - NullNode->markAsSink(); - if (StNotNull) ImplicitNullDeref.insert(NullNode); - else ExplicitNullDeref.insert(NullNode); - } + + for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) + { + Pred = I->second->CheckLocation(Ex, Pred, state, location, *this); + if (!Pred) + break; } - - if (!StNotNull) - return NULL; + + return Pred; // FIXME: Temporarily disable out-of-bounds checking until we make // the logic reflect recent changes to CastRegion and friends. @@ -1283,10 +1303,6 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, } } #endif - - // Generate a new node indicating the checks succeed. - return Builder->generateNode(Ex, StNotNull, Pred, - ProgramPoint::PostLocationChecksSucceedKind); } //===----------------------------------------------------------------------===// @@ -1445,75 +1461,30 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - const char* s = FD->getIdentifier()->getNameStart(); - - switch (FD->getIdentifier()->getLength()) { - default: - break; - - case 4: - if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; - break; - - case 5: - if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; - else if (!memcmp(s, "error", 5)) { - if (CE->getNumArgs() > 0) { - SVal X = state->getSVal(*CE->arg_begin()); - // FIXME: use Assume to inspect the possible symbolic value of - // X. Also check the specific signature of error(). - nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X); - if (CI && CI->getValue() != 0) - Builder->BuildSinks = true; - } - } - break; - - case 6: - if (!memcmp(s, "Assert", 6)) { - Builder->BuildSinks = true; - break; - } - - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true; - - break; - - case 7: - if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true; - break; - - case 8: - if (!memcmp(s ,"db_error", 8) || - !memcmp(s, "__assert", 8)) - Builder->BuildSinks = true; - break; - - case 12: - if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true; - break; - - case 13: - if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true; - break; - - case 14: - if (!memcmp(s, "dtrace_assfail", 14) || - !memcmp(s, "yy_fatal_error", 14)) - Builder->BuildSinks = true; - break; - - case 26: - if (!memcmp(s, "_XCAssertionFailureHandler", 26) || - !memcmp(s, "_DTAssertionFailureHandler", 26) || - !memcmp(s, "_TSAssertionFailureHandler", 26)) - Builder->BuildSinks = true; - - break; - } - + using llvm::StringRef; + bool BuildSinks + = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + + if (BuildSinks) + Builder->BuildSinks = true; } } @@ -2042,24 +2013,27 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, } } + // 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; // Dispatch to plug-in transfer function. - unsigned size = Dst.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); - - EvalObjCMessageExpr(Dst, ME, Pred); + + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); + DI!=DE; ++DI) + EvalObjCMessageExpr(Dst, ME, *DI); // 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); } @@ -2141,45 +2115,25 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - unsigned Count = Builder->getCurrentBlockCount(); - - // Check if 'VD' is a VLA and if so check if has a non-zero size. - QualType T = getContext().getCanonicalType(VD->getType()); - if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { - // FIXME: Handle multi-dimensional VLAs. - - Expr* SE = VLA->getSizeExpr(); - SVal Size_untested = state->getSVal(SE); - - if (Size_untested.isUndef()) { - if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) { - N->markAsSink(); - ExplicitBadSizedVLA.insert(N); - } - continue; - } - - DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested); - const GRState *zeroState = state->Assume(Size, false); - state = state->Assume(Size, true); + ExplodedNode *N = *I; + const GRState *state; + + for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end(); + CI != CE; ++CI) { + state = GetState(N); + N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()), + N, state, DS, *this); + if (!N) + break; + } - if (zeroState) { - if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) { - N->markAsSink(); - if (state) - ImplicitBadSizedVLA.insert(N); - else - ExplicitBadSizedVLA.insert(N); - } - } + if (!N) + continue; - if (!state) - continue; - } + state = GetState(N); // Decls without InitExpr are not initialized explicitly. - const LocationContext *LC = (*I)->getLocationContext(); + const LocationContext *LC = N->getLocationContext(); if (InitEx) { SVal InitVal = state->getSVal(InitEx); @@ -2189,20 +2143,15 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // UnknownVal. if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count); + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); } - - state = state->bindDecl(VD, LC, InitVal); - - // The next thing to do is check if the GRTransferFuncs object wants to - // update the state based on the new binding. If the GRTransferFunc - // object doesn't do anything, just auto-propagate the current state. - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true); - getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD, LC)), - InitVal); + + EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)), + InitVal, true); } else { - state = state->bindDeclWithNoInit(VD, LC); + state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); MakeNode(Dst, DS, *I, state); } } @@ -2752,7 +2701,7 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred, void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { ExplodedNodeSet Tmp1; Expr* LHS = B->getLHS()->IgnoreParens(); @@ -2798,10 +2747,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, unsigned Count = Builder->getCurrentBlockCount(); RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } - + + SVal ExprVal = asLValue ? LeftV : RightV; + // 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, RightV), LeftV, RightV); + EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); continue; } @@ -2930,6 +2881,15 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } //===----------------------------------------------------------------------===// +// Checker registration/lookup. +//===----------------------------------------------------------------------===// + +Checker *GRExprEngine::lookupChecker(void *tag) const { + CheckerMap::iterator I = CheckerM.find(tag); + return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; +} + +//===----------------------------------------------------------------------===// // Visualization. //===----------------------------------------------------------------------===// @@ -2941,7 +2901,8 @@ namespace llvm { template<> struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits { - + // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not + // work. static std::string getNodeAttributes(const ExplodedNode* N, void*) { if (GraphPrintCheckerState->isImplicitNullDeref(N) || diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index da24192c9d5a..695f0b02e597 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -15,6 +15,13 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" @@ -40,10 +47,8 @@ ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { //===----------------------------------------------------------------------===// // Bug Descriptions. //===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport { +namespace clang { +class BuiltinBugReport : public RangedBugReport { public: BuiltinBugReport(BugType& bt, const char* desc, ExplodedNode *n) @@ -57,30 +62,10 @@ public: const ExplodedNode* N); }; -class VISIBILITY_HIDDEN BuiltinBug : public BugType { - GRExprEngine &Eng; -protected: - const std::string desc; -public: - BuiltinBug(GRExprEngine *eng, const char* n, const char* d) - : BugType(n, "Logic errors"), Eng(*eng), desc(d) {} - - BuiltinBug(GRExprEngine *eng, const char* n) - : BugType(n, "Logic errors"), 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); -}; - +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) { @@ -88,27 +73,6 @@ void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { GetNode(I))); } -void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) { - static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this); -} - -class VISIBILITY_HIDDEN NullDeref : public BuiltinBug { -public: - NullDeref(GRExprEngine* eng) - : BuiltinBug(eng,"Null dereference", "Dereference of null pointer") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end()); - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); - } -}; - class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug { public: NilReceiverStructRet(GRExprEngine* eng) : @@ -175,34 +139,6 @@ public: } }; -class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug { -public: - UndefinedDeref(GRExprEngine* eng) - : BuiltinBug(eng,"Dereference of undefined pointer value") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end()); - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN DivZero : public BuiltinBug { -public: - DivZero(GRExprEngine* eng = 0) - : BuiltinBug(eng,"Division by zero") {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N); - } -}; - class VISIBILITY_HIDDEN UndefResult : public BuiltinBug { public: UndefResult(GRExprEngine* eng) @@ -279,20 +215,6 @@ public: } }; -class VISIBILITY_HIDDEN BadCall : public BuiltinBug { -public: - BadCall(GRExprEngine *eng = 0) - : BuiltinBug(eng, "Invalid function call", - "Called function pointer is a null or undefined pointer value") {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N); - } -}; - - class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport { const Stmt *Arg; public: @@ -528,276 +450,8 @@ public: } }; -class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug { -public: - BadSizeVLA(GRExprEngine* eng) : - BuiltinBug(eng, "Bad variable-length array (VLA) size") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ErrorNodes::iterator - I = Eng.ExplicitBadSizedVLA.begin(), - E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) { - - // Determine whether this was a 'zero-sized' VLA or a VLA with an - // undefined size. - ExplodedNode* N = *I; - PostStmt PS = cast<PostStmt>(N->getLocation()); - const DeclStmt *DS = cast<DeclStmt>(PS.getStmt()); - VarDecl* VD = cast<VarDecl>(*DS->decl_begin()); - QualType T = Eng.getContext().getCanonicalType(VD->getType()); - VariableArrayType* VT = cast<VariableArrayType>(T); - Expr* SizeExpr = VT->getSizeExpr(); - - std::string buf; - llvm::raw_string_ostream os(buf); - os << "The expression used to specify the number of elements in the " - "variable-length array (VLA) '" - << VD->getNameAsString() << "' evaluates to "; - - bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef(); - - if (isUndefined) - os << "an undefined or garbage value."; - else - os << "0. VLAs with no elements have undefined behavior."; - - std::string shortBuf; - llvm::raw_string_ostream os_short(shortBuf); - os_short << "Variable-length array '" << VD->getNameAsString() << "' " - << (isUndefined ? "garbage value for array size" - : "has zero elements (undefined behavior)"); - - ArgReport *report = new ArgReport(*this, os_short.str().c_str(), - os.str().c_str(), N, SizeExpr); - - report->addRange(SizeExpr->getSourceRange()); - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(), - N); - } -}; - -//===----------------------------------------------------------------------===// -// __attribute__(nonnull) checking - -class VISIBILITY_HIDDEN CheckAttrNonNull : - public CheckerVisitor<CheckAttrNonNull> { - - BugType *BT; - -public: - CheckAttrNonNull() : BT(0) {} - ~CheckAttrNonNull() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void 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()); - - const FunctionDecl* FD = X.getAsFunctionDecl(); - if (!FD) - return; +} // end clang namespace - const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); - if (!Att) - return; - - // Iterate through the arguments of CE and check them for null. - unsigned idx = 0; - - for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; - ++I, ++idx) { - - if (!Att->isNonNull(idx)) - continue; - - const SVal &V = state->getSVal(*I); - const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); - - if (!DV) - continue; - - ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotNull, *stateNull; - llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); - - 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)) { - - // Lazily allocate the BugType object if it hasn't already been - // created. Ownership is transferred to the BugReporter object once - // the BugReport is passed to 'EmitWarning'. - if (!BT) - BT = new BugType("Argument with 'nonnull' attribute passed null", - "API"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, - "Null pointer passed as an argument to a " - "'nonnull' parameter", errorNode); - - // Highlight the range of the argument that was null. - const Expr *arg = *I; - R->addRange(arg->getSourceRange()); - R->addVisitorCreator(registerTrackNullOrUndefValue, arg); - - // Emit the bug report. - C.EmitReport(R); - } - - // Always return. Either we cached out or we just emitted an error. - return; - } - - // If a pointer value passed the check we should assume that it is - // indeed not null from this point forward. - assert(stateNotNull); - state = stateNotNull; - } - - // 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)); - } -}; -} // end anonymous namespace - -// Undefined arguments checking. -namespace { -class VISIBILITY_HIDDEN CheckUndefinedArg - : public CheckerVisitor<CheckUndefinedArg> { - - BadArg *BT; - -public: - CheckUndefinedArg() : BT(0) {} - ~CheckUndefinedArg() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; - -void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *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 *ErrorNode = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BadArg(); - // Generate a report for this bug. - ArgReport *Report = new ArgReport(*BT, BT->getDescription().c_str(), - ErrorNode, *I); - Report->addRange((*I)->getSourceRange()); - C.EmitReport(Report); - } - } - } -} - -class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor<CheckBadCall> { - BadCall *BT; - -public: - CheckBadCall() : BT(0) {} - ~CheckBadCall() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; - -void CheckBadCall::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 BadCall(); - C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); - } - } -} - -class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> { - DivZero *BT; -public: - CheckDivZero() : BT(0) {} - ~CheckDivZero() {} - - const void *getTag() { - static int x; - return &x; - } - - void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); -}; - -void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { - BinaryOperator::Opcode Op = B->getOpcode(); - if (Op != BinaryOperator::Div && - Op != BinaryOperator::Rem && - Op != BinaryOperator::DivAssign && - Op != BinaryOperator::RemAssign) - return; - - if (!B->getRHS()->getType()->isIntegerType() || - !B->getRHS()->getType()->isScalarType()) - return; - - SVal Denom = C.getState()->getSVal(B->getRHS()); - const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom); - - // Divide-by-undefined handled in the generic checking for uses of - // undefined values. - if (!DV) - return; - - // Check for divide by zero. - ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotZero, *stateZero; - llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); - - if (stateZero && !stateNotZero) { - if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { - if (!BT) - BT = new DivZero(); - - C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); - } - return; - } - - // 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)); -} -} //===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -808,8 +462,6 @@ void GRExprEngine::RegisterInternalChecks() { // 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 NullDeref(this)); - BR.Register(new UndefinedDeref(this)); BR.Register(new UndefBranch(this)); BR.Register(new UndefResult(this)); BR.Register(new RetStack(this)); @@ -817,7 +469,6 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new BadMsgExprArg(this)); BR.Register(new BadReceiver(this)); BR.Register(new OutOfBoundMemoryAccess(this)); - BR.Register(new BadSizeVLA(this)); BR.Register(new NilReceiverStructRet(this)); BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); @@ -826,8 +477,13 @@ void GRExprEngine::RegisterInternalChecks() { // their associated BugType will get registered with the BugReporter // automatically. Note that the check itself is owned by the GRExprEngine // object. - registerCheck(new CheckAttrNonNull()); - registerCheck(new CheckUndefinedArg()); - registerCheck(new CheckBadCall()); - registerCheck(new CheckDivZero()); + registerCheck(new AttrNonNullChecker()); + registerCheck(new UndefinedArgChecker()); + registerCheck(new UndefinedAssignmentChecker()); + registerCheck(new BadCallChecker()); + registerCheck(new DivZeroChecker()); + registerCheck(new UndefDerefChecker()); + registerCheck(new NullDerefChecker()); + registerCheck(new UndefSizedVLAChecker()); + registerCheck(new ZeroSizedVLAChecker()); } diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp new file mode 100644 index 000000000000..e0a8d0dc5f73 --- /dev/null +++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp @@ -0,0 +1,84 @@ +//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a NSAutoreleasePoolChecker, a small checker that warns +// about subpar uses of NSAutoreleasePool. Note that while the check itself +// (in it's current form) could be written as a flow-insensitive check, in +// can be potentially enhanced in the future with flow-sensitive information. +// It is also a good example of the CheckerVisitor interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#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 + : public CheckerVisitor<NSAutoreleasePoolChecker> { + + Selector releaseS; + +public: + NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {} + + static void *getTag() { + static int x = 0; + return &x; + } + + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); +}; + +} // end anonymous namespace + + +void clang::RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng) { + ASTContext &Ctx = Eng.getContext(); + if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) { + Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release", + Ctx))); + } +} + +void +NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const Expr *receiver = ME->getReceiver(); + if (!receiver) + return; + + // FIXME: Enhance with value-tracking information instead of consulting + // the type of the expression. + const ObjCObjectPointerType* PT = + receiver->getType()->getAs<ObjCObjectPointerType>(); + const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); + if (!OD) + return; + if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) + return; + + // Sending 'release' message? + if (ME->getSelector() != releaseS) + return; + + SourceRange R = ME->getSourceRange(); + + C.getBugReporter().EmitBasicReport("Use -drain instead of -release", + "API Upgrade (Apple)", + "Use -drain instead of -release when using NSAutoreleasePool " + "and garbage collection", ME->getLocStart(), &R, 1); +} diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/NSErrorChecker.cpp index 8086da588264..307686ff57b3 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/NSErrorChecker.cpp @@ -1,4 +1,4 @@ -//=- CheckNSError.cpp - Coding conventions for uses of NSError ---*- C++ -*-==// +//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -18,6 +18,7 @@ #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #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" @@ -27,7 +28,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN NSErrorCheck : public BugType { +class VISIBILITY_HIDDEN NSErrorChecker : public BugType { const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; @@ -48,7 +49,7 @@ class VISIBILITY_HIDDEN NSErrorCheck : public BugType { void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); public: - NSErrorCheck(const Decl &D, bool isNSError, GRExprEngine& eng) + NSErrorChecker(const Decl &D, bool isNSError, GRExprEngine& eng) : BugType(isNSError ? "NSError** null dereference" : "CFErrorRef* null dereference", "Coding conventions (Apple)"), @@ -64,11 +65,11 @@ public: void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D) { - BR.Register(new NSErrorCheck(D, true, Eng)); - BR.Register(new NSErrorCheck(D, false, Eng)); + BR.Register(new NSErrorChecker(D, true, Eng)); + BR.Register(new NSErrorChecker(D, false, Eng)); } -void NSErrorCheck::FlushReports(BugReporter& BR) { +void NSErrorChecker::FlushReports(BugReporter& BR) { // Get the analysis engine and the exploded analysis graph. ExplodedGraph& G = Eng.getGraph(); @@ -99,7 +100,7 @@ void NSErrorCheck::FlushReports(BugReporter& BR) { } } -void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { +void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { std::string sbuf; llvm::raw_string_ostream os(sbuf); @@ -121,7 +122,7 @@ void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { } void -NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, +NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { ResultTy = M.getResultType(); @@ -140,7 +141,7 @@ NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, } void -NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy, +NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy, llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { ResultTy = F.getResultType(); @@ -159,7 +160,7 @@ NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy, } -bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { +bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) { const PointerType* PPT = ArgTy->getAs<PointerType>(); if (!PPT) @@ -180,7 +181,7 @@ bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { return false; } -bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { +bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) { const PointerType* PPT = ArgTy->getAs<PointerType>(); if (!PPT) return false; @@ -191,7 +192,7 @@ bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { return TT->getDecl()->getIdentifier() == II; } -void NSErrorCheck::CheckParamDeref(const VarDecl *Param, +void NSErrorChecker::CheckParamDeref(const VarDecl *Param, const LocationContext *LC, const GRState *rootState, BugReporter& BR) { @@ -208,8 +209,10 @@ void NSErrorCheck::CheckParamDeref(const VarDecl *Param, return; // Iterate over the implicit-null dereferences. - for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(), - E=Eng.implicit_null_derefs_end(); I!=E; ++I) { + NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>(); + assert(Checker && "NullDerefChecker not exist."); + for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(), + E = Checker->implicit_nodes_end(); I != E; ++I) { const GRState *state = (*I)->getState(); const SVal* X = state->get<GRState::NullDerefTag>(); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 780772a6f129..dbf8c42d273e 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -275,11 +275,11 @@ public: const GRState *BindCompoundLiteral(const GRState *state, const CompoundLiteralExpr* CL, SVal V); - const GRState *BindDecl(const GRState *ST, const VarDecl *VD, - const LocationContext *LC, SVal InitVal); + const GRState *BindDecl(const GRState *ST, const VarRegion *VR, + SVal InitVal); - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*, - const LocationContext *) { + const GRState *BindDeclWithNoInit(const GRState *state, + const VarRegion *) { return state; } @@ -1409,12 +1409,10 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { } const GRState *RegionStoreManager::BindDecl(const GRState *ST, - const VarDecl *VD, - const LocationContext *LC, + const VarRegion *VR, SVal InitVal) { - QualType T = VD->getType(); - VarRegion* VR = MRMgr.getVarRegion(VD, LC); + QualType T = VR->getDecl()->getType(); if (T->isArrayType()) return BindArray(ST, VR, InitVal); @@ -1630,6 +1628,8 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Process the "intermediate" roots to find if they are referenced by // real roots. llvm::SmallVector<RBDNode, 10> WorkList; + llvm::SmallVector<RBDNode, 10> Postponed; + llvm::DenseSet<const MemRegion*> IntermediateVisited; while (!IntermediateRoots.empty()) { @@ -1647,8 +1647,11 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, } if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) { - if (SymReaper.isLive(SR->getSymbol())) - WorkList.push_back(std::make_pair(&state, SR)); + llvm::SmallVectorImpl<RBDNode> &Q = + SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed; + + Q.push_back(std::make_pair(&state, SR)); + continue; } @@ -1667,6 +1670,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, llvm::DenseSet<RBDNode> Visited; +tryAgain: while (!WorkList.empty()) { RBDNode N = WorkList.back(); WorkList.pop_back(); @@ -1740,6 +1744,21 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, } } + // See if any postponed SymbolicRegions are actually live now, after + // having done a scan. + for (llvm::SmallVectorImpl<RBDNode>::iterator I = Postponed.begin(), + E = Postponed.end() ; I != E ; ++I) { + if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(I->second)) { + if (SymReaper.isLive(SR->getSymbol())) { + WorkList.push_back(*I); + I->second = NULL; + } + } + } + + if (!WorkList.empty()) + goto tryAgain; + // We have now scanned the store, marking reachable regions and symbols // as live. We now remove all the regions that are dead from the store // as well as update DSymbols with the set symbols that are now dead. diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp new file mode 100644 index 000000000000..a229f55ff6d9 --- /dev/null +++ b/lib/Analysis/UndefinedArgChecker.cpp @@ -0,0 +1,43 @@ +//===--- UndefinedArgChecker.h - Undefined arguments 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 undefined arguments. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefinedArgChecker::getTag() { + static int x = 0; + return &x; +} + +void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, + const CallExpr *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.GenerateNode(CE, true)) { + if (!BT) + BT = new BugType("Pass-by-value argument in function call is " + "undefined", "Logic error"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), + N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + } + } + } +} diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp new file mode 100644 index 000000000000..c5b2401f47ce --- /dev/null +++ b/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -0,0 +1,61 @@ +//===--- 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. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefinedAssignmentChecker::getTag() { + static int x = 0; + return &x; +} + +void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, + const Stmt *S, + SVal location, + SVal val) { + if (!val.isUndef()) + return; + + ExplodedNode *N = C.GenerateNode(S, true); + + if (!N) + return; + + if (!BT) + BT = new BugType("Assigned value is garbage or undefined", + "Logic error"); + + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N); + const Expr *ex = 0; + + // FIXME: This check needs to be done on the expression doing the + // assignment, not the "store" expression. + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) + ex = B->getRHS(); + else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + ex = VD->getInit(); + } + + if (ex) { + R->addRange(ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + } + + C.EmitReport(R); +} + diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp new file mode 100644 index 000000000000..76e4477449ed --- /dev/null +++ b/lib/Analysis/VLASizeChecker.cpp @@ -0,0 +1,102 @@ +//=== VLASizeChecker.cpp - Undefined dereference 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 two VLASizeCheckers, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of undefined or zero size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefSizedVLAChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, + Stmt *S, GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + if (Size_untested.isUndef()) { + if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of undefined " + "size", "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + return 0; + } + } + return Pred; +} + +void *ZeroSizedVLAChecker::getTag() { + static int x; + return &x; +} + +ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, + GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested); + // Undefined size is checked in another checker. + if (!Size) + return Pred; + + const GRState *zeroState = state->Assume(*Size, false); + state = state->Assume(*Size, true); + + if (zeroState && !state) { + if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of zero size", + "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + } + if (!state) + return 0; + + return Builder.generateNode(S, state, Pred); + } + else + return Pred; +} + diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 527ebf965934..1a89acc65af3 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -18,7 +18,7 @@ add_clang_library(clangBasic # FIXME: This only gets updated when CMake is run, so this revision number # may be out-of-date! find_package(Subversion) -if (Subversion_FOUND) +if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn") Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG) set_source_files_properties(Version.cpp PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"") diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 16aa0c54846a..401e6cba0692 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -381,3 +381,17 @@ SelectorTable::~SelectorTable() { delete &getSelectorTableImpl(Impl); } +const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { + switch (Operator) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + return 0; + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: return Spelling; +#include "clang/Basic/OperatorKinds.def" + } + + return 0; +} + diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 8f3c777c2004..12caf0c8e512 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -106,9 +106,9 @@ unsigned TargetInfo::getTypeWidth(IntType T) const { }; } -/// getTypeSigned - Return whether an integer types is signed. Returns true if +/// isTypeSigned - Return whether an integer types is signed. Returns true if /// the type is signed; false otherwise. -bool TargetInfo::getTypeSigned(IntType T) const { +bool TargetInfo::isTypeSigned(IntType T) const { switch (T) { default: assert(0 && "not an integer!"); case SignedShort: diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 66d6824b6f29..f418c5a81c12 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -1533,6 +1533,8 @@ namespace { Define(Defines, "ram", "__attribute__((address_space(0)))"); Define(Defines, "_section(SectName)", "__attribute__((section(SectName)))"); + Define(Defines, "near", + "__attribute__((section(\"Address=NEAR\")))"); Define(Defines, "_address(Addr)", "__attribute__((section(\"Address=\"#Addr)))"); Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 987cd24e2c8b..c26921969a88 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -199,6 +199,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { + // FIXME: We're awaiting the llvm intrincis. +#if 0 + // We pass this builtin onto the optimizer so that it can + // figure out the object size in more complex cases. + const llvm::Type *ResType[] = { + ConvertType(E->getType()) + }; + Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1); + return RValue::get(Builder.CreateCall2(F, + EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1)))); +#else // FIXME: Implement. For now we just always fail and pretend we // don't know the object size. llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext()); @@ -207,6 +219,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, bool UseMinimum = TypeArg.getZExtValue() & 2; return RValue::get( llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); +#endif } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index cfa669dc4b6e..3e854ca279b6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -71,16 +71,17 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, const Expr *Init = D.getInit(); QualType T = D.getType(); + bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified(); if (T->isReferenceType()) { ErrorUnsupported(Init, "global variable that binds to a reference"); } else if (!hasAggregateLLVMType(T)) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T); + EmitStoreOfScalar(V, DeclPtr, isVolatile, T); } else if (T->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified()); + EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { - EmitAggExpr(Init, DeclPtr, T.isVolatileQualified()); + EmitAggExpr(Init, DeclPtr, isVolatile); if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -95,8 +96,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() { if (CXXGlobalInits.empty()) return; - const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - false); + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); // Create our global initialization function. // FIXME: Should this be tweakable by targets? @@ -139,18 +141,20 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, // Create the guard variable. llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), false, - GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + false, GV->getLinkage(), + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), GuardVName.str()); // Load the first byte of the guard variable. - const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + const llvm::Type *PtrTy + = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), "tmp"); // Compare it against 0. - llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); + llvm::Value *nullValue + = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); llvm::BasicBlock *InitBlock = createBasicBlock("init"); @@ -163,7 +167,8 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, EmitCXXGlobalVarDeclInit(D, GV); - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1), + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), + 1), Builder.CreateBitCast(GuardV, PtrTy)); EmitBlock(EndBlock); @@ -591,11 +596,16 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); const CXXConstructorDecl *CD = E->getConstructor(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(E->getType()); // For a copy constructor, even if it is trivial, must fall thru so // its argument is code-gen'ed. if (!CD->isCopyConstructor(getContext())) { + QualType InitType = E->getType(); + if (Array) + InitType = getContext().getBaseElementType(Array); const CXXRecordDecl *RD = - cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl()); if (RD->hasTrivialConstructor()) return; } @@ -606,9 +616,18 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, EmitAggExpr((*i), Dest, false); return; } - // Call the constructor. - EmitCXXConstructorCall(CD, Ctor_Complete, Dest, - E->arg_begin(), E->arg_end()); + if (Array) { + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(Dest, BasePtr); + EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr); + } + else + // Call the constructor. + EmitCXXConstructorCall(CD, Ctor_Complete, Dest, + E->arg_begin(), E->arg_end()); } void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { @@ -688,32 +707,39 @@ llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, int64_t nv, int64_t v) { - QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0); +} - FunctionArgList Args; - ImplicitParamDecl *ThisDecl = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, - MD->getThisType(getContext())); - Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); - for (FunctionDecl::param_const_iterator i = MD->param_begin(), - e = MD->param_end(); - i != e; ++i) { - ParmVarDecl *D = *i; - Args.push_back(std::make_pair(D, D->getType())); +llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv, + int64_t v) { + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + const llvm::Type *OrigTy = V->getType(); + if (nv) { + // Do the non-virtual adjustment + V = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateConstInBoundsGEP1_64(V, nv); + V = Builder.CreateBitCast(V, OrigTy); } - IdentifierInfo *II - = &CGM.getContext().Idents.get("__thunk_named_foo_"); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, 0, - Extern - ? FunctionDecl::Extern - : FunctionDecl::Static, - false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - // FIXME: generate body - FinishFunction(); - return Fn; + if (v) { + // Do the virtual this adjustment + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy; + PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); + PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0); + llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + llvm::Value *VTablePtr = V; + assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned"); + v /= LLVMPointerWidth/8; + V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v); + V = Builder.CreateLoad(V); + V = Builder.CreateGEP(ThisVal, V); + V = Builder.CreateBitCast(V, OrigTy); + } + return V; } llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, @@ -723,7 +749,7 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, int64_t v_t, int64_t nv_r, int64_t v_r) { - QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); FunctionArgList Args; ImplicitParamDecl *ThisDecl = @@ -740,13 +766,57 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, = &CGM.getContext().Idents.get("__thunk_named_foo_"); FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, 0, + SourceLocation(), II, ResultType, 0, Extern ? FunctionDecl::Extern : FunctionDecl::Static, false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - // FIXME: generate body + StartFunction(FD, ResultType, Fn, Args, SourceLocation()); + + // generate body + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); + CallArgList CallArgs; + + QualType ArgType = MD->getThisType(getContext()); + llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this"); + if (nv_t || v_t) { + // Do the this adjustment. + const llvm::Type *OrigTy = Callee->getType(); + Arg = DynamicTypeAdjust(Arg, nv_t, v_t); + if (nv_r || v_r) { + Callee = CGM.BuildCovariantThunk(MD, Extern, 0, 0, nv_r, v_r); + Callee = Builder.CreateBitCast(Callee, OrigTy); + nv_r = v_r = 0; + } + } + + CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType)); + + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + QualType ArgType = D->getType(); + + // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); + Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation()); + CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); + } + + RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); + if (nv_r || v_r) { + // Do the return result adjustment. + RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); + } + + if (!ResultType->isVoidType()) + EmitReturnOfRValue(RV, ResultType); + FinishFunction(); return Fn; } @@ -769,7 +839,6 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), &getModule()); CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); - // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } @@ -795,7 +864,6 @@ llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, &getModule()); CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r, v_r); - // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } @@ -815,7 +883,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = - Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); @@ -899,7 +967,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); + BaseCopyCtor->getParamDecl(0)->getType())); QualType ResultType = BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), @@ -1099,11 +1167,11 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, FinishFunction(); } -/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a copy -/// constructor, in accordance with section 12.8 (p7 and p8) of C++03 +/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a +/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 /// The implicitly-defined copy constructor for class X performs a memberwise -/// copy of its subobjects. The order of copying is the same as the order -/// of initialization of bases and members in a user-defined constructor +/// copy of its subobjects. The order of copying is the same as the order of +/// initialization of bases and members in a user-defined constructor /// Each subobject is copied in the manner appropriate to its type: /// if the subobject is of class type, the copy constructor for the class is /// used; @@ -1121,7 +1189,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, const FunctionArgList &Args) { const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + "SynthesizeCXXCopyConstructor - copy constructor has definition already"); StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, SourceLocation()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 78655168e857..06cd05cc75a8 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -441,6 +441,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, RetAttrs |= llvm::Attribute::NoAlias; } + if (CompileOpts.OptimizeSize) + FuncAttrs |= llvm::Attribute::OptimizeForSize; if (CompileOpts.DisableRedZone) FuncAttrs |= llvm::Attribute::NoRedZone; if (CompileOpts.NoImplicitFloat) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 1728c67292b7..b1ceb4627712 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/CompileOptions.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Target/TargetData.h" @@ -316,6 +317,20 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { + + // All constant structs and arrays should be global if + // their initializer is constant and if the element type is POD. + if (CGM.getCompileOpts().MergeAllConstants) { + if (Ty.isConstant(getContext()) + && (Ty->isArrayType() || Ty->isRecordType()) + && (D.getInit() + && D.getInit()->isConstantInitializer(getContext())) + && Ty->isPODType()) { + EmitStaticBlockVarDecl(D); + return; + } + } + // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); Align = getContext().getDeclAlignInBytes(&D); @@ -417,17 +432,18 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); + bool isVolatile = (getContext().getCanonicalType(D.getType()) + .isVolatileQualified()); if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(), - D.getType()); + EmitStoreOfScalar(V, Loc, isVolatile, D.getType()); } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified()); + EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { - EmitAggExpr(Init, Loc, D.getType().isVolatileQualified()); + EmitAggExpr(Init, Loc, isVolatile); } } @@ -492,16 +508,25 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Handle CXX destruction of variables. QualType DtorTy(Ty); if (const ArrayType *Array = DtorTy->getAs<ArrayType>()) - DtorTy = Array->getElementType(); + DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs<RecordType>()) if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!ClassDecl->hasTrivialDestructor()) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); - assert(!Ty->getAs<ArrayType>() && "FIXME - destruction of arrays NYI"); - + CleanupScope scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + if (const ConstantArrayType *Array = + getContext().getAsConstantArrayType(Ty)) { + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); } } @@ -547,6 +572,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) && "Invalid argument to EmitParmDecl"); QualType Ty = D.getType(); + CanQualType CTy = getContext().getCanonicalType(Ty); llvm::Value *DeclPtr; if (!Ty->isConstantSizeType()) { @@ -563,7 +589,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { DeclPtr->setName(Name.c_str()); // Store the initial value into the alloca. - EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(), Ty); + EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); } else { // Otherwise, if this is an aggregate, just use the input pointer. DeclPtr = Arg; diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp new file mode 100644 index 000000000000..adfd0055f936 --- /dev/null +++ b/lib/CodeGen/CGException.cpp @@ -0,0 +1,105 @@ +//===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ exception related code generation. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { + // void *__cxa_allocate_exception(size_t thrown_size); + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + std::vector<const llvm::Type*> Args(1, SizeTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); +} + +static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { + // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *) ); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(3, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); +} + +void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { + // FIXME: Handle rethrows. + if (!E->getSubExpr()) { + ErrorUnsupported(E, "rethrow expression"); + return; + } + + QualType ThrowType = E->getSubExpr()->getType(); + // FIXME: We only handle non-class types for now. + if (ThrowType->isRecordType()) { + ErrorUnsupported(E, "throw expression"); + return; + } + + // FIXME: Handle cleanup. + if (!CleanupEntries.empty()){ + ErrorUnsupported(E, "throw expression"); + return; + } + + // Now allocate the exception object. + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; + + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); + llvm::Value *ExceptionPtr = + Builder.CreateCall(AllocExceptionFn, + llvm::ConstantInt::get(SizeTy, TypeSize), + "exception"); + + // Store the throw exception in the exception object. + if (!hasAggregateLLVMType(ThrowType)) { + llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); + } else { + // FIXME: Handle complex and aggregate expressions. + ErrorUnsupported(E, "throw expression"); + } + + // Now throw the exception. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out); + + // FIXME: Is it OK to use CreateRuntimeVariable for this? + llvm::Constant *TypeInfo = + CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()), + OutName.c_str()); + llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); + + llvm::CallInst *ThrowCall = + Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); +} diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index bb487f6e3fdf..d9dd70ac9e49 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -84,10 +84,9 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); - if (ShouldDestroyTemporaries) { - // Keep track of the current cleanup stack depth. + // Keep track of the current cleanup stack depth. + if (ShouldDestroyTemporaries) OldNumLiveTemporaries = LiveTemporaries.size(); - } E = TE->getSubExpr(); } @@ -148,7 +147,6 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, // Check if need to perform the derived-to-base cast. if (BaseClassDecl) { llvm::Value *Derived = Val.getAggregateAddr(); - llvm::Value *Base = GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, /*NullCheckValue=*/false); @@ -189,18 +187,21 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, //===----------------------------------------------------------------------===// RValue CodeGenFunction::GetUndefRValue(QualType Ty) { - if (Ty->isVoidType()) { + if (Ty->isVoidType()) return RValue::get(0); - } else if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { + + if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { const llvm::Type *EltTy = ConvertType(CTy->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return RValue::getComplex(std::make_pair(U, U)); - } else if (hasAggregateLLVMType(Ty)) { + } + + if (hasAggregateLLVMType(Ty)) { const llvm::Type *LTy = llvm::PointerType::getUnqual(ConvertType(Ty)); return RValue::getAggregate(llvm::UndefValue::get(LTy)); - } else { - return RValue::get(llvm::UndefValue::get(ConvertType(Ty))); } + + return RValue::get(llvm::UndefValue::get(ConvertType(Ty))); } RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E, @@ -245,7 +246,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast<VAArgExpr>(E)); case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E)); case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); case Expr::PredefinedExprClass: @@ -343,9 +343,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { if (LV.isObjCWeak()) { // load of a __weak object. llvm::Value *AddrWeakObj = LV.getAddress(); - llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this, - AddrWeakObj); - return RValue::get(read_weak); + return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this, + AddrWeakObj)); } if (LV.isSimple()) { @@ -522,10 +521,8 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, if (Dst.isPropertyRef()) return EmitStoreThroughPropertyRefLValue(Src, Dst, Ty); - if (Dst.isKVCRef()) - return EmitStoreThroughKVCRefLValue(Src, Dst, Ty); - - assert(0 && "Unknown LValue type"); + assert(Dst.isKVCRef() && "Unknown LValue type"); + return EmitStoreThroughKVCRefLValue(Src, Dst, Ty); } if (Dst.isObjCWeak() && !Dst.isNonGC()) { @@ -551,8 +548,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, BytesBetween); - } - else if (Dst.isGlobalObjCRef()) + } else if (Dst.isGlobalObjCRef()) CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); else CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst); @@ -702,13 +698,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // FIXME: since we're shuffling with undef, can we just use the indices // into that? This could be simpler. llvm::SmallVector<llvm::Constant*, 4> ExtMask; + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); unsigned i; for (i = 0; i != NumSrcElts; ++i) - ExtMask.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i)); + ExtMask.push_back(llvm::ConstantInt::get(Int32Ty, i)); for (; i != NumDstElts; ++i) - ExtMask.push_back(llvm::UndefValue::get( - llvm::Type::getInt32Ty(VMContext))); + ExtMask.push_back(llvm::UndefValue::get(Int32Ty)); llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0], ExtMask.size()); llvm::Value *ExtSrcVal = @@ -717,15 +712,13 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, ExtMaskV, "tmp"); // build identity llvm::SmallVector<llvm::Constant*, 4> Mask; - for (unsigned i = 0; i != NumDstElts; ++i) { - Mask.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i)); - } + for (unsigned i = 0; i != NumDstElts; ++i) + Mask.push_back(llvm::ConstantInt::get(Int32Ty, i)); + // modify when what gets shuffled in for (unsigned i = 0; i != NumSrcElts; ++i) { unsigned Idx = getAccessedFieldNo(i, Elts); - Mask[Idx] = llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i+NumDstElts); + Mask[Idx] = llvm::ConstantInt::get(Int32Ty, i+NumDstElts); } llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp"); @@ -736,8 +729,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, } else { // If the Src is a scalar (not a vector) it must be updating one element. unsigned InIdx = getAccessedFieldNo(0, Elts); - llvm::Value *Elt = llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), InIdx); + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); + llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx); Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); } @@ -747,8 +740,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // setObjCGCLValueClass - sets class of he lvalue for the purpose of // generating write-barries API. It is currently a global, ivar, // or neither. -static -void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { +static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, + LValue &LV) { if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC) return; @@ -759,6 +752,7 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { LV.SetObjCArray(LV, E->getType()->isArrayType()); return; } + if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) { if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) { if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) || @@ -766,10 +760,15 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { LV.SetGlobalObjCRef(LV, true); } LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; } - else if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) + + if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) { + return; + } + + if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); if (LV.isObjCIvar()) { // If cast is to a structure pointer, follow gcc's behavior and make it @@ -779,13 +778,20 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { ExpTy = ExpTy->getAs<PointerType>()->getPointeeType(); if (ExpTy->isRecordType()) LV.SetObjCIvar(LV, false); - } + } + return; } - else if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) + if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) + return; + } + + if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) { + return; + } + + if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getBase(), LV); if (LV.isObjCIvar() && !LV.isObjCArray()) // Using array syntax to assigning to what an ivar points to is not @@ -795,12 +801,15 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { // Using array syntax to assigning to what global points to is not // same as assigning to the global itself. {id *G;} G[i] = 0; LV.SetGlobalObjCRef(LV, false); + return; } - else if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) { + + if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getBase(), LV); // We don't know if member is an 'ivar', but this flag is looked at // only in the context of LV.isObjCIvar(). LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; } } @@ -839,14 +848,18 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { LValue::SetObjCNonGC(LV, NonGCable); setObjCGCLValueClass(getContext(), E, LV); return LV; - } else if (VD && VD->isFileVarDecl()) { + } + + if (VD && VD->isFileVarDecl()) { llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); setObjCGCLValueClass(getContext(), E, LV); return LV; - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) { + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) { llvm::Value* V = CGM.GetAddrOfFunction(FD); if (!FD->hasPrototype()) { if (const FunctionProtoType *Proto = @@ -861,15 +874,19 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } } return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } else if (const ImplicitParamDecl *IPD = - dyn_cast<ImplicitParamDecl>(E->getDecl())) { + } + + if (const ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(E->getDecl())){ llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } else if (const QualifiedDeclRefExpr *QDRExpr = - dyn_cast<QualifiedDeclRefExpr>(E)) { - return EmitPointerToDataMemberLValue(QDRExpr); } + + if (E->getQualifier()) { + // FIXME: the qualifier check does not seem sufficient here + return EmitPointerToDataMemberLValue(E); + } + assert(0 && "Unimp declref"); //an invalid LValue, but the assert will //ensure that this point is never reached. @@ -888,25 +905,24 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType()); switch (E->getOpcode()) { default: assert(0 && "Unknown unary operator lvalue!"); - case UnaryOperator::Deref: - { - QualType T = E->getSubExpr()->getType()->getPointeeType(); - assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); - - Qualifiers Quals = MakeQualifiers(T); - Quals.setAddressSpace(ExprTy.getAddressSpace()); - - LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); - // We should not generate __weak write barrier on indirect reference - // of a pointer to object; as in void foo (__weak id *param); *param = 0; - // But, we continue to generate __strong write barrier on indirect write - // into a pointer to object. - if (getContext().getLangOptions().ObjC1 && - getContext().getLangOptions().getGCMode() != LangOptions::NonGC && - LV.isObjCWeak()) - LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); - return LV; - } + case UnaryOperator::Deref: { + QualType T = E->getSubExpr()->getType()->getPointeeType(); + assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); + + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(ExprTy.getAddressSpace()); + + LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); + // We should not generate __weak write barrier on indirect reference + // of a pointer to object; as in void foo (__weak id *param); *param = 0; + // But, we continue to generate __strong write barrier on indirect write + // into a pointer to object. + if (getContext().getLangOptions().ObjC1 && + getContext().getLangOptions().getGCMode() != LangOptions::NonGC && + LV.isObjCWeak()) + LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); + return LV; + } case UnaryOperator::Real: case UnaryOperator::Imag: LValue LV = EmitLValue(E->getSubExpr()); @@ -932,8 +948,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { std::string GlobalVarName; switch (Type) { - default: - assert(0 && "Invalid type"); + default: assert(0 && "Invalid type"); case PredefinedExpr::Func: GlobalVarName = "__func__."; break; @@ -1089,12 +1104,12 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Constant *BaseElts = Base.getExtVectorElts(); llvm::SmallVector<llvm::Constant *, 4> CElts; + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); for (unsigned i = 0, e = Indices.size(); i != e; ++i) { if (isa<llvm::ConstantAggregateZero>(BaseElts)) - CElts.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 0)); + CElts.push_back(llvm::ConstantInt::get(Int32Ty, 0)); else - CElts.push_back(BaseElts->getOperand(Indices[i])); + CElts.push_back(cast<llvm::Constant>(BaseElts->getOperand(Indices[i]))); } llvm::Constant *CV = llvm::ConstantVector::get(&CElts[0], CElts.size()); return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, @@ -1211,13 +1226,12 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); - if (E->getType()->isComplexType()) { + if (E->getType()->isComplexType()) EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); - } else if (hasAggregateLLVMType(E->getType())) { + else if (hasAggregateLLVMType(E->getType())) EmitAnyExpr(InitExpr, DeclPtr, false); - } else { + else EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType()); - } return Result; } @@ -1238,9 +1252,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { if (!LHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); - llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(), - "condtmp"); - + llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp"); Builder.CreateStore(LHS.getAddress(), Temp); EmitBranch(ContBlock); @@ -1379,7 +1391,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return EmitLValue(E->getRHS()); } - if (E->getOpcode() == BinaryOperator::PtrMemD) + if (E->getOpcode() == BinaryOperator::PtrMemD || + E->getOpcode() == BinaryOperator::PtrMemI) return EmitPointerToDataMemberBinaryExpr(E); // Can only get l-value for binary operator expressions which are a @@ -1406,15 +1419,14 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { RValue RV = EmitCallExpr(E); - if (RV.isScalar()) { - assert(E->getCallReturnType()->isReferenceType() && - "Can't have a scalar return unless the return type is a " - "reference type!"); - - return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); - } + if (!RV.isScalar()) + return LValue::MakeAddr(RV.getAggregateAddr(),MakeQualifiers(E->getType())); + + assert(E->getCallReturnType()->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); - return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); + return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { @@ -1439,9 +1451,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); - PushCXXTemporary(E->getTemporary(), LV.getAddress()); - return LV; } @@ -1497,21 +1507,18 @@ CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) { return LValue::MakePropertyRef(E, E->getType().getCVRQualifiers()); } -LValue -CodeGenFunction::EmitObjCKVCRefLValue( +LValue CodeGenFunction::EmitObjCKVCRefLValue( const ObjCImplicitSetterGetterRefExpr *E) { // This is a special l-value that just issues sends when we load or store // through it. return LValue::MakeKVCRef(E, E->getType().getCVRQualifiers()); } -LValue -CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { +LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { return EmitUnsupportedLValue(E, "use of super"); } LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { - // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); // FIXME: can this be volatile? @@ -1519,8 +1526,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { } -LValue CodeGenFunction::EmitPointerToDataMemberLValue( - const QualifiedDeclRefExpr *E) { +LValue CodeGenFunction::EmitPointerToDataMemberLValue(const DeclRefExpr *E) { const FieldDecl *Field = cast<FieldDecl>(E->getDecl()); const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext()); QualType NNSpecTy = @@ -1530,12 +1536,9 @@ LValue CodeGenFunction::EmitPointerToDataMemberLValue( llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy)); LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field), /*isUnion*/false, /*Qualifiers*/0); - const llvm::Type* ResultType = ConvertType( - getContext().getPointerDiffType()); - V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, - "datamember"); - LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); - return LV; + const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType()); + V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember"); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, @@ -1566,9 +1569,11 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, Callee, Args, TargetDecl); } -LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( - const BinaryOperator *E) { +LValue CodeGenFunction:: +EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress(); + if (E->getOpcode() == BinaryOperator::PtrMemI) + BaseV = Builder.CreateLoad(BaseV, "indir.ptr"); const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); BaseV = Builder.CreateBitCast(BaseV, i8Ty); LValue RHSLV = EmitLValue(E->getRHS()); @@ -1577,13 +1582,12 @@ LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType()); OffsetV = Builder.CreateBitCast(OffsetV, ResultType); llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); + QualType Ty = E->getRHS()->getType(); - const MemberPointerType *MemPtrType = Ty->getAs<MemberPointerType>(); - Ty = MemPtrType->getPointeeType(); - const llvm::Type* PType = - ConvertType(getContext().getPointerType(Ty)); + Ty = Ty->getAs<MemberPointerType>()->getPointeeType(); + + const llvm::Type *PType = ConvertType(getContext().getPointerType(Ty)); AddV = Builder.CreateBitCast(AddV, PType); - LValue LV = LValue::MakeAddr(AddV, MakeQualifiers(Ty)); - return LV; + return LValue::MakeAddr(AddV, MakeQualifiers(Ty)); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f47b6ab3c8cc..901f867a5913 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -297,7 +297,7 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); - const QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr()); + const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); const llvm::Type *PtrDiffTy = @@ -329,7 +329,8 @@ void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BinaryOperator::PtrMemD) + if (E->getOpcode() == BinaryOperator::PtrMemD || + E->getOpcode() == BinaryOperator::PtrMemI) VisitPointerToDataMemberBinaryOperator(E); else CGF.ErrorUnsupported(E, "aggregate binary expression"); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index fc3748c8e3c8..9145d92128a1 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -228,7 +228,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder { if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); - llvm::Constant *C = llvm::Constant::getNullValue(Ty); + llvm::Constant *C = llvm::UndefValue::get(Ty); Elements.push_back(C); assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); @@ -266,7 +266,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder { if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); - llvm::Constant *Padding = llvm::Constant::getNullValue(Ty); + llvm::Constant *Padding = llvm::UndefValue::get(Ty); PackedElements.push_back(Padding); ElementOffsetInBytes += getSizeInBytes(Padding); } @@ -434,7 +434,7 @@ public: E->getType()->getAs<MemberPointerType>()) { QualType T = MPT->getPointeeType(); if (T->isFunctionProtoType()) { - QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr()); + DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl())); } @@ -496,7 +496,7 @@ public: if (NumPadBytes > 1) Ty = llvm::ArrayType::get(Ty, NumPadBytes); - Elts.push_back(llvm::Constant::getNullValue(Ty)); + Elts.push_back(llvm::UndefValue::get(Ty)); Types.push_back(Ty); } @@ -739,8 +739,7 @@ public: E->getType().getAddressSpace()); return C; } - case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: { + case Expr::DeclRefExprClass: { NamedDecl *Decl = cast<DeclRefExpr>(E)->getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl)) return CGM.GetAddrOfFunction(FD); @@ -777,11 +776,17 @@ public: } case Expr::AddrLabelExprClass: { assert(CGF && "Invalid address of label expression outside function."); +#ifndef USEINDIRECTBRANCH unsigned id = CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); llvm::Constant *C = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id); return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType())); +#else + llvm::Constant *Ptr = + CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); + return llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType())); +#endif } case Expr::CallExprClass: { CallExpr* CE = cast<CallExpr>(E); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 69604f9aaaee..96b58d8995ae 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -135,11 +135,16 @@ public: } Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { +#ifndef USEINDIRECTBRANCH llvm::Value *V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), CGF.GetIDForAddrOfLabel(E->getLabel())); return Builder.CreateIntToPtr(V, ConvertType(E->getType())); +#else + llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); + return Builder.CreateBitCast(V, ConvertType(E->getType())); +#endif } // l-values. @@ -272,7 +277,12 @@ public: Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } - + + Value *VisitCXXThrowExpr(const CXXThrowExpr *E) { + CGF.EmitCXXThrowExpr(E); + return 0; + } + // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (CGF.getContext().getLangOptions().OverflowChecking @@ -678,14 +688,13 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's // input is the same width as the vector being constructed, generate an // optimized shuffle of the swizzle input into the result. + unsigned Offset = (CurIdx == 0) ? 0 : ResElts; if (isa<ExtVectorElementExpr>(IE)) { llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init); Value *SVOp = SVI->getOperand(0); const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); if (OpTy->getNumElements() == ResElts) { - unsigned Offset = (CurIdx == 0) ? 0 : ResElts; - for (unsigned j = 0; j != CurIdx; ++j) { // If the current vector initializer is a shuffle with undef, merge // this shuffle directly into it. @@ -717,13 +726,13 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { Args.push_back(llvm::UndefValue::get(I32Ty)); llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT), - Mask, "vecext"); + Mask, "vext"); Args.clear(); for (unsigned j = 0; j != CurIdx; ++j) Args.push_back(llvm::ConstantInt::get(I32Ty, j)); for (unsigned j = 0; j != InitElts; ++j) - Args.push_back(llvm::ConstantInt::get(I32Ty, j+ResElts)); + Args.push_back(llvm::ConstantInt::get(I32Ty, j+Offset)); for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) Args.push_back(llvm::UndefValue::get(I32Ty)); } @@ -1639,9 +1648,10 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { /// expression is cheap enough and side-effect-free enough to evaluate /// unconditionally instead of conditionally. This is used to convert control /// flow into selects in some cases. -static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) { +static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, + CodeGenFunction &CGF) { if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) - return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr()); + return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF); // TODO: Allow anything we can constant fold to an integer or fp constant. if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) || @@ -1652,7 +1662,9 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) { // X and Y are local variables. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) - if (VD->hasLocalStorage() && !VD->getType().isVolatileQualified()) + if (VD->hasLocalStorage() && !(CGF.getContext() + .getCanonicalType(VD->getType()) + .isVolatileQualified())) return true; return false; @@ -1681,8 +1693,9 @@ VisitConditionalOperator(const ConditionalOperator *E) { // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. - if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS()) && - isCheapEnoughToEvaluateUnconditionally(E->getRHS())) { + if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS(), + CGF) && + isCheapEnoughToEvaluateUnconditionally(E->getRHS(), CGF)) { llvm::Value *CondV = CGF.EvaluateExprAsBool(E->getCond()); llvm::Value *LHS = Visit(E->getLHS()); llvm::Value *RHS = Visit(E->getRHS()); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index cadba328bf12..2fe3f5b1b443 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -280,17 +280,29 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, Args); } else { + // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); ValueDecl *Self = OMD->getSelfDecl(); ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); DeclRefExpr Base(Self, Self->getType(), Loc); ParmVarDecl *ArgDecl = *OMD->param_begin(); DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), Loc); - ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, - true, true); - BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, - Ivar->getType(), Loc); - EmitStmt(&Assign); + ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true); + + // The property type can differ from the ivar type in some situations with + // Objective-C pointer types, we can always bit cast the RHS in these cases. + if (getContext().getCanonicalType(Ivar->getType()) != + getContext().getCanonicalType(ArgDecl->getType())) { + ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, + false); + BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, + Ivar->getType(), Loc); + EmitStmt(&Assign); + } else { + BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, + Ivar->getType(), Loc); + EmitStmt(&Assign); + } } FinishFunction(); diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h index d1a13aa29711..4ebf4e88decb 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -15,7 +15,7 @@ #define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <vector> namespace llvm { diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp index 7bc774fce75b..7af15f0a8ca4 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRtti.cpp @@ -16,32 +16,31 @@ using namespace clang; using namespace CodeGen; llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - llvm::Type *Ptr8Ty; - Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Constant *Rtti = llvm::Constant::getNullValue(Ptr8Ty); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); if (!getContext().getLangOptions().Rtti) - return Rtti; + return llvm::Constant::getNullValue(Int8PtrTy); llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(getMangleContext(), RD, Out); + mangleCXXRtti(getMangleContext(), Context.getTagDeclType(RD), Out); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; std::vector<llvm::Constant *> info; // assert(0 && "FIXME: implement rtti descriptor"); // FIXME: descriptor - info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); // assert(0 && "FIXME: implement rtti ts"); // FIXME: TS - info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, info.size()); + llvm::ArrayType *type = llvm::ArrayType::get(Int8PtrTy, info.size()); C = llvm::ConstantArray::get(type, info); - Rtti = new llvm::GlobalVariable(getModule(), type, true, linktype, C, - Out.str()); - Rtti = llvm::ConstantExpr::getBitCast(Rtti, Ptr8Ty); + llvm::Constant *Rtti = + new llvm::GlobalVariable(getModule(), type, true, linktype, C, + Out.str()); + Rtti = llvm::ConstantExpr::getBitCast(Rtti, Int8PtrTy); return Rtti; } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index f58b57926787..9126c2c99cdf 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -287,8 +287,13 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { // Emit initial switch which will be patched up later by // EmitIndirectSwitches(). We need a default dest, so we use the // current BB, but this is overwritten. +#ifndef USEINDIRECTBRANCH llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()), llvm::Type::getInt32Ty(VMContext), +#else + llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()), + llvm::Type::getInt8PtrTy(VMContext), +#endif "addr"); llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 2a06f51f6685..fa77471bce0e 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -47,7 +47,7 @@ public: bool isVolatileQualified() const { return Volatile; } - /// getScalar() - Return the Value* of this scalar value. + /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); return V1; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 9df0e1abd547..e2e11478de26 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -43,6 +43,9 @@ private: llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall; llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset; llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex; + + typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t; + Pures_t Pures; typedef std::pair<Index_t, Index_t> CallOffset; typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t; Thunks_t Thunks; @@ -58,6 +61,7 @@ private: Index_t extra; int CurrentVBaseOffset; typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t; + llvm::Constant *cxa_pure; public: VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c, @@ -68,6 +72,13 @@ public: LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)), CurrentVBaseOffset(0) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + + // Calculate pointer for ___cxa_pure_virtual. + const llvm::FunctionType *FTy; + std::vector<const llvm::Type*> ArgTys; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual")); } llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; } @@ -84,8 +95,10 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } - void GenerateVBaseOffsets(std::vector<llvm::Constant *> &offsets, - const CXXRecordDecl *RD, uint64_t Offset, +#define D1(x) +//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) + + void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { @@ -94,22 +107,24 @@ public: Index_t next_vbindex = current_vbindex; if (i->isVirtual() && !SeenVBase.count(Base)) { SeenVBase.insert(Base); - int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; - llvm::Constant *m = wrap(BaseOffset); - m = wrap((0?700:0) + BaseOffset); if (updateVBIndex) { - next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8) + next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8) - 3*LLVMPointerWidth/8); VBIndex[Base] = next_vbindex; } - offsets.push_back(m); + int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; + VCalls.push_back((0?700:0) + BaseOffset); + D1(printf(" vbase for %s at %d delta %d most derived %s\n", + Base->getNameAsCString(), + (int)-VCalls.size()-3, (int)BaseOffset, + Class->getNameAsCString())); } // We also record offsets for non-virtual bases to closest enclosing // virtual base. We do this so that we don't have to search // for the nearst virtual base class when generating thunks. if (updateVBIndex && VBIndex.count(Base) == 0) VBIndex[Base] = next_vbindex; - GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex); + GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex); } } @@ -144,8 +159,8 @@ public: /// getNVOffset - Returns the non-virtual offset for the given (B) base of the /// derived class D. Index_t getNVOffset(QualType qB, QualType qD) { - qD = qD->getAs<PointerType>()->getPointeeType(); - qB = qB->getAs<PointerType>()->getPointeeType(); + qD = qD->getPointeeType(); + qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); int64_t o = getNVOffset_1(D, B); @@ -159,8 +174,8 @@ public: /// getVbaseOffset - Returns the index into the vtable for the virtual base /// offset for the given (B) virtual base of the derived class D. Index_t getVbaseOffset(QualType qB, QualType qD) { - qD = qD->getAs<PointerType>()->getPointeeType(); - qB = qB->getAs<PointerType>()->getPointeeType(); + qD = qD->getPointeeType(); + qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); if (D != Class) @@ -177,6 +192,7 @@ public: bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, bool MorallyVirtual, Index_t OverrideOffset, Index_t Offset) { + const bool isPure = MD->isPure(); typedef CXXMethodDecl::method_iterator meth_iter; // FIXME: Should OverrideOffset's be Offset? @@ -215,7 +231,9 @@ public: } Index[MD] = i; submethods[i] = m; - + if (isPure) + Pures[MD] = 1; + Pures.erase(OMD); Thunks.erase(OMD); if (MorallyVirtual) { Index_t &idx = VCall[OMD]; @@ -223,9 +241,17 @@ public: VCallOffset[MD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } else { VCallOffset[MD] = VCallOffset[OMD]; VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; + D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } VCall[MD] = idx; CallOffset ThisOffset; @@ -237,7 +263,7 @@ public: CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); - else + else if (!isPure) Thunks[MD] = ThisOffset; return true; } @@ -252,7 +278,7 @@ public: CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); - else + else if (!isPure) Thunks[MD] = ThisOffset; } return true; @@ -266,6 +292,7 @@ public: for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); i != e; ++i) { const CXXMethodDecl *MD = i->first; + assert(!MD->isPure() && "Trying to thunk a pure"); Index_t idx = Index[MD]; Index_t nv_O = i->second.first; Index_t v_O = i->second.second; @@ -276,6 +303,8 @@ public: e = CovariantThunks.end(); i != e; ++i) { const CXXMethodDecl *MD = i->first; + if (MD->isPure()) + continue; Index_t idx = Index[MD]; Index_t nv_t = i->second.first.first.first; Index_t v_t = i->second.first.first.second; @@ -285,6 +314,25 @@ public: v_r); } CovariantThunks.clear(); + for (Pures_t::iterator i = Pures.begin(), e = Pures.end(); + i != e; ++i) { + const CXXMethodDecl *MD = i->first; + Index_t idx = Index[MD]; + submethods[idx] = cxa_pure; + } + Pures.clear(); + } + + llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) { + if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) + return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + return wrap(CGM.GetAddrOfFunction(MD, Ty)); } void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) { @@ -298,37 +346,16 @@ public: continue; const CXXMethodDecl *MD = *mi; - llvm::Constant *m = 0; - if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); - else { - const FunctionProtoType *FPT = - MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - m = wrap(CGM.GetAddrOfFunction(MD, Ty)); - } - + llvm::Constant *m = WrapAddrOf(MD); OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset); } } } - void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) { - llvm::Constant *m = 0; - if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); - else { - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - m = wrap(CGM.GetAddrOfFunction(MD, Ty)); - } - + void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset, + bool ForVirtualBase) { + llvm::Constant *m = WrapAddrOf(MD); + // If we can find a previously allocated slot for this, reuse it. if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset)) return; @@ -336,6 +363,9 @@ public: // else allocate a new slot. Index[MD] = submethods.size(); submethods.push_back(m); + D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD])); + if (MD->isPure()) + Pures[MD] = 1; if (MorallyVirtual) { VCallOffset[MD] = Offset/8; Index_t &idx = VCall[MD]; @@ -343,16 +373,19 @@ public: if (idx == 0) { idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d\n", + MD->getNameAsCString(), (int)-VCalls.size()-3, + (int)VCallOffset[MD])); } } } void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset) { + Index_t Offset, bool RDisVirtualBase) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) if (mi->isVirtual()) - AddMethod(*mi, MorallyVirtual, Offset); + AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase); } void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, @@ -381,6 +414,7 @@ public: void insertVCalls(int InsertionPoint) { llvm::Constant *e = 0; + D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); @@ -392,11 +426,10 @@ public: VCalls.clear(); } - Index_t end(const CXXRecordDecl *RD, std::vector<llvm::Constant *> &offsets, - const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseWasVirtual, bool MorallyVirtual, - int64_t Offset, bool ForVirtualBase, Path_t *Path) { + Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -405,16 +438,6 @@ public: StartNewTable(); extra = 0; - // FIXME: Cleanup. - if (!ForVirtualBase) { - D(methods.push_back(wrap(666))); - // then virtual base offsets... - for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(667))); - } - bool DeferVCalls = MorallyVirtual || ForVirtualBase; int VCallInsertionPoint = methods.size(); if (!DeferVCalls) { @@ -423,20 +446,12 @@ public: // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - if (ForVirtualBase) { - D(methods.push_back(wrap(668))); - // then virtual base offsets... - for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(669))); - } - methods.push_back(wrap(-(Offset/8))); methods.push_back(rtti); Index_t AddressPoint = methods.size(); InstallThunks(); + D1(printf("============= combining methods\n")); methods.insert(methods.end(), submethods.begin(), submethods.end()); submethods.clear(); @@ -445,10 +460,8 @@ public: MorallyVirtual, Offset, Path); if (ForVirtualBase) { - D(methods.push_back(wrap(670))); insertVCalls(VCallInsertionPoint); AddressPoint += VCalls.size(); - D(methods.push_back(wrap(671))); } if (alloc) { @@ -457,7 +470,36 @@ public: return AddressPoint; } - void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) { + void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase) { + if (!RD->isDynamicClass()) + return; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + + // vtables are composed from the chain of primaries. + if (PrimaryBase) { + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + if (!PrimaryBaseWasVirtual) + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); + } + + D1(printf(" doing vcall entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + // And add the virtuals for the class to the primary vtable. + AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase); + } + + void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase, bool bottom=false) { if (!RD->isDynamicClass()) return; @@ -469,11 +511,22 @@ public: if (PrimaryBase) { if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); + + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); } - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset); + D1(printf(" doing vbase entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); + + if (RDisVirtualBase || bottom) { + Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, + RDisVirtualBase); + } } int64_t GenerateVtableForBase(const CXXRecordDecl *RD, @@ -487,27 +540,21 @@ public: const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - std::vector<llvm::Constant *> offsets; extra = 0; - GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0); - if (ForVirtualBase) - extra = offsets.size(); + D1(printf("building entries for base %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); - // vtables are composed from the chain of primaries. - if (PrimaryBase) { - if (PrimaryBaseWasVirtual) - IndirectPrimary.insert(PrimaryBase); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); - } + if (ForVirtualBase) + extra = VCalls.size(); - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset); + VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, + true); if (Path) OverrideMethods(Path, MorallyVirtual, Offset); - return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, Path); + return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, + Offset, ForVirtualBase, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -532,6 +579,8 @@ public: VCall.clear(); int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); CurrentVBaseOffset = BaseOffset; + D1(printf("vtable %s virtual base %s\n", + Class->getNameAsCString(), Base->getNameAsCString())); GenerateVtableForBase(Base, true, BaseOffset, true, Path); } int64_t BaseOffset = Offset; @@ -567,6 +616,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -591,6 +641,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -614,13 +665,14 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { mangleCXXVtable(CGM.getMangleContext(), RD, Out); llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; + linktype = llvm::GlobalValue::LinkOnceODRLinkage; std::vector<llvm::Constant *> methods; llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... AddressPoint = b.GenerateVtableForBase(RD); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 2f46313c9c20..10884a7560f5 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangCodeGen CGCall.cpp CGDebugInfo.cpp CGDecl.cpp + CGException.cpp CGExpr.cpp CGExprAgg.cpp CGExprComplex.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index ba93e5d0ebc8..88beadf33140 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -27,7 +27,11 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), +#ifndef USEINDIRECTBRANCH DebugInfo(0), IndirectGotoSwitch(0), +#else + DebugInfo(0), IndirectBranch(0), +#endif SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0) { LLVMIntTy = ConvertType(getContext().IntTy); @@ -130,10 +134,33 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EmitFunctionEpilog(*CurFnInfo, ReturnValue); +#ifdef USEINDIRECTBRANCH + // If someone did an indirect goto, emit the indirect goto block at the end of + // the function. + if (IndirectBranch) { + EmitBlock(IndirectBranch->getParent()); + Builder.ClearInsertionPoint(); + } + + +#endif // Remove the AllocaInsertPt instruction, which is just a convenience for us. llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = 0; Ptr->eraseFromParent(); +#ifdef USEINDIRECTBRANCH + + // If someone took the address of a label but never did an indirect goto, we + // made a zero entry PHI node, which is illegal, zap it now. + if (IndirectBranch) { + llvm::PHINode *PN = cast<llvm::PHINode>(IndirectBranch->getAddress()); + if (PN->getNumIncomingValues() == 0) { + PN->replaceAllUsesWith(llvm::UndefValue::get(PN->getType())); + PN->eraseFromParent(); + } + } + +#endif } void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, @@ -466,13 +493,26 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { TypeInfo.second/8)); } +#ifndef USEINDIRECTBRANCH unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned. unsigned &Entry = LabelIDs[L]; if (Entry) return Entry; +#else + +llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { + // Make sure that there is a block for the indirect goto. + if (IndirectBranch == 0) + GetIndirectGotoBlock(); +#endif +#ifndef USEINDIRECTBRANCH Entry = LabelIDs.size(); +#else + llvm::BasicBlock *BB = getBasicBlockForLabel(L); +#endif +#ifndef USEINDIRECTBRANCH // If this is the first "address taken" of a label and the indirect goto has // already been seen, add this to it. if (IndirectGotoSwitch) { @@ -488,18 +528,42 @@ unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { } return Entry; +#else + // Make sure the indirect branch includes all of the address-taken blocks. + IndirectBranch->addDestination(BB); + return llvm::BlockAddress::get(CurFn, BB); +#endif } llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { +#ifndef USEINDIRECTBRANCH // If we already made the switch stmt for indirect goto, return its block. if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent(); +#else + // If we already made the indirect branch for indirect goto, return its block. + if (IndirectBranch) return IndirectBranch->getParent(); +#endif +#ifndef USEINDIRECTBRANCH EmitBlock(createBasicBlock("indirectgoto")); +#else + CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto")); +#endif +#ifndef USEINDIRECTBRANCH + const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); +#else + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); +#endif + // Create the PHI node that indirect gotos will add entries to. - llvm::Value *DestVal = - Builder.CreatePHI(llvm::Type::getInt32Ty(VMContext), "indirect.goto.dest"); +#ifndef USEINDIRECTBRANCH + llvm::Value *DestVal = Builder.CreatePHI(Int32Ty, "indirect.goto.dest"); +#else + llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest"); +#endif +#ifndef USEINDIRECTBRANCH // Create the switch instruction. For now, set the insert block to this block // which will be fixed as labels are added. IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock()); @@ -524,8 +588,6 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(AddrTakenLabelsByID[0])); - const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); - // FIXME: The iteration order of this is nondeterminstic! for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i) IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1), @@ -541,6 +603,11 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { } return IndirectGotoSwitch->getParent(); +#else + // Create the indirect branch instruction. + IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal); + return IndirectBranch->getParent(); +#endif } llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 639e683f0369..9bb219642ab4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -183,13 +183,22 @@ public: void PopConditionalTempDestruction(); private: - CGDebugInfo* DebugInfo; + CGDebugInfo *DebugInfo; +#ifndef USEINDIRECTBRANCH /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing /// the GCC address-of-label extension and indirect goto. IDs are assigned to /// labels inside getIDForAddrOfLabel(). std::map<const LabelStmt*, unsigned> LabelIDs; +#else + /// IndirectBranch - The first time an indirect goto is seen we create a + /// block with an indirect branch. Every time we see the address of a label + /// taken, we add the label to the indirect goto. Every subsequent indirect + /// goto is codegen'd as a jump to the IndirectBranch's basic block. + llvm::IndirectBrInst *IndirectBranch; +#endif +#ifndef USEINDIRECTBRANCH /// IndirectGotoSwitch - The first time an indirect goto is seen we create a /// block with the switch for the indirect gotos. Every time we see the /// address of a label taken, we add the label to the indirect goto. Every @@ -197,6 +206,7 @@ private: /// IndirectGotoSwitch's basic block. llvm::SwitchInst *IndirectGotoSwitch; +#endif /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C /// decls. llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; @@ -377,6 +387,11 @@ public: /// GenerateVtable - Generate the vtable for the given type. llvm::Value *GenerateVtable(const CXXRecordDecl *RD); + /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an + /// object pointer to alter the dynamic type of the pointer. Used by + /// GenerateCovariantThunk for building thunks. + llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v); + /// GenerateThunk - Generate a thunk for the given method llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, int64_t nv, int64_t v); @@ -502,7 +517,7 @@ public: //===--------------------------------------------------------------------===// Qualifiers MakeQualifiers(QualType T) { - Qualifiers Quals = T.getQualifiers(); + Qualifiers Quals = getContext().getCanonicalType(T).getQualifiers(); Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T)); return Quals; } @@ -558,7 +573,11 @@ public: /// the input field number being accessed. static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts); +#ifndef USEINDIRECTBRANCH unsigned GetIDForAddrOfLabel(const LabelStmt *L); +#else + llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L); +#endif llvm::BasicBlock *GetIndirectGotoBlock(); /// EmitMemSetToZero - Generate code to memset a value of the given type to 0. @@ -819,7 +838,7 @@ public: LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); - LValue EmitPointerToDataMemberLValue(const QualifiedDeclRefExpr *E); + LValue EmitPointerToDataMemberLValue(const DeclRefExpr *E); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); @@ -1000,6 +1019,8 @@ public: bool IsAggLocVolatile = false, bool IsInitializer = false); + void EmitCXXThrowExpr(const CXXThrowExpr *E); + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ea84829b78a5..db609f62453c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -253,6 +253,10 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->isInAnonymousNamespace()) return CodeGenModule::GVA_Internal; + // "static" functions get internal linkage. + if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD)) + return CodeGenModule::GVA_Internal; + // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; @@ -260,19 +264,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) External = CodeGenModule::GVA_TemplateInstantiation; - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - // C++ member functions defined inside the class are always inline. - if (MD->isInline() || !MD->isOutOfLine()) - return CodeGenModule::GVA_CXXInline; - - return External; - } - - // "static" functions get internal linkage. - if (FD->getStorageClass() == FunctionDecl::Static) - return CodeGenModule::GVA_Internal; - - if (!FD->isInline()) + if (!FD->isInlined()) return External; if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { @@ -285,8 +277,16 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_C99Inline; } - // C++ inline semantics - assert(Features.CPlusPlus && "Must be in C++ mode"); + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return CodeGenModule::GVA_C99Inline; + return CodeGenModule::GVA_CXXInline; } @@ -601,6 +601,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast<ValueDecl>(GD.getDecl()); + PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(), + Context.getSourceManager(), + "Generating code for declaration"); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) @@ -949,7 +953,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: - assert(false && "Variable should not be instantiated"); + llvm::llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index dedf824ef9fd..d43d13e26bbb 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -180,7 +180,7 @@ static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext, } const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { - const clang::Type &Ty = *Context.getCanonicalType(T); + const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 2e6034bbcd97..a5b34527969b 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -52,7 +52,8 @@ namespace { void mangleGuardVariable(const VarDecl *D); void mangleCXXVtable(const CXXRecordDecl *RD); - void mangleCXXRtti(const CXXRecordDecl *RD); + void mangleCXXVTT(const CXXRecordDecl *RD); + void mangleCXXRtti(QualType Ty); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type); @@ -114,6 +115,7 @@ namespace { } static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); for (const DeclContext *DC = D->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) @@ -204,10 +206,17 @@ void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) { mangleName(RD); } -void CXXNameMangler::mangleCXXRtti(const CXXRecordDecl *RD) { +void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) { + // <special-name> ::= TT <type> # VTT structure + Out << "_ZTT"; + mangleName(RD); +} + +void CXXNameMangler::mangleCXXRtti(QualType Ty) { // <special-name> ::= TI <type> # typeinfo structure Out << "_ZTI"; - mangleName(RD); + + mangleType(Ty); } void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { @@ -1355,7 +1364,7 @@ namespace clang { "Mangling declaration"); CXXNameMangler Mangler(Context, os); - if (!Mangler.mangle(cast<NamedDecl>(D->getCanonicalDecl()))) + if (!Mangler.mangle(D)) return false; os.flush(); @@ -1424,10 +1433,10 @@ namespace clang { os.flush(); } - void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD, + void mangleCXXRtti(MangleContext &Context, QualType Ty, llvm::raw_ostream &os) { CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXRtti(RD); + Mangler.mangleCXXRtti(Ty); os.flush(); } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 2cdb4e23919d..7f46a106f32a 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -65,7 +65,9 @@ namespace clang { llvm::raw_ostream &os); void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD, llvm::raw_ostream &os); - void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD, + void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, + llvm::raw_ostream &os); + void mangleCXXRtti(MangleContext &Context, QualType T, llvm::raw_ostream &os); void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D, CXXCtorType Type, llvm::raw_ostream &os); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index c9d0b266d1cc..808c31c64828 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -12,8 +12,8 @@ #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" -#include "clang/Driver/Driver.h" // FIXME: Remove? -#include "clang/Driver/DriverDiagnostic.h" // FIXME: Remove? +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Job.h" #include "clang/Driver/HostInfo.h" @@ -22,9 +22,11 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/Process.h" #include "InputInfo.h" #include "ToolChains.h" @@ -32,13 +34,6 @@ using namespace clang::driver; using namespace clang::driver::tools; -static const char *MakeFormattedString(const ArgList &Args, - const llvm::format_object_base &Fmt) { - llvm::SmallString<256> Str; - llvm::raw_svector_ostream(Str) << Fmt; - return Args.MakeArgString(Str.str()); -} - /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { @@ -203,6 +198,10 @@ void Clang::AddPreprocessingOptions(const Driver &D, // those options. :( Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, options::OPT_Xpreprocessor); + + // -I- is a deprecated GCC feature, reject it. + if (Arg *A = Args.getLastArg(options::OPT_I_)) + D.Diag(clang::diag::err_drv_I_dash_not_supported) << A->getAsString(Args); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. @@ -417,8 +416,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - // FIXME: This needs to change to use a clang-cc option, and set the attribute - // on functions. if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || @@ -426,8 +423,6 @@ void Clang::AddX86TargetArgs(const ArgList &Args, Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("--disable-red-zone"); - // FIXME: This needs to change to use a clang-cc option, and set the attribute - // on functions. if (Args.hasFlag(options::OPT_msoft_float, options::OPT_mno_soft_float, false)) @@ -507,6 +502,57 @@ static bool needsExceptions(const ArgList &Args, types::ID InputType, } } +/// getEffectiveClangTriple - Get the "effective" target triple, which is the +/// triple for the target but with the OS version potentially modified for +/// Darwin's -mmacosx-version-min. +static std::string getEffectiveClangTriple(const Driver &D, + const ToolChain &TC, + const ArgList &Args) { + llvm::Triple Triple(getLLVMTriple(TC, Args)); + + if (Triple.getOS() != llvm::Triple::Darwin) { + // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on + // non-Darwin. + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, + options::OPT_miphoneos_version_min_EQ)) + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return Triple.getTriple(); + } + + // If -mmacosx-version-min=10.3.9 is specified, change the effective triple + // from being something like powerpc-apple-darwin9 to powerpc-apple-darwin7. + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { + unsigned Major, Minor, Micro; + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, + HadExtra) || HadExtra || + Major != 10) + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + // Mangle the MacOS version min number into the Darwin number: e.g. 10.3.9 + // is darwin7.9. + llvm::SmallString<16> Str; + llvm::raw_svector_ostream(Str) << "darwin" << Minor + 4 << "." << Micro; + Triple.setOSName(Str.str()); + } else if (Arg *A = Args.getLastArg(options::OPT_miphoneos_version_min_EQ)) { + unsigned Major, Minor, Micro; + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, + HadExtra) || HadExtra) + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + // Mangle the iPhoneOS version number into the Darwin number: e.g. 2.0 is 2 + // -> 9.2.0. + llvm::SmallString<16> Str; + llvm::raw_svector_ostream(Str) << "darwin9." << Major << "." << Minor; + Triple.setOSName(Str.str()); + } + + return Triple.getTriple(); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, @@ -518,12 +564,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Add the "effective" target triple. CmdArgs.push_back("-triple"); + std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); - const char *TripleStr = - Args.MakeArgString(getLLVMTriple(getToolChain(), Args)); - CmdArgs.push_back(TripleStr); - + // Select the appropriate action. if (isa<AnalyzeJobAction>(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); @@ -606,9 +652,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // issue is that llvm-gcc translates these options based on // the values in cc1, whereas we are processing based on // the driver arguments. - // - // FIXME: This is currently broken for -f flags when -fno - // variants are present. // This comes from the default translation the driver + cc1 // would do to enable flag_pic. @@ -661,8 +704,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--debug-pass=Structure"); if (Args.hasArg(options::OPT_fdebug_pass_arguments)) CmdArgs.push_back("--debug-pass=Arguments"); - // FIXME: set --inline-threshhold=50 if (optimize_size || optimize - // < 3) + if (!Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants)) + CmdArgs.push_back("--no-merge-all-constants"); // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more @@ -714,9 +758,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } - // FIXME: Add --stack-protector-buffer-size=<xxx> on - // -fstack-protect. - Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_MQ)) || @@ -726,8 +767,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_P); - Args.AddLastArg(CmdArgs, options::OPT_mmacosx_version_min_EQ); - Args.AddLastArg(CmdArgs, options::OPT_miphoneos_version_min_EQ); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); // Special case debug options to only pass -g to clang. This is @@ -736,7 +775,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-g"); Args.AddLastArg(CmdArgs, options::OPT_nostdinc); - Args.AddLastArg(CmdArgs, options::OPT_nostdclanginc); + Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); Args.AddLastArg(CmdArgs, options::OPT_isysroot); @@ -759,7 +798,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + Args.AddLastArg(CmdArgs, options::OPT_pedantic); + Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} @@ -770,9 +811,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) if (types::isCXX(InputType)) - CmdArgs.push_back("-std=c++98"); + CmdArgs.push_back("-std=c++98"); else - CmdArgs.push_back("-std=c89"); + CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); @@ -794,10 +835,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT__relocatable_pch, true)) CmdArgs.push_back("--relocatable-pch"); - if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { - CmdArgs.push_back("-fconstant-string-class"); - CmdArgs.push_back(A->getValue(Args)); - } + if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { + CmdArgs.push_back("-fconstant-string-class"); + CmdArgs.push_back(A->getValue(Args)); + } + + // Pass -fmessage-length=. + if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { + A->render(Args, CmdArgs); + } else { + // If -fmessage-length=N was not specified, determine whether this is a + // terminal and, if so, implicitly define -fmessage-length appropriately. + unsigned N = llvm::sys::Process::StandardErrColumns(); + CmdArgs.push_back("-fmessage-length"); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); + } // Forward -f options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); @@ -805,7 +857,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime); Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions); - Args.AddLastArg(CmdArgs, options::OPT_fmessage_length_EQ); Args.AddLastArg(CmdArgs, options::OPT_fms_extensions); Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime); Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics); @@ -871,9 +922,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fsigned-char=0"); } - // -fno-pascal-strings is default, only pass non-default. If the - // -tool chain happened to translate to -mpascal-strings, we want to - // -back translate here. + // -fno-pascal-strings is default, only pass non-default. If the tool chain + // happened to translate to -mpascal-strings, we want to back translate here. // // FIXME: This is gross; that translation should be pulled from the // tool chain. @@ -905,9 +955,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); - if (!Args.hasFlag(options::OPT_fcolor_diagnostics, - options::OPT_fno_color_diagnostics)) - CmdArgs.push_back("-fno-color-diagnostics"); + + // Color diagnostics are the default, unless the terminal doesn't support + // them. + if (Args.hasFlag(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics) && + llvm::sys::Process::StandardErrHasColors()) + CmdArgs.push_back("-fcolor-diagnostics"); + if (!Args.hasFlag(options::OPT_fshow_source_location, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); @@ -979,6 +1034,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, II.getInputArg().renderAsInput(Args, CmdArgs); } + Args.AddAllArgs(CmdArgs, options::OPT_undef); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); @@ -1667,23 +1724,18 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, static bool isSourceSuffix(const char *Str) { // match: 'C', 'CPP', 'c', 'cc', 'cp', 'c++', 'cpp', 'cxx', 'm', // 'mm'. - switch (strlen(Str)) { - default: - return false; - case 1: - return (memcmp(Str, "C", 1) == 0 || - memcmp(Str, "c", 1) == 0 || - memcmp(Str, "m", 1) == 0); - case 2: - return (memcmp(Str, "cc", 2) == 0 || - memcmp(Str, "cp", 2) == 0 || - memcmp(Str, "mm", 2) == 0); - case 3: - return (memcmp(Str, "CPP", 3) == 0 || - memcmp(Str, "c++", 3) == 0 || - memcmp(Str, "cpp", 3) == 0 || - memcmp(Str, "cxx", 3) == 0); - } + return llvm::StringSwitch<bool>(Str) + .Case("C", true) + .Case("c", true) + .Case("m", true) + .Case("cc", true) + .Case("cp", true) + .Case("mm", true) + .Case("CPP", true) + .Case("c++", true) + .Case("cpp", true) + .Case("cxx", true) + .Default(false); } // FIXME: Can we tablegen this? @@ -1861,7 +1913,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, // Adding all arguments doesn't make sense here but this is what // gcc does. Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, - "-macosx_version_min"); + "-macosx_version_min"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ, "-iphoneos_version_min"); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); @@ -2137,10 +2189,10 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -2167,15 +2219,15 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const Driver &D = getToolChain().getHost().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } @@ -2212,14 +2264,13 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); -// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/opt/gcc4/lib/gcc/%s/4.2.4", - getToolChain().getTripleString().c_str()))); + CmdArgs.push_back(Args.MakeArgString("-L/opt/gcc4/lib/gcc/" + + getToolChain().getTripleString() + + "/4.2.4")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); @@ -2307,7 +2358,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } @@ -2345,9 +2396,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc-lib/%s/3.3.5", - getToolChain().getTripleString().c_str()))); + std::string Triple = getToolChain().getTripleString(); + if (Triple.substr(0, 6) == "x86_64") + Triple.replace(0, 6, "amd64"); + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + + "/3.3.5")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); @@ -2547,10 +2600,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // For now, DragonFly Assemble does just about the same as for // FreeBSD, but this may change soon. void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on DragonFly/pc64, we have to explicitly @@ -2678,7 +2731,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lthread_xu"); + CmdArgs.push_back("-lpthread"); if (!Args.hasArg(options::OPT_nolibc)) { CmdArgs.push_back("-lc"); diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index eee8c19c2776..c616c6a5bf4b 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -9,6 +9,7 @@ #include "clang/Driver/Types.h" +#include "llvm/ADT/StringSwitch.h" #include <string.h> #include <cassert> @@ -102,51 +103,42 @@ bool types::isCXX(ID Id) { } types::ID types::lookupTypeForExtension(const char *Ext) { - unsigned N = strlen(Ext); - - switch (N) { - case 1: - if (memcmp(Ext, "c", 1) == 0) return TY_C; - if (memcmp(Ext, "i", 1) == 0) return TY_PP_C; - if (memcmp(Ext, "m", 1) == 0) return TY_ObjC; - if (memcmp(Ext, "M", 1) == 0) return TY_ObjCXX; - if (memcmp(Ext, "h", 1) == 0) return TY_CHeader; - if (memcmp(Ext, "C", 1) == 0) return TY_CXX; - if (memcmp(Ext, "H", 1) == 0) return TY_CXXHeader; - if (memcmp(Ext, "f", 1) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "F", 1) == 0) return TY_Fortran; - if (memcmp(Ext, "s", 1) == 0) return TY_PP_Asm; - if (memcmp(Ext, "S", 1) == 0) return TY_Asm; - case 2: - if (memcmp(Ext, "ii", 2) == 0) return TY_PP_CXX; - if (memcmp(Ext, "mi", 2) == 0) return TY_PP_ObjC; - if (memcmp(Ext, "mm", 2) == 0) return TY_ObjCXX; - if (memcmp(Ext, "cc", 2) == 0) return TY_CXX; - if (memcmp(Ext, "cc", 2) == 0) return TY_CXX; - if (memcmp(Ext, "cp", 2) == 0) return TY_CXX; - if (memcmp(Ext, "hh", 2) == 0) return TY_CXXHeader; - break; - case 3: - if (memcmp(Ext, "ads", 3) == 0) return TY_Ada; - if (memcmp(Ext, "adb", 3) == 0) return TY_Ada; - if (memcmp(Ext, "ast", 3) == 0) return TY_AST; - if (memcmp(Ext, "cxx", 3) == 0) return TY_CXX; - if (memcmp(Ext, "cpp", 3) == 0) return TY_CXX; - if (memcmp(Ext, "CPP", 3) == 0) return TY_CXX; - if (memcmp(Ext, "cXX", 3) == 0) return TY_CXX; - if (memcmp(Ext, "for", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "FOR", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "fpp", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "FPP", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "f90", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "f95", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "F90", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "F95", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "mii", 3) == 0) return TY_PP_ObjCXX; - break; - } - - return TY_INVALID; + return llvm::StringSwitch<types::ID>(Ext) + .Case("c", TY_C) + .Case("i", TY_PP_C) + .Case("m", TY_ObjC) + .Case("M", TY_ObjCXX) + .Case("h", TY_CHeader) + .Case("C", TY_CXX) + .Case("H", TY_CXXHeader) + .Case("f", TY_PP_Fortran) + .Case("F", TY_Fortran) + .Case("s", TY_PP_Asm) + .Case("S", TY_Asm) + .Case("ii", TY_PP_CXX) + .Case("mi", TY_PP_ObjC) + .Case("mm", TY_ObjCXX) + .Case("cc", TY_CXX) + .Case("CC", TY_CXX) + .Case("cp", TY_CXX) + .Case("hh", TY_CXXHeader) + .Case("ads", TY_Ada) + .Case("adb", TY_Ada) + .Case("ast", TY_AST) + .Case("cxx", TY_CXX) + .Case("cpp", TY_CXX) + .Case("CPP", TY_CXX) + .Case("CXX", TY_CXX) + .Case("for", TY_PP_Fortran) + .Case("FOR", TY_PP_Fortran) + .Case("fpp", TY_Fortran) + .Case("FPP", TY_Fortran) + .Case("f90", TY_PP_Fortran) + .Case("f95", TY_PP_Fortran) + .Case("F90", TY_Fortran) + .Case("F95", TY_Fortran) + .Case("mii", TY_PP_ObjCXX) + .Default(TY_INVALID); } types::ID types::lookupTypeForTypeSpecifier(const char *Name) { diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 8d76680f6f92..9a30f59465f8 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -400,11 +400,6 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<parameter> " << PVD->getNameAsString() << "\n"; break; } - case Decl::OriginalParmVar: { - OriginalParmVarDecl* OPVD = cast<OriginalParmVarDecl>(*I); - Out << "<original parameter> " << OPVD->getNameAsString() << "\n"; - break; - } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); Out << "<objc property> " << OPD->getNameAsString() << "\n"; @@ -457,6 +452,8 @@ class RecordLayoutDumper : public ASTConsumer { // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 55f274005909..049f3bd3ea14 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -29,7 +29,6 @@ #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 25316bed9fb4..c0b4ebaab03b 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -241,11 +241,9 @@ bool getVisualStudioDir(std::string &path) { return(false); } -void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple) { +void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. llvm::Triple::OSType os = triple.getOS(); - switch (os) { case llvm::Triple::Win32: { @@ -276,162 +274,186 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, } } break; - case llvm::Triple::Cygwin: - if (Lang.CPlusPlus) { - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", - System, false, false, false); - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", - System, false, false, false); - } - AddPath("/usr/include", System, false, false, false); - break; case llvm::Triple::MinGW64: - if (Lang.CPlusPlus) { // I'm guessing here. - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); - } - // Fall through. case llvm::Triple::MinGW32: - if (Lang.CPlusPlus) { - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); - } AddPath("c:/mingw/include", System, true, false, false); break; default: - if (Lang.CPlusPlus) { - switch (os) { - case llvm::Triple::Darwin: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", - "i686-apple-darwin10/x86_64", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", - "i686-apple-darwin8", - triple); - break; - case llvm::Triple::Linux: - // Ubuntu 7.10 - Gutsy Gibbon - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", - "x86_64-linux-gnu/32", - "x86_64-linux-gnu", - triple); - // Fedora 8 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // Fedora 9 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // Fedora 10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // openSUSE 11.1 32 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i586-suse-linux", - "i586-suse-linux", - triple); - // openSUSE 11.1 64 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-suse-linux/32", - "x86_64-suse-linux", - triple); - // openSUSE 11.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i586-suse-linux", - "i586-suse-linux", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-suse-linux", - "x86_64-suse-linux", - triple); - // Arch Linux 2008-06-24 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - triple); - // Gentoo x86 2009.1 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Gentoo x86 2009.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Gentoo x86 2008.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Ubuntu 8.10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-pc-linux-gnu", - "i486-pc-linux-gnu", - triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); - // Gentoo amd64 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - break; - case llvm::Triple::FreeBSD: - // DragonFly - AddPath("/usr/include/c++/4.1", System, true, false, false); - // FreeBSD - AddPath("/usr/include/c++/4.2", System, true, false, false); - break; - case llvm::Triple::Solaris: - // Solaris - Fall though.. - case llvm::Triple::AuroraUX: - // AuroraUX - AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", - "i386-pc-solaris2.11", - "i386-pc-solaris2.11", - triple); - break; - default: - break; - } - } break; } AddPath("/usr/local/include", System, false, false, false); AddPath("/usr/include", System, false, false, false); +} + +void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { + llvm::Triple::OSType os = triple.getOS(); + // FIXME: temporary hack: hard-coded paths. + switch (os) { + case llvm::Triple::Cygwin: + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", + System, true, false, false); + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", + System, true, false, false); + break; + case llvm::Triple::MinGW64: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); + // Fall through. + case llvm::Triple::MinGW32: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); + break; + case llvm::Triple::Darwin: + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "i686-apple-darwin10", + "i686-apple-darwin10/x86_64", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", + "i686-apple-darwin8", + "i686-apple-darwin8", + triple); + break; + case llvm::Triple::Linux: + // Ubuntu 7.10 - Gutsy Gibbon + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", + "x86_64-linux-gnu/32", + "x86_64-linux-gnu", + triple); + // Fedora 8 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // Fedora 9 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // Fedora 10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // openSUSE 11.1 32 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i586-suse-linux", + "i586-suse-linux", + triple); + // openSUSE 11.1 64 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "x86_64-suse-linux/32", + "x86_64-suse-linux", + triple); + // openSUSE 11.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "i586-suse-linux", + "i586-suse-linux", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "x86_64-suse-linux", + "x86_64-suse-linux", + triple); + // Arch Linux 2008-06-24 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-gnu", + triple); + // Gentoo x86 2009.1 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Gentoo x86 2009.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Gentoo x86 2008.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Ubuntu 8.10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-pc-linux-gnu", + "i486-pc-linux-gnu", + triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); + // Gentoo amd64 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Exherbo (2009-10-26) + AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu/32", + "x86_64-pc-linux-gnu", + triple); + AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + break; + case llvm::Triple::FreeBSD: + // DragonFly + AddPath("/usr/include/c++/4.1", System, true, false, false); + // FreeBSD + AddPath("/usr/include/c++/4.2", System, true, false, false); + break; + case llvm::Triple::Solaris: + // Solaris - Fall though.. + case llvm::Triple::AuroraUX: + // AuroraUX + AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", + "i386-pc-solaris2.11", + "i386-pc-solaris2.11", + triple); + break; + default: + break; + } +} + +void InitHeaderSearch::AddDefaultFrameworkIncludePaths(const llvm::Triple &triple) { + llvm::Triple::OSType os = triple.getOS(); + if (os != llvm::Triple::Darwin) + return; AddPath("/System/Library/Frameworks", System, true, false, true); AddPath("/Library/Frameworks", System, true, false, true); } +void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple) { + AddDefaultCIncludePaths(triple); + AddDefaultFrameworkIncludePaths(triple); + if (Lang.CPlusPlus) + AddDefaultCPlusPlusIncludePaths(triple); +} + void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) { AddEnvVarPaths("CPATH"); if (Lang.CPlusPlus && Lang.ObjC1) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index b1a0a5ee8d51..ec5c1061bb93 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -17,8 +17,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" #include "llvm/System/Path.h" - -namespace clang { +using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit @@ -346,27 +345,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI, assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); DefineBuiltinMacro(Buf, "__CHAR_BIT__=8"); - unsigned IntMaxWidth; - const char *IntMaxSuffix; - if (TI.getIntMaxType() == TargetInfo::SignedLongLong) { - IntMaxWidth = TI.getLongLongWidth(); - IntMaxSuffix = "LL"; - } else if (TI.getIntMaxType() == TargetInfo::SignedLong) { - IntMaxWidth = TI.getLongWidth(); - IntMaxSuffix = "L"; - } else { - assert(TI.getIntMaxType() == TargetInfo::SignedInt); - IntMaxWidth = TI.getIntWidth(); - IntMaxSuffix = ""; - } - DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf); DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf); DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf); DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf); DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf); DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf); - DefineTypeSize("__INTMAX_MAX__", IntMaxWidth, IntMaxSuffix, true, Buf); + TargetInfo::IntType IntMaxType = TI.getIntMaxType(); + DefineTypeSize("__INTMAX_MAX__", TI.getTypeWidth(IntMaxType), + TI.getTypeConstantSuffix(IntMaxType), true, Buf); DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); @@ -455,8 +442,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// -bool InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions& InitOpts) { +bool clang::InitializePreprocessor(Preprocessor &PP, + const PreprocessorInitOptions &InitOpts, + bool undef_macros) { std::vector<char> PredefineBuffer; const char *LineDirective = "# 1 \"<built-in>\" 3\n"; @@ -464,8 +452,9 @@ bool InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. - InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), - PredefineBuffer); + if (!undef_macros) + InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), + PredefineBuffer); // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. @@ -504,5 +493,3 @@ bool InitializePreprocessor(Preprocessor &PP, // Once we've read this, we're done. return false; } - -} // namespace clang diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 9c6059b1c7c0..26f426ba329b 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -32,6 +32,7 @@ #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <iterator> #include <cstdio> @@ -2104,7 +2105,13 @@ void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, + Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(), + Record, Idx)); } void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -2197,6 +2204,25 @@ QualType PCHReader::GetType(pch::TypeID ID) { return TypesLoaded[Index].withFastQualifiers(FastQuals); } +TemplateArgumentLocInfo +PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const RecordData &Record, + unsigned &Index) { + switch (Kind) { + case TemplateArgument::Expression: + return ReadDeclExpr(); + case TemplateArgument::Type: + return GetDeclaratorInfo(Record, Index); + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + return TemplateArgumentLocInfo(); + } + llvm::llvm_unreachable("unexpected template argument loc"); + return TemplateArgumentLocInfo(); +} + Decl *PCHReader::GetDecl(pch::DeclID ID) { if (ID == 0) return 0; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index d1cb461640b7..b9ece21f74c3 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -52,7 +52,6 @@ namespace { void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *PD); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); void VisitBlockDecl(BlockDecl *BD); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -107,9 +106,9 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // set the underlying type of the typedef *before* we try to read // the type associated with the TypedefDecl. VisitNamedDecl(TD); - TD->setUnderlyingType(Reader.GetType(Record[Idx + 1])); - TD->setTypeForDecl(Reader.GetType(Record[Idx]).getTypePtr()); - Idx += 2; + uint64_t TypeData = Record[Idx++]; + TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx)); + TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); } void PCHDeclReader::VisitTagDecl(TagDecl *TD) { @@ -163,7 +162,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setPreviousDeclaration( cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); - FD->setInline(Record[Idx++]); + FD->setInlineSpecified(Record[Idx++]); FD->setVirtualAsWritten(Record[Idx++]); FD->setPure(Record[Idx++]); FD->setHasInheritedPrototype(Record[Idx++]); @@ -370,11 +369,6 @@ void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); } -void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) { - VisitParmVarDecl(PD); - PD->setOriginalType(Reader.GetType(Record[Idx++])); -} - void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast<StringLiteral>(Reader.ReadDeclExpr())); @@ -618,7 +612,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = Context->getTranslationUnitDecl(); break; case pch::DECL_TYPEDEF: - D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0); break; case pch::DECL_ENUM: D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0); @@ -696,10 +690,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, VarDecl::None, 0); break; - case pch::DECL_ORIGINAL_PARM_VAR: - D = OriginalParmVarDecl::Create(*Context, 0, SourceLocation(), 0, - QualType(),0, QualType(), VarDecl::None, 0); - break; case pch::DECL_FILE_SCOPE_ASM: D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); break; diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 4b9496e00f8b..01af67dd50a1 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -347,6 +347,8 @@ unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: read qualifier + // FIXME: read explicit template arguments return 0; } @@ -422,7 +424,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { E->setArgument(cast<Expr>(StmtStack.back())); ++Idx; } else { - E->setArgument(Reader.GetType(Record[Idx++])); + E->setArgument(Reader.GetDeclaratorInfo(Record, Idx)); } E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index fb48df332121..de56166125ed 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -368,7 +368,11 @@ void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( } void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record); } void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); @@ -589,7 +593,6 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); - RECORD(DECL_ORIGINAL_PARM_VAR); RECORD(DECL_FILE_SCOPE_ASM); RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); @@ -2106,6 +2109,23 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { Record.push_back(SID); } +void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordData &Record) { + switch (Arg.getArgument().getKind()) { + case TemplateArgument::Expression: + AddStmt(Arg.getLocInfo().getAsExpr()); + break; + case TemplateArgument::Type: + AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); + break; + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + break; + } +} + void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { if (DInfo == 0) { AddTypeRef(QualType(), Record); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index fbd9929e49d7..8997e661a5a1 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -55,7 +55,6 @@ namespace { void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, @@ -107,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); - Writer.AddTypeRef(D->getUnderlyingType(), Record); + Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record); Code = pch::DECL_TYPEDEF; } @@ -162,7 +161,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Writer.AddStmt(D->getBody()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->isInline()); + Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); Record.push_back(D->isPure()); Record.push_back(D->hasInheritedPrototype()); @@ -390,13 +389,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { assert(D->getInit() == 0 && "PARM_VAR_DECL never has init"); } -void PCHDeclWriter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - VisitParmVarDecl(D); - Writer.AddTypeRef(D->getOriginalType(), Record); - Code = pch::DECL_ORIGINAL_PARM_VAR; - AbbrevToUse = 0; -} - void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAsmString()); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 9497f973f6bc..78a56db7edcd 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -314,6 +314,8 @@ void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); + // FIXME: write qualifier + // FIXME: write explicit template arguments Code = pch::EXPR_DECL_REF; } @@ -382,7 +384,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); if (E->isArgumentType()) - Writer.AddTypeRef(E->getArgumentType(), Record); + Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record); else { Record.push_back(0); Writer.WriteSubStmt(E->getArgumentExpr()); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index f3cb20619ed5..630a093a4bf6 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -66,7 +66,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, OS << ' '; // Make sure we have enough space in the spelling buffer. - if (I->getLength() < SpellingBuffer.size()) + if (I->getLength() > SpellingBuffer.size()) SpellingBuffer.resize(I->getLength()); const char *Buffer = SpellingBuffer.data(); unsigned SpellingLen = PP.getSpelling(*I, Buffer); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 0ea0a58d5239..24ad69e3e0d3 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -2569,7 +2569,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Build sizeof(returnType) SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - returnType, + Context->getTrivialDeclaratorInfo(returnType), Context->getSizeType(), SourceLocation(), SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) @@ -2609,10 +2609,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // typedef struct objc_object Protocol; QualType RewriteObjC::getProtocolType() { if (!ProtocolTypeDecl) { + DeclaratorInfo *DInfo + = Context->getTrivialDeclaratorInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get("Protocol"), - Context->getObjCIdType()); + DInfo); } return Context->getTypeDeclType(ProtocolTypeDecl); } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 14769c187393..b1d8800369e5 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -13,6 +13,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -37,6 +38,12 @@ static const enum llvm::raw_ostream::Colors savedColor = /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; +TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, + const DiagnosticOptions &diags) + : OS(os), LangOpts(0), DiagOpts(&diags), + LastCaretDiagnosticWasNote(false) { +} + void TextDiagnosticPrinter:: PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid()) return; @@ -46,7 +53,7 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { // Print out the other include frames first. PrintIncludeStack(PLoc.getIncludeLoc(), SM); - if (ShowLocation) + if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else @@ -281,13 +288,13 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, Ranges[i] = SourceRange(S, E); } - if (ShowLocation) { + if (DiagOpts->ShowLocation) { std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc); // Emit the file/line/column that this expansion came from. OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':' << SM.getLineNumber(IInfo.first, IInfo.second) << ':'; - if (ShowColumn) + if (DiagOpts->ShowColumn) OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':'; OS << ' '; } @@ -370,13 +377,13 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // produce easily machine parsable output. Add a space before the source line // and the caret to make it trivial to tell the main diagnostic line from what // the user is intended to see. - if (PrintRangeInfo) { + if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } std::string FixItInsertionLine; - if (NumHints && PrintFixItInfo) { + if (NumHints && DiagOpts->ShowFixits) { for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints; Hint != LastHint; ++Hint) { if (Hint->InsertionLoc.isValid()) { @@ -417,20 +424,20 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // Emit what we have computed. OS << SourceLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { - if (UseColors) + if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); - if (PrintRangeInfo) + if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); } } @@ -627,15 +634,15 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } // Compute the column number. - if (ShowLocation) { - if (UseColors) + if (DiagOpts->ShowLocation) { + if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (ShowColumn) + if (DiagOpts->ShowColumn) if (unsigned ColNo = PLoc.getColumn()) OS << ColNo << ':'; - if (PrintRangeInfo && Info.getNumRanges()) { + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); bool PrintedRange = false; @@ -679,12 +686,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS << ':'; } OS << ' '; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); } } - if (UseColors) { + if (DiagOpts->ShowColors) { // Print diagnostic category in bold and color switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); @@ -703,20 +710,20 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, case Diagnostic::Fatal: OS << "fatal error: "; break; } - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); - if (PrintDiagnosticOption) + if (DiagOpts->ShowOptionNames) if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { OutStr += " [-W"; OutStr += Opt; OutStr += ']'; } - if (UseColors) { + if (DiagOpts->ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { case Diagnostic::Warning: OS.changeColor(savedColor, true); break; @@ -726,17 +733,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } } - if (MessageLength) { + if (DiagOpts->MessageLength) { // We will be word-wrapping the error message, so compute the // column number where we currently are (after printing the // location information). unsigned Column = OS.tell() - StartOfLocationInfo; - PrintWordWrapped(OS, OutStr, MessageLength, Column); + PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); } else { OS.write(OutStr.begin(), OutStr.size()); } OS << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); // If caret diagnostics are enabled and we have location, we want to @@ -745,7 +752,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (CaretDiagnostics && Info.getLocation().isValid() && + if (DiagOpts->ShowCarets && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumCodeModificationHints())) { @@ -772,7 +779,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), Info.getCodeModificationHints(), Info.getNumCodeModificationHints(), - MessageLength); + DiagOpts->MessageLength); } OS.flush(); diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 6c874f4b7bb5..e63291b2af90 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -35,4 +35,4 @@ add_custom_target(clang-headers ALL install(FILES ${files} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ - DESTINATION lib/clang/${CLANG_VERSION}/include) + DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include) diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index a7020d838ec9..f79a0f4af557 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -28,7 +28,8 @@ /* If we're hosted, fall back to the system's stdint.h, which might have * additional definitions. */ -#if __STDC_HOSTED__ +#if __STDC_HOSTED__ && \ + defined(__has_include_next) && __has_include_next(<stdint.h>) # include_next <stdint.h> #else diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 8edd634f8af4..73b584b5205d 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/ |