diff options
338 files changed, 14006 insertions, 5659 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cd52d0..7f4ab33 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 24e1ac3..2b4aa04 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 9ac35e1..1c892fd 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 daa7387..42cf8fa 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 44cbe0e..1a58f44 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 30896c9..7392170 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 8b84bc2..a775051 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 72ce0d8..813e83a 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 790ea3c..e1fae8f 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 79a0d36..3ef3cc3 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 729a2f1..bcd28ea 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 8d44676..f1a2793 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 0d09ea3..2a87f58 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 3f66b1f..5931a3f 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 7490b1d..5f318ba 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 458af1f..1e6871f 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 2d523ff..f1aa2cd5 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 8d7e4b5..034029a 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 0000000..bb14c62 --- /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 66ff34c..8ef8fb5 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 db02a68..daa8147 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 1d7181b..da78578 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 fabeea3..5edfe6f 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 8e02ccf..66e850a 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 1434fce..914118c 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 0000000..46b3edd --- /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 4e00d69c..3bef08d 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 0000000..007ec09 --- /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 0000000..70f3c44 --- /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 0000000..688cf64 --- /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 0000000..317e43a --- /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 0000000..7f4e7d5 --- /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 0000000..7fee501 --- /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 0000000..b339b3d --- /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 e5c61e6..2f2a11a 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 d8b9d56..8678ca9 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 5f7b2cb..40c1ed3 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 7a462c5..6ca2e9e 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 d3996c6..167a102 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 666e45b..7aaae9c 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 3826d3a..afc6361 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 2799785..98c703d 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 cbf9cdb..bb251ad 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 dfdf0ff..e2f1104 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 e5c7327..ae8b923 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 3f132c0..bbc5513 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 19b0ea3..db8d580 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 7a87e24..99fddb5 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 2184bf3..6b60f2e 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 790b75b..c0a9505 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 e8cc564..9960d5b 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 8a69cba..7e9ac53 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 b88e2aa..e61ef92 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 4084be6..5370114 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 9573777..7dfabba 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 508af53..ad53a8d 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 36323c2..8b80d1d 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 0000000..58673e4 --- /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 a90b4ea..48c4268 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 eb03602..b29ee27 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 1e953d6..b2bb9a1 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 cc16970..cc8b3a0 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 728e138..22427eb 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 0fd8d44..98e5a75 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 36cf56d..f8e01f7 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 97656f7..c4ab5ae 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 0765ac3..35960ff 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 8acdb30..8d91095 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 050b3f4..073365d 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 51970f18..dccb8bc 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 9cb4677..f34d469 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 d2f509d..5b3522c 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 7f5fa35..aef3d29 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 20e1150..e541406 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 d270a95..a6996a4 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 224bf87..6cfdcdd 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 457f4c8..b4c0c59 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 7f38ac1..7b48b72 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 9d0d836..d9d1950 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 9a1c654..9ebc91a 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 a4de3e5..a8ea752 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 cba0e22..7c6fc41 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 94d2299..7862c57 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 c79cc3c..0b159c3 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 6e4cdd2..b57b37d 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 2af1976..4bd7f96 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 c4d42f6..02e0c74 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 0000000..94e1ca1 --- /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 24588bc..5b4cf0a 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 5fb0178..3608d34 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 0000000..1cf5d0c --- /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 0000000..33bb515 --- /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 aa2d0ab..4781d5e 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 1271ae4..ea4d3ec 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 d81d83c..888af9b 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 c629ad1..03614e8 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 89c1783..cd4697f 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 ae8845d..17dc068 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 1a900f8..2d9b531 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 0000000..33c85d5 --- /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 0000000..9c2359f --- /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 ea0255d..c71882e 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 da24192..695f0b0 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 0000000..e0a8d0d --- /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 8086da5..307686f 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 780772a..dbf8c42 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 0000000..a229f55 --- /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 0000000..c5b2401 --- /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 0000000..76e4477 --- /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 527ebf9..1a89acc 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 16aa0c5..401e6cb 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 8f3c777..12caf0c 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 66d6824..f418c5a 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 987cd24..c269219 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 cfa669d..3e854ca 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 7865516..06cd05c 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 1728c67..b1ceb46 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 0000000..adfd005 --- /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 bb487f6..d9dd70a 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 f47b6ab..901f867 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 fc3748c..9145d92 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 69604f9..96b58d8 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 cadba32..2fe3f5b 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 d1a13aa..4ebf4e8 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 7bc774f..7af15f0 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 f58b579..9126c2c 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 2a06f51..fa77471 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 9df0e1a..e2e1147 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 2f46313..10884a7 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 ba93e5d..88beadf 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 639e683..9bb2196 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 ea84829..db609f6 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 dedf824..d43d13e 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 2e6034b..a5b3452 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 2cdb4e2..7f46a10 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 c9d0b26..808c31c 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 eee8c19..c616c6a 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 8d76680..9a30f59 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 55f2740..049f3bd 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 25316be..c0b4eba 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 b1a0a5e..ec5c106 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 9c6059b..26f426ba 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 d1cb461..b9ece21 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 4b9496e..01af67d 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 fb48df3..de56166 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 fbd9929..8997e66 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 9497f97..78a56db 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 f3cb206..630a093 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 0ea0a58..24ad69e 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 14769c1..b1d8800 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 6c874f4..e63291b 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 a7020d8..f79a0f4 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 8edd634..73b584b 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -45,6 +45,9 @@ protected: if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) if (ContainsLocation(DD->getDeclaratorInfo())) return ContainsLoc; + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + if (ContainsLocation(TD->getTypeDeclaratorInfo())) + return ContainsLoc; return CheckRange(D->getSourceRange()); } @@ -57,11 +60,6 @@ protected: } template <typename T> - bool ContainsLocation(T Node) { - return CheckRange(Node) == ContainsLoc; - } - - template <typename T> bool isAfterLocation(T Node) { return CheckRange(Node) == AfterLoc; } @@ -69,6 +67,11 @@ protected: public: LocResolverBase(ASTContext &ctx, SourceLocation loc) : Ctx(ctx), Loc(loc) {} + + template <typename T> + bool ContainsLocation(T Node) { + return CheckRange(Node) == ContainsLoc; + } #ifndef NDEBUG /// \brief Debugging output. @@ -89,6 +92,7 @@ public: StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent) : LocResolverBase(ctx, loc), Parent(parent) {} + ASTLocation VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node); ASTLocation VisitDeclStmt(DeclStmt *Node); ASTLocation VisitStmt(Stmt *Node); @@ -109,6 +113,7 @@ public: ASTLocation VisitVarDecl(VarDecl *D); ASTLocation VisitFunctionDecl(FunctionDecl *D); ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D); + ASTLocation VisitTypedefDecl(TypedefDecl *D); ASTLocation VisitDecl(Decl *D); }; @@ -132,6 +137,25 @@ public: } // anonymous namespace ASTLocation +StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + if (Node->isArgumentType()) { + DeclaratorInfo *DInfo = Node->getArgumentTypeInfo(); + if (ContainsLocation(DInfo)) + return ResolveInDeclarator(Parent, Node, DInfo); + } else { + Expr *SubNode = Node->getArgumentExpr(); + if (ContainsLocation(SubNode)) + return Visit(SubNode); + } + + return ASTLocation(Parent, Node); +} + + +ASTLocation StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { assert(ContainsLocation(Node) && "Should visit only after verifying that loc is in range"); @@ -278,6 +302,16 @@ ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { return ASTLocation(D); } +ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + if (ContainsLocation(D->getTypeDeclaratorInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeDeclaratorInfo()); + + return ASTLocation(D); +} + ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); @@ -529,11 +563,40 @@ void LocResolverBase::print(Stmt *Node) { /// \brief Returns the AST node that a source location points to. /// ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, - Decl *RelativeToDecl) { + ASTLocation *LastLoc) { if (Loc.isInvalid()) return ASTLocation(); - if (RelativeToDecl) - return DeclLocResolver(Ctx, Loc).Visit(RelativeToDecl); + if (LastLoc && LastLoc->isValid()) { + DeclContext *DC = 0; + + if (Decl *Dcl = LastLoc->dyn_AsDecl()) { + DC = Dcl->getDeclContext(); + } else if (LastLoc->isStmt()) { + Decl *Parent = LastLoc->getParentDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Parent)) + DC = FD; + else { + // This is needed to handle statements within an initializer. + // Example: + // void func() { long double fabsf = __builtin_fabsl(__x); } + // In this case, the 'parent' of __builtin_fabsl is fabsf. + DC = Parent->getDeclContext(); + } + } else { // We have 'N_NamedRef' or 'N_Type' + DC = LastLoc->getParentDecl()->getDeclContext(); + } + assert(DC && "Missing DeclContext"); + + FunctionDecl *FD = dyn_cast<FunctionDecl>(DC); + DeclLocResolver DLocResolver(Ctx, Loc); + + if (FD && FD->isThisDeclarationADefinition() && + DLocResolver.ContainsLocation(FD)) { + return DLocResolver.VisitFunctionDecl(FD); + } + // Fall through and try the slow path... + // FIXME: Optimize more cases. + } return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); } diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index c9a10dc..df71276 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -15,7 +15,7 @@ #include "clang/Basic/FileManager.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include <cstdio> diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index e264efa..dc7d95e 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -974,11 +974,11 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, /// 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. -static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, - Preprocessor &PP) { +bool Preprocessor::ConcatenateIncludeName( + llvm::SmallVector<char, 128> &FilenameBuffer) { Token CurTok; - PP.Lex(CurTok); + Lex(CurTok); while (CurTok.isNot(tok::eom)) { // Append the spelling of this token to the buffer. If there was a space // before it, add it now. @@ -990,7 +990,7 @@ static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, FilenameBuffer.resize(PreAppendSize+CurTok.getLength()); const char *BufPtr = &FilenameBuffer[PreAppendSize]; - unsigned ActualLen = PP.getSpelling(CurTok, BufPtr); + unsigned ActualLen = getSpelling(CurTok, BufPtr); // If the token was spelled somewhere else, copy it into FilenameBuffer. if (BufPtr != &FilenameBuffer[PreAppendSize]) @@ -1004,12 +1004,12 @@ static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, if (CurTok.is(tok::greater)) return false; - PP.Lex(CurTok); + Lex(CurTok); } // If we hit the eom marker, emit an error and return true so that the caller // knows the EOM has been read. - PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename); + Diag(CurTok.getLocation(), diag::err_pp_expects_filename); return true; } @@ -1047,7 +1047,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // This could be a <foo/bar.h> file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); - if (ConcatenateIncludeName(FilenameBuffer, *this)) + if (ConcatenateIncludeName(FilenameBuffer)) return; // Found <eom> but no ">"? Diagnostic already emitted. FilenameStart = FilenameBuffer.data(); FilenameEnd = FilenameStart + FilenameBuffer.size(); diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 908385c..a74396c 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -71,6 +71,61 @@ struct DefinedTracker { IdentifierInfo *TheMacro; }; +/// EvaluateDefined - Process a 'defined(sym)' expression. +static bool EvaluateDefined(PPValue &Result, Token &PeekTok, + DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { + IdentifierInfo *II; + Result.setBegin(PeekTok.getLocation()); + + // Get the next token, don't expand it. + PP.LexUnexpandedToken(PeekTok); + + // Two options, it can either be a pp-identifier or a (. + SourceLocation LParenLoc; + if (PeekTok.is(tok::l_paren)) { + // Found a paren, remember we saw it and skip it. + LParenLoc = PeekTok.getLocation(); + PP.LexUnexpandedToken(PeekTok); + } + + // If we don't have a pp-identifier now, this is an error. + if ((II = PeekTok.getIdentifierInfo()) == 0) { + PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); + return true; + } + + // Otherwise, we got an identifier, is it defined to something? + Result.Val = II->hasMacroDefinition(); + Result.Val.setIsUnsigned(false); // Result is signed intmax_t. + + // If there is a macro, mark it used. + if (Result.Val != 0 && ValueLive) { + MacroInfo *Macro = PP.getMacroInfo(II); + Macro->setIsUsed(true); + } + + // Consume identifier. + Result.setEnd(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + + // If we are in parens, ensure we have a trailing ). + if (LParenLoc.isValid()) { + if (PeekTok.isNot(tok::r_paren)) { + PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined"; + PP.Diag(LParenLoc, diag::note_matching) << "("; + return true; + } + // Consume the ). + Result.setEnd(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + } + + // Success, remember that we saw defined(X). + DT.State = DefinedTracker::DefinedMacro; + DT.TheMacro = II; + return false; +} + /// EvaluateValue - Evaluate the token PeekTok (and any others needed) and /// return the computed value in Result. Return true if there was an error /// parsing. This function also returns information about the form of the @@ -87,10 +142,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { - // If this identifier isn't 'defined' and it wasn't macro expanded, it turns - // into a simple 0, unless it is the C++ keyword "true", in which case it - // turns into "1". - if (!II->isStr("defined")) { + if (II->isStr("defined")) { + // Handle "defined X" and "defined(X)". + return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); + } else { + // If this identifier isn't 'defined' or one of the special + // preprocessor keywords and it wasn't macro expanded, it turns + // into a simple 0, unless it is the C++ keyword "true", in which case it + // turns into "1". if (ValueLive) PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; Result.Val = II->getTokenID() == tok::kw_true; @@ -99,57 +158,6 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, PP.LexNonComment(PeekTok); return false; } - - // Handle "defined X" and "defined(X)". - Result.setBegin(PeekTok.getLocation()); - - // Get the next token, don't expand it. - PP.LexUnexpandedToken(PeekTok); - - // Two options, it can either be a pp-identifier or a (. - SourceLocation LParenLoc; - if (PeekTok.is(tok::l_paren)) { - // Found a paren, remember we saw it and skip it. - LParenLoc = PeekTok.getLocation(); - PP.LexUnexpandedToken(PeekTok); - } - - // If we don't have a pp-identifier now, this is an error. - if ((II = PeekTok.getIdentifierInfo()) == 0) { - PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); - return true; - } - - // Otherwise, we got an identifier, is it defined to something? - Result.Val = II->hasMacroDefinition(); - Result.Val.setIsUnsigned(false); // Result is signed intmax_t. - - // If there is a macro, mark it used. - if (Result.Val != 0 && ValueLive) { - MacroInfo *Macro = PP.getMacroInfo(II); - Macro->setIsUsed(true); - } - - // Consume identifier. - Result.setEnd(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - - // If we are in parens, ensure we have a trailing ). - if (LParenLoc.isValid()) { - if (PeekTok.isNot(tok::r_paren)) { - PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen); - PP.Diag(LParenLoc, diag::note_matching) << "("; - return true; - } - // Consume the ). - Result.setEnd(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - } - - // Success, remember that we saw defined(X). - DT.State = DefinedTracker::DefinedMacro; - DT.TheMacro = II; - return false; } switch (PeekTok.getKind()) { diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 7ddf215..699b701 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -64,8 +64,10 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); // Clang Extensions. - Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); - Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); + Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); + Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); + Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); } /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token @@ -503,6 +505,117 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { } } +/// EvaluateHasIncludeCommon - Process a '__has_include("path")' +/// or '__has_include_next("path")' expression. +/// Returns true if successful. +static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, + IdentifierInfo *II, Preprocessor &PP, + const DirectoryLookup *LookupFrom) { + SourceLocation LParenLoc; + + // Get '('. + PP.LexNonComment(Tok); + + // Ensure we have a '('. + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); + return false; + } + + // Save '(' location for possible missing ')' message. + LParenLoc = Tok.getLocation(); + + // Get the file name. + PP.getCurrentLexer()->LexIncludeFilename(Tok); + + // Reserve a buffer to get the spelling. + llvm::SmallVector<char, 128> FilenameBuffer; + const char *FilenameStart, *FilenameEnd; + + switch (Tok.getKind()) { + case tok::eom: + // If the token kind is EOM, the error has already been diagnosed. + return false; + + case tok::angle_string_literal: + case tok::string_literal: { + FilenameBuffer.resize(Tok.getLength()); + FilenameStart = &FilenameBuffer[0]; + unsigned Len = PP.getSpelling(Tok, FilenameStart); + FilenameEnd = FilenameStart+Len; + break; + } + + case tok::less: + // This could be a <foo/bar.h> file coming from a macro expansion. In this + // case, glue the tokens together into FilenameBuffer and interpret those. + FilenameBuffer.push_back('<'); + if (PP.ConcatenateIncludeName(FilenameBuffer)) + return false; // Found <eom> but no ">"? Diagnostic already emitted. + FilenameStart = FilenameBuffer.data(); + FilenameEnd = FilenameStart + FilenameBuffer.size(); + break; + default: + PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); + return false; + } + + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), + FilenameStart, FilenameEnd); + // If GetIncludeFilenameSpelling set the start ptr to null, there was an + // error. + if (FilenameStart == 0) { + return false; + } + + // Search include directories. + const DirectoryLookup *CurDir; + const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd, + isAngled, LookupFrom, CurDir); + + // Get the result value. Result = true means the file exists. + Result = File != 0; + + // Get ')'. + PP.LexNonComment(Tok); + + // Ensure we have a trailing ). + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(LParenLoc, diag::note_matching) << "("; + return false; + } + + return true; +} + +/// EvaluateHasInclude - Process a '__has_include("path")' expression. +/// Returns true if successful. +static bool EvaluateHasInclude(bool &Result, Token &Tok, IdentifierInfo *II, + Preprocessor &PP) { + return(EvaluateHasIncludeCommon(Result, Tok, II, PP, NULL)); +} + +/// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression. +/// Returns true if successful. +static bool EvaluateHasIncludeNext(bool &Result, Token &Tok, + IdentifierInfo *II, Preprocessor &PP) { + // __has_include_next is like __has_include, except that we start + // searching after the current found directory. If we can't do this, + // issue a diagnostic. + const DirectoryLookup *Lookup = PP.GetCurDirLookup(); + if (PP.isInPrimaryFile()) { + Lookup = 0; + PP.Diag(Tok, diag::pp_include_next_in_primary); + } else if (Lookup == 0) { + PP.Diag(Tok, diag::pp_include_next_absolute_path); + } else { + // Start looking up in the next directory. + ++Lookup; + } + + return(EvaluateHasIncludeCommon(Result, Tok, II, PP, Lookup)); +} /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. @@ -671,6 +784,20 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { sprintf(TmpBuffer, "%d", (int)Value); Tok.setKind(tok::numeric_constant); CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); + } else if (II == Ident__has_include || + II == Ident__has_include_next) { + // The argument to these two builtins should be a parenthesized + // file name string literal using angle brackets (<>) or + // double-quotes (""). + bool Value = false; + bool IsValid; + if (II == Ident__has_include) + IsValid = EvaluateHasInclude(Value, Tok, II, *this); + else + IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this); + sprintf(TmpBuffer, "%d", (int)Value); + Tok.setKind(tok::numeric_constant); + CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else { assert(0 && "Unknown identifier!"); } diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 224a31c..344ce9e 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/AttributeList.h" #include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, @@ -52,94 +53,58 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { AttrName = AttrName.substr(2, AttrName.size() - 4); // FIXME: Hand generating this is neither smart nor efficient. - const char *Str = AttrName.data(); - switch (AttrName.size()) { - case 4: - if (!memcmp(Str, "weak", 4)) return AT_weak; - if (!memcmp(Str, "pure", 4)) return AT_pure; - if (!memcmp(Str, "mode", 4)) return AT_mode; - if (!memcmp(Str, "used", 4)) return AT_used; - break; - case 5: - if (!memcmp(Str, "alias", 5)) return AT_alias; - if (!memcmp(Str, "const", 5)) return AT_const; - break; - case 6: - if (!memcmp(Str, "packed", 6)) return AT_packed; - if (!memcmp(Str, "malloc", 6)) return AT_malloc; - if (!memcmp(Str, "format", 6)) return AT_format; - if (!memcmp(Str, "unused", 6)) return AT_unused; - if (!memcmp(Str, "blocks", 6)) return AT_blocks; - break; - case 7: - if (!memcmp(Str, "aligned", 7)) return AT_aligned; - if (!memcmp(Str, "cleanup", 7)) return AT_cleanup; - if (!memcmp(Str, "nodebug", 7)) return AT_nodebug; - if (!memcmp(Str, "nonnull", 7)) return AT_nonnull; - if (!memcmp(Str, "nothrow", 7)) return AT_nothrow; - if (!memcmp(Str, "objc_gc", 7)) return AT_objc_gc; - if (!memcmp(Str, "regparm", 7)) return AT_regparm; - if (!memcmp(Str, "section", 7)) return AT_section; - if (!memcmp(Str, "stdcall", 7)) return AT_stdcall; - break; - case 8: - if (!memcmp(Str, "annotate", 8)) return AT_annotate; - if (!memcmp(Str, "noreturn", 8)) return AT_noreturn; - if (!memcmp(Str, "noinline", 8)) return AT_noinline; - if (!memcmp(Str, "fastcall", 8)) return AT_fastcall; - if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet; - if (!memcmp(Str, "sentinel", 8)) return AT_sentinel; - if (!memcmp(Str, "NSObject", 8)) return AT_nsobject; - break; - case 9: - if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; - if (!memcmp(Str, "dllexport", 9)) return AT_dllexport; - if (!memcmp(Str, "may_alias", 9)) return IgnoredAttribute; // FIXME: TBAA - break; - case 10: - if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; - if (!memcmp(Str, "visibility", 10)) return AT_visibility; - if (!memcmp(Str, "destructor", 10)) return AT_destructor; - if (!memcmp(Str, "format_arg", 10)) return AT_format_arg; - if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline; - break; - case 11: - if (!memcmp(Str, "weak_import", 11)) return AT_weak_import; - if (!memcmp(Str, "vector_size", 11)) return AT_vector_size; - if (!memcmp(Str, "constructor", 11)) return AT_constructor; - if (!memcmp(Str, "unavailable", 11)) return AT_unavailable; - break; - case 12: - if (!memcmp(Str, "overloadable", 12)) return AT_overloadable; - break; - case 13: - if (!memcmp(Str, "address_space", 13)) return AT_address_space; - if (!memcmp(Str, "always_inline", 13)) return AT_always_inline; - if (!memcmp(Str, "vec_type_hint", 13)) return IgnoredAttribute; - break; - case 14: - if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception; - break; - case 15: - if (!memcmp(Str, "ext_vector_type", 15)) return AT_ext_vector_type; - break; - case 17: - if (!memcmp(Str, "transparent_union", 17)) return AT_transparent_union; - if (!memcmp(Str, "analyzer_noreturn", 17)) return AT_analyzer_noreturn; - break; - case 18: - if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result; - break; - case 19: - if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained; - if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained; - break; - case 20: - if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size; - case 22: - if (!memcmp(Str, "no_instrument_function", 22)) - return AT_no_instrument_function; - break; - } - return UnknownAttribute; + return llvm::StringSwitch<AttributeList::Kind>(AttrName) + .Case("weak", AT_weak) + .Case("pure", AT_pure) + .Case("mode", AT_mode) + .Case("used", AT_used) + .Case("alias", AT_alias) + .Case("const", AT_const) + .Case("packed", AT_packed) + .Case("malloc", AT_malloc) + .Case("format", AT_format) + .Case("unused", AT_unused) + .Case("blocks", AT_blocks) + .Case("aligned", AT_aligned) + .Case("cleanup", AT_cleanup) + .Case("nodebug", AT_nodebug) + .Case("nonnull", AT_nonnull) + .Case("nothrow", AT_nothrow) + .Case("objc_gc", AT_objc_gc) + .Case("regparm", AT_regparm) + .Case("section", AT_section) + .Case("stdcall", AT_stdcall) + .Case("annotate", AT_annotate) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("fastcall", AT_fastcall) + .Case("iboutlet", AT_IBOutlet) + .Case("sentinel", AT_sentinel) + .Case("NSObject", AT_nsobject) + .Case("dllimport", AT_dllimport) + .Case("dllexport", AT_dllexport) + .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("deprecated", AT_deprecated) + .Case("visibility", AT_visibility) + .Case("destructor", AT_destructor) + .Case("format_arg", AT_format_arg) + .Case("gnu_inline", AT_gnu_inline) + .Case("weak_import", AT_weak_import) + .Case("vector_size", AT_vector_size) + .Case("constructor", AT_constructor) + .Case("unavailable", AT_unavailable) + .Case("overloadable", AT_overloadable) + .Case("address_space", AT_address_space) + .Case("always_inline", AT_always_inline) + .Case("vec_type_hint", IgnoredAttribute) + .Case("objc_exception", AT_objc_exception) + .Case("ext_vector_type", AT_ext_vector_type) + .Case("transparent_union", AT_transparent_union) + .Case("analyzer_noreturn", AT_analyzer_noreturn) + .Case("warn_unused_result", AT_warn_unused_result) + .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_returns_retained", AT_cf_returns_retained) + .Case("reqd_work_group_size", AT_reqd_wg_size) + .Case("no_instrument_function", AT_no_instrument_function) + .Default(UnknownAttribute); } diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index b8422aa..3436900 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -446,3 +446,28 @@ bool DeclSpec::isMissingDeclaratorOk() { || tst == TST_enum ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; } + +void UnqualifiedId::clear() { + if (Kind == IK_TemplateId) + TemplateId->Destroy(); + + Kind = IK_Identifier; + Identifier = 0; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); +} + +void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]) { + Kind = IK_OperatorFunctionId; + StartLocation = OperatorLoc; + EndLocation = OperatorLoc; + OperatorFunctionId.Operator = Op; + for (unsigned I = 0; I != 3; ++I) { + OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); + + if (SymbolLocations[I].isValid()) + EndLocation = SymbolLocations[I]; + } +} diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 71b22ca..1e7d397 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -161,9 +161,8 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, TemplateNameKind MinimalAction::isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, TemplateTy &TemplateDecl) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b56c331..e905553 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -336,10 +336,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd, - bool RequireSemi) { + SourceLocation &DeclEnd) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -347,32 +346,109 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); - ParseDeclarator(DeclaratorInfo); + DeclGroupPtrTy DG = ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, + &DeclEnd); + return DG; +} - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); +/// ParseDeclGroup - Having concluded that this is either a function +/// definition or a group of object declarations, actually parse the +/// result. +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, + unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd) { + // Parse the first declarator. + ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); + ParseDeclarator(D); + + // Bail out if the first declarator didn't seem well-formed. + if (!D.hasName() && !D.mayOmitIdentifier()) { + // Skip until ; or }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclGroupPtrTy(); + } + + if (AllowFunctionDefinitions && D.isFunctionDeclarator()) { + if (isDeclarationAfterDeclarator()) { + // Fall though. We have to check this first, though, because + // __attribute__ might be the start of a function definition in + // (extended) K&R C. + } else if (isStartOfFunctionDefinition()) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } - DeclEnd = Tok.getLocation(); + DeclPtrTy TheDecl = ParseFunctionDefinition(D); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + } - // If the client wants to check what comes after the declaration, just return - // immediately without checking anything! - if (!RequireSemi) return DG; + llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; + DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + D.complete(FirstDecl); + if (FirstDecl.get()) + DeclsInGroup.push_back(FirstDecl); - if (Tok.is(tok::semi)) { + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + while (Tok.is(tok::comma)) { + // Consume the comma. ConsumeToken(); - return DG; + + // Parse the next declarator. + D.clear(); + + // Accept attributes in an init-declarator. In the first declarator in a + // declaration, these would be part of the declspec. In subsequent + // declarators, they become part of the declarator itself, so that they + // don't apply to declarators after *this* one. Examples: + // short __attribute__((common)) var; -> declspec + // short var __attribute__((common)); -> declarator + // short x, __attribute__((common)) var; -> declarator + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseAttributes(&Loc); + D.AddAttributes(AttrList, Loc); + } + + ParseDeclarator(D); + + DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); + if (ThisDecl.get()) + DeclsInGroup.push_back(ThisDecl); } - Diag(Tok, diag::err_expected_semi_declaration); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return DG; + if (DeclEnd) + *DeclEnd = Tok.getLocation(); + + if (Context != Declarator::ForContext && + ExpectAndConsume(tok::semi, + Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + + return Actions.FinalizeDeclaratorGroup(CurScope, DS, + DeclsInGroup.data(), + DeclsInGroup.size()); } /// \brief Parse 'declaration' after parsing 'declaration-specifiers @@ -498,63 +574,6 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, return ThisDecl; } -/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after -/// parsing 'declaration-specifiers declarator'. This method is split out this -/// way to handle the ambiguity between top-level function-definitions and -/// declarations. -/// -/// init-declarator-list: [C99 6.7] -/// init-declarator -/// init-declarator-list ',' init-declarator -/// -/// According to the standard grammar, =default and =delete are function -/// definitions, but that definitely doesn't fit with the parser here. -/// -Parser::DeclGroupPtrTy Parser:: -ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { - // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls - // that we parse together here. - llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; - - // At this point, we know that it is not a function definition. Parse the - // rest of the init-declarator-list. - while (1) { - DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); - if (ThisDecl.get()) - DeclsInGroup.push_back(ThisDecl); - - // If we don't have a comma, it is either the end of the list (a ';') or an - // error, bail out. - if (Tok.isNot(tok::comma)) - break; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - D.clear(); - - // Accept attributes in an init-declarator. In the first declarator in a - // declaration, these would be part of the declspec. In subsequent - // declarators, they become part of the declarator itself, so that they - // don't apply to declarators after *this* one. Examples: - // short __attribute__((common)) var; -> declspec - // short var __attribute__((common)); -> declarator - // short x, __attribute__((common)) var; -> declarator - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); - D.AddAttributes(AttrList, Loc); - } - - ParseDeclarator(D); - } - - return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(), - DeclsInGroup.data(), - DeclsInGroup.size()); -} - /// ParseSpecifierQualifierList /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] @@ -1468,8 +1487,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// void Parser:: -ParseStructDeclaration(DeclSpec &DS, - llvm::SmallVectorImpl<FieldDeclarator> &Fields) { +ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. @@ -1489,9 +1507,17 @@ ParseStructDeclaration(DeclSpec &DS, } // Read struct-declarators until we find the semicolon. - Fields.push_back(FieldDeclarator(DS)); + bool FirstDeclarator = true; while (1) { - FieldDeclarator &DeclaratorInfo = Fields.back(); + ParsingDeclRAIIObject PD(*this); + FieldDeclarator DeclaratorInfo(DS); + + // Attributes are only allowed here on successive declarators. + if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseAttributes(&Loc); + DeclaratorInfo.D.AddAttributes(AttrList, Loc); + } /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression @@ -1514,6 +1540,10 @@ ParseStructDeclaration(DeclSpec &DS, DeclaratorInfo.D.AddAttributes(AttrList, Loc); } + // We're done with this declarator; invoke the callback. + DeclPtrTy D = Fields.invoke(DeclaratorInfo); + PD.complete(D); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) @@ -1522,15 +1552,7 @@ ParseStructDeclaration(DeclSpec &DS, // Consume the comma. ConsumeToken(); - // Parse the next declarator. - Fields.push_back(FieldDeclarator(DS)); - - // Attributes are only allowed on the second declarator. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); - Fields.back().D.AddAttributes(AttrList, Loc); - } + FirstDeclarator = false; } } @@ -1562,7 +1584,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, << DeclSpec::getSpecifierName((DeclSpec::TST)TagType); llvm::SmallVector<DeclPtrTy, 32> FieldDecls; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; // While we still have something to read, read the declarations in the struct. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -1578,28 +1599,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Parse all the comma separated declarators. DeclSpec DS; - FieldDeclarators.clear(); + if (!Tok.is(tok::at)) { - ParseStructDeclaration(DS, FieldDeclarators); - - // Convert them all to fields. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - DeclPtrTy Field; - // Install the declarator into the current TagDecl. - if (FD.D.getExtension()) { - // Silences extension warnings - ExtensionRAIIObject O(Diags); - Field = Actions.ActOnField(CurScope, TagDecl, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); - } else { - Field = Actions.ActOnField(CurScope, TagDecl, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); + struct CFieldCallback : FieldCallback { + Parser &P; + DeclPtrTy TagDecl; + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls; + + CFieldCallback(Parser &P, DeclPtrTy TagDecl, + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls) : + P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} + + virtual DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the current TagDecl. + DeclPtrTy Field = P.Actions.ActOnField(P.CurScope, TagDecl, + FD.D.getDeclSpec().getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + FieldDecls.push_back(Field); + return Field; } - FieldDecls.push_back(Field); - } + } Callback(*this, TagDecl, FieldDecls); + + ParseStructDeclaration(DS, Callback); } else { // Handle @defs ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { @@ -2107,7 +2128,6 @@ void Parser::ParseDeclarator(Declarator &D) { /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { - if (Diags.hasAllExtensionsSilenced()) D.setExtension(); // C++ member pointers start with a '::' or a nested-name. @@ -2270,97 +2290,47 @@ void Parser::ParseDeclaratorInternal(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLang().CPlusPlus) { - if (D.mayHaveIdentifier()) { - // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet() || - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, - true); - if (afterCXXScope) { - // Change the declaration context for name lookup, until this function - // is exited (and the declarator has been parsed). - DeclScopeObj.EnterDeclaratorScope(); - } - - if (Tok.is(tok::identifier)) { - assert(Tok.getIdentifierInfo() && "Not an identifier?"); - - // If this identifier is the name of the current class, it's a - // constructor name. - if (!D.getDeclSpec().hasTypeSpecifier() && - Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) { - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, SS), - Tok.getLocation()); - // This is a normal identifier. - } else - D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - - D.setTemplateId(TemplateId); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::kw_operator)) { - SourceLocation OperatorLoc = Tok.getLocation(); - SourceLocation EndLoc; - - // First try the name of an overloaded operator - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) { - D.setOverloadedOperator(Op, OperatorLoc, EndLoc); - } else { - // This must be a conversion function (C++ [class.conv.fct]). - if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc)) - D.setConversionFunction(ConvType, OperatorLoc, EndLoc); - else { - D.SetIdentifier(0, Tok.getLocation()); - } - } - goto PastIdentifier; - } else if (Tok.is(tok::tilde)) { - // This should be a C++ destructor. - SourceLocation TildeLoc = ConsumeToken(); - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { - // FIXME: Inaccurate. - SourceLocation NameLoc = Tok.getLocation(); - SourceLocation EndLoc; - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - TypeResult Type = ParseClassName(EndLoc, SS, true); - if (Type.isInvalid()) - D.SetIdentifier(0, TildeLoc); - else - D.setDestructor(Type.get(), TildeLoc, NameLoc); - } else { - Diag(Tok, diag::err_destructor_class_name); - D.SetIdentifier(0, TildeLoc); - } - goto PastIdentifier; - } - - // If we reached this point, token is not identifier and not '~'. - - if (afterCXXScope) { - Diag(Tok, diag::err_expected_unqualified_id); + if (getLang().CPlusPlus && D.mayHaveIdentifier()) { + // ParseDeclaratorInternal might already have parsed the scope. + bool afterCXXScope = D.getCXXScopeSpec().isSet() || + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); + if (afterCXXScope) { + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + // We found something that indicates the start of an unqualified-id. + // Parse that unqualified-id. + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), + /*ObjectType=*/0, + D.getName())) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); - goto PastIdentifier; + } else { + // Parsed the unqualified-id; update range information and move along. + if (D.getSourceRange().getBegin().isInvalid()) + D.SetRangeBegin(D.getName().getSourceRange().getBegin()); + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); } + goto PastIdentifier; } - } - - // If we reached this point, we are either in C/ObjC or the token didn't - // satisfy any of the C++-specific checks. - if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { assert(!getLang().CPlusPlus && "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { + goto PastIdentifier; + } + + if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' @@ -2374,7 +2344,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); else if (getLang().CPlusPlus) - Diag(Tok, diag::err_expected_unqualified_id); + Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus; else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); @@ -2623,6 +2593,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, SourceLocation DSStart = Tok.getLocation(); // Parse the declaration-specifiers. + // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS; // If the caller parsed attributes for the first argument, add them now. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d381e3e..91f8686 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -323,6 +323,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SkipUntil(tok::semi); return DeclPtrTy(); } + // FIXME: what about conversion functions? } else if (Tok.is(tok::identifier)) { // Parse identifier. TargetName = Tok.getIdentifierInfo(); @@ -589,6 +590,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; @@ -596,6 +599,56 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // The name was supposed to refer to a template, but didn't. + // Eat the template argument list and try to continue parsing this as + // a class (or template thereof). + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + true, LAngleLoc, + TemplateArgs, TemplateArgIsType, + TemplateArgLocations, RAngleLoc)) { + // We couldn't parse the template argument list at all, so don't + // try to give any location information for the list. + LAngleLoc = RAngleLoc = SourceLocation(); + } + + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : 2) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + + // Strip off the last template parameter list if it was empty, since + // we've removed its template argument list. + if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { + if (TemplateParams && TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + } + } else if (TemplateInfo.Kind + == ParsedTemplateInfo::ExplicitInstantiation) { + // Pretend this is just a forward declaration. + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc + = SourceLocation(); + const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc + = SourceLocation(); + } + + + } } else if (Tok.is(tok::annot_template_id)) { TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); @@ -660,7 +713,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Create the tag portion of the class or class template. Action::DeclResult TagOrTempResult = true; // invalid Action::TypeResult TypeResult = true; // invalid - TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; // FIXME: When TUK == TUK_Reference and we have a template-id, we need // to turn that template-id into a type. @@ -1047,7 +1099,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); Action::MultiTemplateParamsArg TemplateParams(Actions, @@ -1060,7 +1112,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - Declarator DeclaratorInfo(DS, Declarator::MemberContext); + ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); if (Tok.isNot(tok::colon)) { // Parse the first declarator. @@ -1179,6 +1231,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); } + DeclaratorInfo.complete(ThisDecl); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 8be89a8..95a0e98 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -340,7 +340,18 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Eat the colon. ColonLoc = ConsumeToken(); } - + + if ((OpToken.is(tok::periodstar) || OpToken.is(tok::arrowstar)) + && Tok.is(tok::identifier)) { + CXXScopeSpec SS; + if (Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), CurScope, &SS)) { + const char *Opc = OpToken.is(tok::periodstar) ? "'.*'" : "'->*'"; + Diag(OpToken, diag::err_pointer_to_member_type) << Opc; + return ExprError(); + } + + } // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could @@ -612,36 +623,39 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } - // Support 'Class.property' notation. - // We don't use isTokObjCMessageIdentifierReceiver(), since it allows - // 'super' (which is inappropriate here). - if (getLang().ObjC1 && - Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope) && - NextToken().is(tok::period)) { - IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo(); - SourceLocation IdentLoc = ConsumeToken(); + // Consume the identifier so that we can see if it is followed by a '(' or + // '.'. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation ILoc = ConsumeToken(); + + // Support 'Class.property' notation. We don't use + // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is + // inappropriate here). + if (getLang().ObjC1 && Tok.is(tok::period) && + Actions.getTypeName(II, ILoc, CurScope)) { SourceLocation DotLoc = ConsumeToken(); - + if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected_property_name); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); - - Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName, - IdentLoc, PropertyLoc); + + Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, + ILoc, PropertyLoc); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } - // Consume the identifier so that we can see if it is followed by a '('. + // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation L = ConsumeToken(); - Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren)); + UnqualifiedId Name; + CXXScopeSpec ScopeSpec; + Name.setIdentifier(&II, ILoc); + Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name, + Tok.is(tok::l_paren), false); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } @@ -954,110 +968,20 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ConsumeToken(); } - if (Tok.is(tok::identifier)) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc, - OpKind, Tok.getLocation(), - *Tok.getIdentifierInfo(), - ObjCImpDecl, &SS); - ConsumeToken(); - } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) { - // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T() - - // Consume the tilde. - ConsumeToken(); - - if (!Tok.is(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return ExprError(); - } - - if (NextToken().is(tok::less)) { - // class-name: - // ~ simple-template-id - TemplateTy Template - = Actions.ActOnDependentTemplateName(SourceLocation(), - *Tok.getIdentifierInfo(), - Tok.getLocation(), - SS, - ObjectType); - if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS, - SourceLocation(), true)) - return ExprError(); - - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdToken didn't work?"); - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getAnnotationRange(), - Tok.getAnnotationValue(), - SS, - NextToken().is(tok::l_paren)); - } else { - // class-name: - // ~ identifier - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getLocation(), - Tok.getIdentifierInfo(), - SS, - NextToken().is(tok::l_paren)); - } - - // Consume the identifier or template-id token. - ConsumeToken(); - } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { - // We have a reference to a member operator, e.g., t.operator int or - // t.operator+. - SourceLocation OperatorLoc = Tok.getLocation(); - - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope, - move(LHS), OpLoc, - OpKind, - OperatorLoc, - Op, &SS); - // TryParseOperatorFunctionId already consumed our token, so - // don't bother - } else if (TypeTy *ConvType = ParseConversionFunctionId()) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope, - move(LHS), OpLoc, - OpKind, - OperatorLoc, - ConvType, &SS); - } else { - // Don't emit a diagnostic; ParseConversionFunctionId does it for us - return ExprError(); - } - } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) { - // We have a reference to a member template along with explicitly- - // specified template arguments, e.g., t.f<int>. - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (!LHS.isInvalid()) { - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), - TemplateId->NumArgs); - - LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc); - } - ConsumeToken(); - } else { - Diag(Tok, diag::err_expected_ident); + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/false, + ObjectType, + Name)) return ExprError(); - } + + if (!LHS.isInvalid()) + LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind, + SS, Name, ObjCImpDecl, + Tok.is(tok::l_paren)); + break; } case tok::plusplus: // postfix-expression: postfix-expression '++' diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fa65156..a7ca0c5 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,8 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" + using namespace clang; /// \brief Parse global scope or nested-name-specifier if present. @@ -107,31 +109,58 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, break; SourceLocation TemplateKWLoc = ConsumeToken(); - - if (Tok.isNot(tok::identifier)) { + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + + // If the next token is not '<', we may have a stray 'template' keyword. + // Complain and suggest removing the template keyword, but otherwise + // allow parsing to continue. + if (NextToken().isNot(tok::less)) { + Diag(NextToken().getLocation(), + diag::err_less_after_template_name_in_nested_name_spec) + << Tok.getIdentifierInfo()->getName() + << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc)); + break; + } + + // Consume the identifier. + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) + break; + + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + break; + } else if (Tok.isNot(tok::less)) { + std::string OperatorName = "operator "; + OperatorName += getOperatorSpelling( + TemplateName.OperatorFunctionId.Operator); + Diag(Tok.getLocation(), + diag::err_less_after_template_name_in_nested_name_spec) + << OperatorName + << TemplateName.getSourceRange(); + break; + } + } else { Diag(Tok.getLocation(), diag::err_id_after_template_in_nested_name_spec) << SourceRange(TemplateKWLoc); break; } - if (NextToken().isNot(tok::less)) { - Diag(NextToken().getLocation(), - diag::err_less_after_template_name_in_nested_name_spec) - << Tok.getIdentifierInfo()->getName() - << SourceRange(TemplateKWLoc, Tok.getLocation()); - break; - } - TemplateTy Template - = Actions.ActOnDependentTemplateName(TemplateKWLoc, - *Tok.getIdentifierInfo(), - Tok.getLocation(), SS, + = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType); if (!Template) break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, - &SS, TemplateKWLoc, false)) + &SS, TemplateName, TemplateKWLoc, false)) break; continue; @@ -218,9 +247,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // type-name '<' if (Next.is(tok::less)) { TemplateTy Template; - if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II, - Tok.getLocation(), - &SS, + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, + TemplateName, ObjectType, EnteringContext, Template)) { @@ -230,8 +260,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. - if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), - false)) + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + SourceLocation(), false)) break; continue; } @@ -251,25 +282,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, /// unqualified-id /// qualified-id /// -/// unqualified-id: -/// identifier -/// operator-function-id -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id -/// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id /// '::' template-id /// -/// nested-name-specifier: -/// type-name '::' -/// namespace-name '::' -/// nested-name-specifier identifier '::' -/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] -/// /// NOTE: The standard specifies that, for qualified-id, the parser does not /// expect: /// @@ -307,69 +325,19 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - - // unqualified-id: - // identifier - // operator-function-id - // conversion-function-id - // '~' class-name [TODO] - // template-id - // - switch (Tok.getKind()) { - default: - return ExprError(Diag(Tok, diag::err_expected_unqualified_id)); - - case tok::identifier: { - // Consume the identifier so that we can see if it is followed by a '('. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation L = ConsumeToken(); - return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren), - &SS, isAddressOfOperand); - } - - case tok::kw_operator: { - SourceLocation OperatorLoc = Tok.getLocation(); - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) - return Actions.ActOnCXXOperatorFunctionIdExpr( - CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS, - isAddressOfOperand); - if (TypeTy *Type = ParseConversionFunctionId()) - return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type, - Tok.is(tok::l_paren), SS, - isAddressOfOperand); - - // We already complained about a bad conversion-function-id, - // above. + + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/0, + Name)) return ExprError(); - } - - case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - assert((TemplateId->Kind == TNK_Function_template || - TemplateId->Kind == TNK_Dependent_template_name) && - "A template type name is not an ID expression"); - - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), - TemplateId->NumArgs); - - OwningExprResult Result - = Actions.ActOnTemplateIdExpr(SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc); - ConsumeToken(); // Consume the template-id token - return move(Result); - } - - } // switch. - - assert(0 && "The switch was supposed to take care everything."); + + return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren), + isAddressOfOperand); + } /// ParseCXXCasts - This handles the various ways to cast expressions to another @@ -761,6 +729,473 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { return false; } +/// \brief Finish parsing a C++ unqualified-id that is a template-id of +/// some form. +/// +/// This routine is invoked when a '<' is encountered after an identifier or +/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine +/// whether the unqualified-id is actually a template-id. This routine will +/// then parse the template arguments and form the appropriate template-id to +/// return to the caller. +/// +/// \param SS the nested-name-specifier that precedes this template-id, if +/// we're actually parsing a qualified-id. +/// +/// \param Name for constructor and destructor names, this is the actual +/// identifier that may be a template-name. +/// +/// \param NameLoc the location of the class-name in a constructor or +/// destructor. +/// +/// \param EnteringContext whether we're entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Id as input, describes the template-name or operator-function-id +/// that precedes the '<'. If template arguments were parsed successfully, +/// will be updated with the template-id. +/// +/// \returns true if a parse error occurred, false otherwise. +bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Id) { + assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + + TemplateTy Template; + TemplateNameKind TNK = TNK_Non_template; + switch (Id.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, + Template); + break; + + case UnqualifiedId::IK_ConstructorName: { + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Name, NameLoc); + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template); + break; + } + + case UnqualifiedId::IK_DestructorName: { + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Name, NameLoc); + if (ObjectType) { + Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + TemplateName, ObjectType); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } else { + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template); + + if (TNK == TNK_Non_template && Id.DestructorName == 0) { + // The identifier following the destructor did not refer to a template + // or to a type. Complain. + if (ObjectType) + Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << Name; + else + Diag(NameLoc, diag::err_destructor_class_name); + return true; + } + } + break; + } + + default: + return false; + } + + if (TNK == TNK_Non_template) + return false; + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + &SS, true, LAngleLoc, + TemplateArgs, + TemplateArgIsType, + TemplateArgLocations, + RAngleLoc)) + return true; + + if (Id.getKind() == UnqualifiedId::IK_Identifier || + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) { + // Form a parsed representation of the template-id to be stored in the + // UnqualifiedId. + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + + if (Id.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = Id.Identifier; + TemplateId->Operator = OO_None; + TemplateId->TemplateNameLoc = Id.StartLocation; + } else { + TemplateId->Name = 0; + TemplateId->Operator = Id.OperatorFunctionId.Operator; + TemplateId->TemplateNameLoc = Id.StartLocation; + } + + TemplateId->Template = Template.getAs<void*>(); + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + void **Args = TemplateId->getTemplateArgs(); + bool *ArgIsType = TemplateId->getTemplateArgIsType(); + SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); + Arg != ArgEnd; ++Arg) { + Args[Arg] = TemplateArgs[Arg]; + ArgIsType[Arg] = TemplateArgIsType[Arg]; + ArgLocs[Arg] = TemplateArgLocations[Arg]; + } + + Id.setTemplateId(TemplateId); + return false; + } + + // Bundle the template arguments together. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgIsType.data(), + TemplateArgs.size()); + + // Constructor and destructor names. + Action::TypeResult Type + = Actions.ActOnTemplateIdType(Template, NameLoc, + LAngleLoc, TemplateArgsPtr, + &TemplateArgLocations[0], + RAngleLoc); + if (Type.isInvalid()) + return true; + + if (Id.getKind() == UnqualifiedId::IK_ConstructorName) + Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); + else + Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + + return false; +} + +/// \brief Parse an operator-function-id or conversion-function-id as part +/// of a C++ unqualified-id. +/// +/// This routine is responsible only for parsing the operator-function-id or +/// conversion-function-id; it does not handle template arguments in any way. +/// +/// \code +/// operator-function-id: [C++ 13.5] +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] +/// + - * / % ^ & | ~ +/// ! = < > += -= *= /= %= +/// ^= &= |= << >> >>= <<= == != +/// <= >= && || ++ -- , ->* -> +/// () [] +/// +/// conversion-function-id: [C++ 12.3.2] +/// operator conversion-type-id +/// +/// conversion-type-id: +/// type-specifier-seq conversion-declarator[opt] +/// +/// conversion-declarator: +/// ptr-operator conversion-declarator[opt] +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Result) { + assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); + + // Consume the 'operator' keyword. + SourceLocation KeywordLoc = ConsumeToken(); + + // Determine what kind of operator name we have. + unsigned SymbolIdx = 0; + SourceLocation SymbolLocations[3]; + OverloadedOperatorKind Op = OO_None; + switch (Tok.getKind()) { + case tok::kw_new: + case tok::kw_delete: { + bool isNew = Tok.getKind() == tok::kw_new; + // Consume the 'new' or 'delete'. + SymbolLocations[SymbolIdx++] = ConsumeToken(); + if (Tok.is(tok::l_square)) { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = isNew? OO_Array_New : OO_Array_Delete; + } else { + Op = isNew? OO_New : OO_Delete; + } + break; + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case tok::Token: \ + SymbolLocations[SymbolIdx++] = ConsumeToken(); \ + Op = OO_##Name; \ + break; +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + + case tok::l_paren: { + // Consume the '('. + SourceLocation LParenLoc = ConsumeParen(); + // Consume the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, + LParenLoc); + if (RParenLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LParenLoc; + SymbolLocations[SymbolIdx++] = RParenLoc; + Op = OO_Call; + break; + } + + case tok::l_square: { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = OO_Subscript; + break; + } + + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(CurScope); + + // Consume the operator token. + ConsumeToken(); + + // Don't try to parse any further. + return true; + } + + default: + break; + } + + if (Op != OO_None) { + // We have parsed an operator-function-id. + Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); + return false; + } + + // Parse a conversion-function-id. + // + // conversion-function-id: [C++ 12.3.2] + // operator conversion-type-id + // + // conversion-type-id: + // type-specifier-seq conversion-declarator[opt] + // + // conversion-declarator: + // ptr-operator conversion-declarator[opt] + + // Parse the type-specifier-seq. + DeclSpec DS; + if (ParseCXXTypeSpecifierSeq(DS)) + return true; + + // Parse the conversion-declarator, which is merely a sequence of + // ptr-operators. + Declarator D(DS, Declarator::TypeNameContext); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); + + // Finish up the type. + Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D); + if (Ty.isInvalid()) + return true; + + // Note that this is a conversion-function-id. + Result.setConversionFunctionId(KeywordLoc, Ty.get(), + D.getSourceRange().getEnd()); + return false; +} + +/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the +/// name of an entity. +/// +/// \code +/// unqualified-id: [C++ expr.prim.general] +/// identifier +/// operator-function-id +/// conversion-function-id +/// [C++0x] literal-operator-id [TODO] +/// ~ class-name +/// template-id +/// +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param AllowDestructorName whether we allow parsing of a destructor name. +/// +/// \param AllowConstructorName whether we allow parsing a constructor name. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + TypeTy *ObjectType, + UnqualifiedId &Result) { + // unqualified-id: + // identifier + // template-id (when it hasn't already been annotated) + if (Tok.is(tok::identifier)) { + // Consume the identifier. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (AllowConstructorName && + Actions.isCurrentClassName(*Id, CurScope, &SS)) { + // We have parsed a constructor name. + Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope, + &SS, false), + IdLoc, IdLoc); + } else { + // We have parsed an identifier. + Result.setIdentifier(Id, IdLoc); + } + + // If the next token is a '<', we may have a template. + if (Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, + ObjectType, Result); + + return false; + } + + // unqualified-id: + // template-id (already parsed and annotated) + if (Tok.is(tok::annot_template_id)) { + // FIXME: Could this be a constructor name??? + + // We have already parsed a template-id; consume the annotation token as + // our unqualified-id. + Result.setTemplateId( + static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue())); + ConsumeToken(); + return false; + } + + // unqualified-id: + // operator-function-id + // conversion-function-id + if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) + return true; + + // If we have an operator-function-id and the next token is a '<', we may + // have a + // + // template-id: + // operator-function-id < template-argument-list[opt] > + if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId && + Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), + EnteringContext, ObjectType, + Result); + + return false; + } + + if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { + // C++ [expr.unary.op]p10: + // There is an ambiguity in the unary-expression ~X(), where X is a + // class-name. The ambiguity is resolved in favor of treating ~ as a + // unary complement rather than treating ~X as referring to a destructor. + + // Parse the '~'. + SourceLocation TildeLoc = ConsumeToken(); + + // Parse the class-name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_destructor_class_name); + return true; + } + + // Parse the class-name (or template-name in a simple-template-id). + IdentifierInfo *ClassName = Tok.getIdentifierInfo(); + SourceLocation ClassNameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + Result.setDestructorName(TildeLoc, 0, ClassNameLoc); + return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, + EnteringContext, ObjectType, Result); + } + + // Note that this is a destructor name. + Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, + CurScope, &SS); + if (!Ty) { + if (ObjectType) + Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << ClassName; + else + Diag(ClassNameLoc, diag::err_destructor_class_name); + return true; + } + + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); + return false; + } + + Diag(Tok, diag::err_expected_unqualified_id) + << getLang().CPlusPlus; + return true; +} + /// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded /// operator name (C++ [over.oper]). If successful, returns the /// predefined identifier that corresponds to that overloaded diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 2e0cd6d..b043dd99 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -305,51 +305,68 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, if (Tok.is(tok::l_paren)) ParseObjCPropertyAttribute(OCDS); + struct ObjCPropertyCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + llvm::SmallVectorImpl<DeclPtrTy> &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, + llvm::SmallVectorImpl<DeclPtrTy> &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + MethodImplKind(MethodImplKind) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + DeclPtrTy Property = + P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, + GetterSel, SetterSel, IDecl, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } + } Callback(*this, interfaceDecl, allProperties, + OCDS, AtLoc, MethodImplKind); + // Parse all the comma separated declarators. DeclSpec DS; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; - ParseStructDeclaration(DS, FieldDeclarators); + ParseStructDeclaration(DS, Callback); ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", tok::at); - - // Convert them all to property declarations. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - if (FD.D.getIdentifier() == 0) { - Diag(AtLoc, diag::err_objc_property_requires_field_name) - << FD.D.getSourceRange(); - continue; - } - if (FD.BitfieldSize) { - Diag(AtLoc, diag::err_objc_property_bitfield) - << FD.D.getSourceRange(); - continue; - } - - // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = - OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); - - Selector GetterSel = - PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); - Selector SetterSel; - if (SetterName) - SetterSel = PP.getSelectorTable().getSelector(1, &SetterName); - else - SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), - FD.D.getIdentifier()); - bool isOverridingProperty = false; - DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS, - GetterSel, SetterSel, - interfaceDecl, - &isOverridingProperty, - MethodImplKind); - if (!isOverridingProperty) - allProperties.push_back(Property); - } break; } } @@ -681,6 +698,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, DeclPtrTy IDecl, tok::ObjCKeywordKind MethodImplKind) { + ParsingDeclRAIIObject PD(*this); + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; @@ -707,10 +726,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, MethodAttrs = ParseAttributes(); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, 0, CargNames, MethodAttrs, MethodImplKind); + PD.complete(Result); + return Result; } llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; @@ -783,10 +805,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, return DeclPtrTy(); Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CargNames, MethodAttrs, MethodImplKind, isVariadic); + PD.complete(Result); + return Result; } /// objc-protocol-refs: @@ -858,7 +883,6 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, SourceLocation atLoc) { assert(Tok.is(tok::l_brace) && "expected {"); llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); @@ -893,21 +917,31 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, } } + struct ObjCIvarCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + tok::ObjCKeywordKind visibility; + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls; + + ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V, + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls) : + P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the interface decl. + DeclPtrTy Field + = P.Actions.ActOnIvar(P.CurScope, + FD.D.getDeclSpec().getSourceRange().getBegin(), + IDecl, FD.D, FD.BitfieldSize, visibility); + AllIvarDecls.push_back(Field); + return Field; + } + } Callback(*this, interfaceDecl, visibility, AllIvarDecls); + // Parse all the comma separated declarators. DeclSpec DS; - FieldDeclarators.clear(); - ParseStructDeclaration(DS, FieldDeclarators); - - // Convert them all to fields. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - // Install the declarator into interfaceDecl. - DeclPtrTy Field = Actions.ActOnIvar(CurScope, - DS.getSourceRange().getBegin(), - interfaceDecl, - FD.D, FD.BitfieldSize, visibility); - AllIvarDecls.push_back(Field); - } + ParseStructDeclaration(DS, Callback); if (Tok.is(tok::semi)) { ConsumeToken(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 272be2f..7637382 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -938,8 +938,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, - false); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8e63fb8..045acd8 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -101,6 +101,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // (and retrieves the outer template parameter list from its // context). bool isSpecialization = true; + bool LastParamListWasEmpty = false; TemplateParameterLists ParamLists; TemplateParameterDepthCounter Depth(TemplateParameterDepth); do { @@ -140,13 +141,16 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, if (!TemplateParams.empty()) { isSpecialization = false; ++Depth; + } else { + LastParamListWasEmpty = true; } } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); // Parse the actual template declaration. return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(&ParamLists, - isSpecialization), + isSpecialization, + LastParamListWasEmpty), DeclEnd, AS); } @@ -186,16 +190,18 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Parse the declaration specifiers. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(Decl); + return Decl; } // Parse the declarator. - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); + ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -221,6 +227,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + DS.complete(ThisDecl); return ThisDecl; } @@ -668,22 +675,23 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, + UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); - assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) && + assert(Template && Tok.is(tok::less) && "Parser isn't at the beginning of a template-id"); // Consume the template-name. - IdentifierInfo *Name = Tok.getIdentifierInfo(); - SourceLocation TemplateNameLoc = ConsumeToken(); + SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; TemplateArgIsTypeList TemplateArgIsType; TemplateArgLocationList TemplateArgLocations; - bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, + bool Invalid = ParseTemplateIdAfterTemplateName(Template, + TemplateNameLoc, SS, false, LAngleLoc, TemplateArgs, TemplateArgIsType, @@ -732,7 +740,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; - TemplateId->Name = Name; + if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = TemplateName.Identifier; + TemplateId->Operator = OO_None; + } else { + TemplateId->Name = 0; + TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; + } TemplateId->Template = Template.getAs<void*>(); TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index bc737e9..335a6cf 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -526,7 +526,7 @@ bool Parser::isStartOfFunctionDefinition() { Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -534,6 +534,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -548,6 +549,9 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { SkipUntil(tok::semi); // FIXME: better skip? return DeclGroupPtrTy(); } + + DS.abort(); + const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) @@ -567,58 +571,12 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + DS.abort(); DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } - // Parse the first declarator. - Declarator DeclaratorInfo(DS, Declarator::FileContext); - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return DeclGroupPtrTy(); - } - - // If we have a declaration or declarator list, handle it. - if (isDeclarationAfterDeclarator()) { - // Parse the init-declarator-list for a normal declaration. - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); - // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); - return DG; - } - - if (DeclaratorInfo.isFunctionDeclarator() && - isStartOfFunctionDefinition()) { - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - if (Tok.is(tok::l_brace)) { - // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefinition() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, true); - } else { - SkipUntil(tok::semi); - } - return DeclGroupPtrTy(); - } - DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo); - return Actions.ConvertDeclToDeclGroup(TheDecl); - } - - if (DeclaratorInfo.isFunctionDeclarator()) - Diag(Tok, diag::err_expected_fn_body); - else - Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return ParseDeclGroup(DS, Declarator::FileContext, true); } /// ParseFunctionDefinition - We parsed and verified that the specified @@ -635,7 +593,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// -Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, +Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); assert(FnTypeInfo.Kind == DeclaratorChunk::Function && @@ -687,6 +645,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, D) : Actions.ActOnStartOfFunctionDef(CurScope, D); + // Break out of the ParsingDeclarator context before we parse the body. + D.complete(Res); + + // Break out of the ParsingDeclSpec context, too. This const_cast is + // safe because we're always the sole owner. + D.getMutableDeclSpec().abort(); + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res); @@ -981,17 +946,21 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // If this is a template-id, annotate with a template-id or type token. if (NextToken().is(tok::less)) { TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); if (TemplateNameKind TNK - = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(), - Tok.getLocation(), &SS, + = Actions.isTemplateName(CurScope, SS, TemplateName, /*ObjectType=*/0, EnteringContext, - Template)) - if (AnnotateTemplateIdToken(Template, TNK, &SS)) { + Template)) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. return Tok.isNot(tok::identifier); } + } } // The current token, which is either an identifier or a @@ -1065,3 +1034,10 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { PP.AnnotateCachedTokens(Tok); return true; } + +// Anchor the Parser::FieldCallback vtable to this translation unit. +// We use a spurious method instead of the destructor because +// destroying FieldCallbacks can actually be slightly +// performance-sensitive. +void Parser::FieldCallback::_anchor() { +} diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index c78ab5b..9b24d55 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -156,6 +156,17 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, case Result::RK_Keyword: OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; break; + + case Result::RK_Macro: { + OS << Results[I].Macro->getName() << " : " << Results[I].Rank; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + OS << '\n'; + break; + } } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fc9c14f..8104dd3 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -277,15 +277,20 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); if (PP.getTargetInfo().getPointerWidth(0) >= 64) { + DeclaratorInfo *DInfo; + // Install [u]int128_t for 64-bit targets. + DInfo = Context.getTrivialDeclaratorInfo(Context.Int128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__int128_t"), - Context.Int128Ty), TUScope); + DInfo), TUScope); + + DInfo = Context.getTrivialDeclaratorInfo(Context.UnsignedInt128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__uint128_t"), - Context.UnsignedInt128Ty), TUScope); + DInfo), TUScope); } @@ -298,10 +303,10 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushOnScopeChains(SelTag, TUScope); QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); - TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("SEL"), - SelT); + DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT); + TypedefDecl *SelTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("SEL"), SelInfo); PushOnScopeChains(SelTypedef, TUScope); Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); } @@ -317,22 +322,23 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - TypedefDecl *IdTypedef = - TypedefDecl::Create( - Context, CurContext, SourceLocation(), &Context.Idents.get("id"), - Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy) - ); + QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); + DeclaratorInfo *IdInfo = Context.getTrivialDeclaratorInfo(IdT); + TypedefDecl *IdTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("id"), IdInfo); PushOnScopeChains(IdTypedef, TUScope); Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); Context.ObjCIdRedefinitionType = Context.getObjCIdType(); } // Create the built-in typedef for 'Class'. if (Context.getObjCClassType().isNull()) { - TypedefDecl *ClassTypedef = - TypedefDecl::Create( - Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), - Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy) - ); + QualType ClassType + = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); + DeclaratorInfo *ClassInfo = Context.getTrivialDeclaratorInfo(ClassType); + TypedefDecl *ClassTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Class"), ClassInfo); PushOnScopeChains(ClassTypedef, TUScope); Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); Context.ObjCClassRedefinitionType = Context.getObjCClassType(); @@ -344,7 +350,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(0), CurContext(0), - PreDeclaratorDC(0), CurBlock(0), PackContext(0), + PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), CompleteTranslationUnit(CompleteTranslationUnit), diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6dd081b..0f84b46 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -73,6 +73,7 @@ namespace clang { class TypedefDecl; class TemplateDecl; class TemplateArgument; + class TemplateArgumentLoc; class TemplateArgumentList; class TemplateParameterList; class TemplateTemplateParmDecl; @@ -271,6 +272,15 @@ public: llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; std::vector<DeclarationName> TentativeDefinitionList; + /// \brief The collection of delayed deprecation warnings. + llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8> + DelayedDeprecationWarnings; + + /// \brief The depth of the current ParsingDeclaration stack. + /// If nonzero, we are currently parsing a declaration (and + /// hence should delay deprecation warnings). + unsigned ParsingDeclDepth; + /// WeakUndeclaredIdentifiers - Identifiers contained in /// #pragma weak before declared. rare. may alias another /// identifier, declared or undeclared @@ -447,8 +457,6 @@ public: // Type Analysis / Processing: SemaType.cpp. // QualType adjustParameterType(QualType T); - QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &IsInvalid); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); @@ -470,12 +478,12 @@ public: SourceLocation Loc, DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, DeclaratorInfo **DInfo = 0, - unsigned Skip = 0, TagDecl **OwnedDecl = 0); - DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, - unsigned Skip); + TagDecl **OwnedDecl = 0); + DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T); /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); DeclarationName GetNameForDeclarator(Declarator &D); + DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name); static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); @@ -767,7 +775,8 @@ public: /// Subroutines of ActOnDeclarator(). - TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T); + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + DeclaratorInfo *DInfo); void MergeTypeDefDecl(TypedefDecl *New, Decl *Old); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); @@ -868,7 +877,7 @@ public: bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -876,7 +885,7 @@ public: bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -914,7 +923,7 @@ public: void AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); @@ -936,7 +945,7 @@ public: DeclarationName &UnqualifiedName, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -945,7 +954,7 @@ public: FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -963,6 +972,10 @@ public: FunctionSet &Functions, Expr *LHS, Expr *RHS); + OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + ExprArg Base,ExprArg Idx); + ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, @@ -990,7 +1003,7 @@ public: void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2 }; + AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; ControlFlowKind CheckFallThrough(Stmt *); Scope *getNonFieldDeclScope(Scope *S); @@ -1377,7 +1390,7 @@ public: QualType T1, QualType T2, FunctionSet &Functions); - void ArgumentDependentLookup(DeclarationName Name, + void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, FunctionSet &Functions); @@ -1582,6 +1595,10 @@ public: /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); + ParsingDeclStackState PushParsingDeclaration(); + void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); + void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. @@ -1604,23 +1621,12 @@ public: // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; - virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS = 0, - bool isAddressOfOperand = false); - virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S, - SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand); - virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S, - SourceLocation OperatorLoc, - TypeTy *Ty, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand); + virtual OwningExprResult ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Name, + bool HasTrailingLParen, + bool IsAddressOfOperand); + OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, @@ -1664,7 +1670,8 @@ public: virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, + OwningExprResult CreateSizeOfAlignOfExpr(DeclaratorInfo *T, + SourceLocation OpLoc, bool isSizeOf, SourceRange R); OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R); @@ -1684,6 +1691,10 @@ public: SourceLocation LLoc, ExprArg Idx, SourceLocation RLoc); + OwningExprResult CreateBuiltinArraySubscriptExpr(ExprArg Base, + SourceLocation LLoc, + ExprArg Idx, + SourceLocation RLoc); OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -1709,20 +1720,21 @@ public: DeclarationName MemberName, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, DeclPtrTy ImplDecl, const CXXScopeSpec *SS, NamedDecl *FirstQualifierInScope = 0); - virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS = 0); + virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &Member, + DeclPtrTy ObjCImpDecl, + bool HasTrailingLParen); + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, @@ -1742,7 +1754,7 @@ public: SourceRange &QualifierRange, bool &ArgumentDependentLookup, bool &HasExplicitTemplateArguments, - const TemplateArgument *&ExplicitTemplateArgs, + const TemplateArgumentLoc *&ExplicitTemplateArgs, unsigned &NumExplicitTemplateArgs); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. @@ -1900,7 +1912,6 @@ public: /// and sets it as the initializer for the the passed in VarDecl. bool InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, MultiExprArg Exprs); /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -2099,52 +2110,6 @@ public: tok::TokenKind OpKind, TypeTy *&ObjectType); - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - IdentifierInfo *ClassName, - const CXXScopeSpec &SS, - bool HasTrailingLParen); - - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceRange TypeRange, - TypeTy *Type, - const CXXScopeSpec &SS, - bool HasTrailingLParen); - - virtual OwningExprResult - ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - OverloadedOperatorKind OverOpKind, - const CXXScopeSpec *SS = 0); - virtual OwningExprResult - ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - TypeTy *Ty, - const CXXScopeSpec *SS = 0); - - 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); - /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. @@ -2305,7 +2270,7 @@ public: SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); - void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, + void SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, @@ -2445,9 +2410,8 @@ public: // C++ Templates [C++ 14] // virtual TemplateNameKind isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); @@ -2507,13 +2471,13 @@ public: AccessSpecifier AS); void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocs, - llvm::SmallVector<TemplateArgument, 16> &TemplateArgs); + SourceLocation *TemplateArgLocsIn, + llvm::SmallVector<TemplateArgumentLoc, 16> &TempArgs); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); @@ -2534,22 +2498,21 @@ public: TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc); + OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType); bool CheckClassTemplatePartialSpecializationArgs( @@ -2578,10 +2541,18 @@ public: MultiTemplateParamsArg TemplateParameterLists, Declarator &D); + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, NamedDecl *&PrevDecl); @@ -2621,18 +2592,18 @@ public: bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgument &Arg, + const TemplateArgumentLoc &Arg, TemplateArgumentListBuilder &Converted); - bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, - SourceLocation ArgLoc); + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, + DeclaratorInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); @@ -2807,7 +2778,7 @@ public: TemplateDeductionResult SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, llvm::SmallVectorImpl<TemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, @@ -2823,7 +2794,7 @@ public: TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, @@ -2832,7 +2803,7 @@ public: TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, @@ -2863,6 +2834,7 @@ public: void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used); void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced); @@ -3101,7 +3073,7 @@ public: llvm::DenseMap<const Decl *, Decl *> LocalDecls; /// \brief The outer scope, in which contains local variable - /// definitions from some other instantiation (that is not + /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; @@ -3110,9 +3082,13 @@ public: LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { - SemaRef.CurrentInstantiationScope = this; + if (!CombineWithOuterScope) + SemaRef.CurrentInstantiationScope = this; + else + assert(SemaRef.CurrentInstantiationScope && + "No outer instantiation scope?"); } ~LocalInstantiationScope() { @@ -3133,6 +3109,11 @@ public: return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); } + NonTypeTemplateParmDecl *getInstantiationOf( + const NonTypeTemplateParmDecl *Var) { + return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); + } + void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert(!Stored && "Already instantiated this local"); @@ -3190,7 +3171,7 @@ public: bool Complain = true); bool - InstantiateClassTemplateSpecialization( + InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); @@ -3213,8 +3194,8 @@ public: TemplateName SubstTemplateName(TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); - TemplateArgument Subst(TemplateArgument Arg, - const MultiLevelTemplateArgumentList &TemplateArgs); + bool Subst(const TemplateArgumentLoc &Arg, TemplateArgumentLoc &Result, + const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index bf39604..8bb3348 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -83,7 +83,8 @@ static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,bool CStyle, const SourceRange &OpRange, - unsigned &msg); + unsigned &msg, + CastExpr::CastKind &Kind); static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -480,7 +481,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, // conversion. C++ 5.2.9p9 has additional information. // DR54's access restrictions apply here also. tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle, - OpRange, msg); + OpRange, msg, Kind); if (tcr != TC_NotApplicable) return tcr; @@ -706,7 +707,7 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg) { + unsigned &msg, CastExpr::CastKind &Kind) { const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); if (!DestMemPtr) return TC_NotApplicable; @@ -760,6 +761,7 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, return TC_Failed; } + Kind = CastExpr::CK_DerivedToBaseMemberPointer; return TC_Success; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 589b0c6..38b6ebe 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1272,10 +1272,15 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, // Skip over implicit cast expressions when checking for block expressions. RetValExp = RetValExp->IgnoreParenCasts(); - if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp)) + if (BlockExpr *C = dyn_cast<BlockExpr>(RetValExp)) if (C->hasBlockDeclRefExprs()) Diag(C->getLocStart(), diag::err_ret_local_block) << C->getSourceRange(); + + if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp)) + Diag(ALE->getLocStart(), diag::warn_ret_addr_label) + << ALE->getSourceRange(); + } else if (lhsType->isReferenceType()) { // Perform checking for stack values returned by reference. // Check for a reference to the stack @@ -1420,8 +1425,7 @@ static DeclRefExpr* EvalVal(Expr *E) { // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: { + case Stmt::DeclRefExprClass: { // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking // at code that refers to a variable's name. We check if it has local // storage within the function, and if so, return the expression. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3811513..e9df17d 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,8 @@ #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include <list> @@ -801,9 +803,45 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { - if (Kind != RK_Declaration) + if (Kind == RK_Keyword) return 0; + if (Kind == RK_Macro) { + MacroInfo *MI = S.PP.getMacroInfo(Macro); + if (!MI || !MI->isFunctionLike()) + return 0; + + // Format a function-like macro with placeholders for the arguments. + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTextChunk(Macro->getName().str().c_str()); + Result->AddTextChunk("("); + for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); + A != AEnd; ++A) { + if (A != MI->arg_begin()) + Result->AddTextChunk(", "); + + if (!MI->isVariadic() || A != AEnd - 1) { + // Non-variadic argument. + Result->AddPlaceholderChunk((*A)->getName().str().c_str()); + continue; + } + + // Variadic argument; cope with the different between GNU and C99 + // variadic macros, providing a single placeholder for the rest of the + // arguments. + if ((*A)->isStr("__VA_ARGS__")) + Result->AddPlaceholderChunk("..."); + else { + std::string Arg = (*A)->getName(); + Arg += "..."; + Result->AddPlaceholderChunk(Arg.c_str()); + } + } + Result->AddTextChunk(")"); + return Result; + } + + assert(Kind == RK_Declaration && "Missed a macro kind?"); NamedDecl *ND = Declaration; if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { @@ -999,6 +1037,10 @@ namespace { case Result::RK_Keyword: return strcmp(X.Keyword, Y.Keyword) < 0; + + case Result::RK_Macro: + return llvm::LowercaseString(X.Macro->getName()) < + llvm::LowercaseString(Y.Macro->getName()); } // Silence GCC warning. @@ -1007,6 +1049,16 @@ namespace { }; } +// Add all of the known macros as code-completion results. +static void AddMacroResults(Preprocessor &PP, unsigned Rank, + ResultBuilder &Results) { + Results.EnterNewScope(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); + M != MEnd; ++M) + Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); + Results.ExitScope(); +} + static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, CodeCompleteConsumer::Result *Results, unsigned NumResults) { @@ -1019,8 +1071,9 @@ static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, void Sema::CodeCompleteOrdinaryName(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1076,6 +1129,9 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, CurContext, Results); } + // Add macros + AddMacroResults(PP, NextRank, Results); + // Hand off the results found for code completion. HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); @@ -1117,10 +1173,11 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // We could have the start of a nested-name-specifier. Add those // results as well. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank, CurContext, Results); } + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1171,8 +1228,7 @@ void Sema::CodeCompleteCase(Scope *S) { // At the XXX, our completions are TagDecl::TK_union, // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union, // TK_struct, and TK_class. - if (QualifiedDeclRefExpr *QDRE = dyn_cast<QualifiedDeclRefExpr>(DRE)) - Qualifier = QDRE->getQualifier(); + Qualifier = DRE->getQualifier(); } } @@ -1199,6 +1255,7 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1235,7 +1292,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, SourceRange QualifierRange; bool ArgumentDependentLookup; bool HasExplicitTemplateArgs; - const TemplateArgument *ExplicitTemplateArgs; + const TemplateArgumentLoc *ExplicitTemplateArgs; unsigned NumExplicitTemplateArgs; DeconstructCallFunction(Fn, @@ -1293,6 +1350,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + AddMacroResults(PP, NextRank + 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1309,10 +1367,11 @@ void Sema::CodeCompleteUsing(Scope *S) { // After "using", we can see anything that would start a // nested-name-specifier. - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, - CurContext, Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1324,9 +1383,10 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1361,6 +1421,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1370,8 +1431,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1398,10 +1460,11 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add any nested-name-specifiers Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank + 1, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b83181b..d89cb5f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -95,7 +95,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::FoundOverloaded: return 0; - case LookupResult::Ambiguous: { + case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll // do the lookup again when looking for an object, and we can // diagnose the error then. If we don't do this, then the error @@ -131,51 +131,43 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // perform the name lookup again. DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc); break; - } case LookupResult::Found: IIDecl = Result.getFoundDecl(); break; } - if (IIDecl) { - QualType T; - - if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { - // Check whether we can use this type - (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - - if (getLangOptions().CPlusPlus) { - // C++ [temp.local]p2: - // Within the scope of a class template specialization or - // partial specialization, when the injected-class-name is - // not followed by a <, it is equivalent to the - // injected-class-name followed by the template-argument s - // of the class template specialization or partial - // specialization enclosed in <>. - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) - if (RD->isInjectedClassName()) - if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) - T = Template->getInjectedClassNameType(Context); - } - - if (T.isNull()) - T = Context.getTypeDeclType(TD); - } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { - // Check whether we can use this interface. - (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - - T = Context.getObjCInterfaceType(IDecl); - } else - return 0; + assert(IIDecl && "Didn't find decl"); + QualType T; + if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); + + // C++ [temp.local]p2: + // Within the scope of a class template specialization or + // partial specialization, when the injected-class-name is + // not followed by a <, it is equivalent to the + // injected-class-name followed by the template-argument s + // of the class template specialization or partial + // specialization enclosed in <>. + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) + if (RD->isInjectedClassName()) + if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) + T = Template->getInjectedClassNameType(Context); + + if (T.isNull()) + T = Context.getTypeDeclType(TD); + if (SS) T = getQualifiedNameType(*SS, T); + + } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); + T = Context.getObjCInterfaceType(IDecl); + } else + return 0; - return T.getAsOpaquePtr(); - } - - return 0; + return T.getAsOpaquePtr(); } /// isTagName() - This method is called *for error recovery purposes only* @@ -1055,9 +1047,11 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { /// Statement that should return a value. /// /// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end and -/// NeverFallThrough iff we never fall off the end of the statement. We assume -/// that functions not marked noreturn will return. +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { // FIXME: Eventually share this CFG object when we have other warnings based // of the CFG. This can be done using AnalysisContext. @@ -1065,7 +1059,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { // FIXME: They should never return 0, fix that, delete this code. if (cfg == 0) - return NeverFallThrough; + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; // The CFG leaves in dead things, and we don't want to dead code paths to // confuse us, so we mark all live things first. std::queue<CFGBlock*> workq; @@ -1094,7 +1089,7 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { bool HasLiveReturn = false; bool HasFakeEdge = false; bool HasPlainEdge = false; - for (CFGBlock::succ_iterator I=cfg->getExit().pred_begin(), + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), E = cfg->getExit().pred_end(); I != E; ++I) { @@ -1138,8 +1133,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { if (NoReturnEdge == false) HasPlainEdge = true; } - if (!HasPlainEdge) - return NeverFallThrough; + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } if (HasFakeEdge || HasLiveReturn) return MaybeFallThrough; // This says AlwaysFallThrough for calls to functions that are not marked @@ -1161,6 +1159,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { // which this code would then warn about. if (getDiagnostics().hasErrorOccurred()) return; + bool ReturnsVoid = false; bool HasNoReturn = false; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -1202,10 +1201,12 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { else if (!ReturnsVoid) Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); break; - case NeverFallThrough: - if (ReturnsVoid) + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); break; + case NeverFallThrough: + break; } } } @@ -1225,7 +1226,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { return; bool ReturnsVoid = false; bool HasNoReturn = false; - if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) { + if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ if (FT->getResultType()->isVoidType()) ReturnsVoid = true; if (FT->getNoReturnAttr()) @@ -1253,10 +1254,12 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { else if (!ReturnsVoid) Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); break; - case NeverFallThrough: + case NeverFallThroughOrReturn: if (ReturnsVoid) Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); break; + case NeverFallThrough: + break; } } } @@ -1330,6 +1333,10 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { } if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { + // If there are attributes in the DeclSpec, apply them to the record. + if (const AttributeList *AL = DS.getAttributes()) + ProcessDeclAttributeList(S, Record, AL); + if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || @@ -1602,53 +1609,60 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. DeclarationName Sema::GetNameForDeclarator(Declarator &D) { - switch (D.getKind()) { - case Declarator::DK_Abstract: - assert(D.getIdentifier() == 0 && "abstract declarators have no name"); - return DeclarationName(); - - case Declarator::DK_Normal: - assert (D.getIdentifier() != 0 && "normal declarators have an identifier"); - return DeclarationName(D.getIdentifier()); - - case Declarator::DK_Constructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Ty)); - } - - case Declarator::DK_Destructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(Ty)); - } - - case Declarator::DK_Conversion: { - // FIXME: We'd like to keep the non-canonical type for diagnostics! - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Ty)); - } + return GetNameFromUnqualifiedId(D.getName()); +} - case Declarator::DK_Operator: - assert(D.getIdentifier() == 0 && "operator names have no identifier"); - return Context.DeclarationNames.getCXXOperatorName( - D.getOverloadedOperator()); +/// \brief Retrieves the canonicalized name from a parsed unqualified-id. +DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + return DeclarationName(Name.Identifier); - case Declarator::DK_TemplateId: { - TemplateName Name - = TemplateName::getFromVoidPointer(D.getTemplateId()->Template); - if (TemplateDecl *Template = Name.getAsTemplateDecl()) - return Template->getDeclName(); - if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) - return Ovl->getDeclName(); - - return DeclarationName(); - } + case UnqualifiedId::IK_OperatorFunctionId: + return Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator); + + case UnqualifiedId::IK_ConversionFunctionId: { + QualType Ty = GetTypeFromParser(Name.ConversionFunctionId); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_ConstructorName: { + QualType Ty = GetTypeFromParser(Name.ConstructorName); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_DestructorName: { + QualType Ty = GetTypeFromParser(Name.DestructorName); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_TemplateId: { + TemplateName TName + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + if (TemplateDecl *Template = TName.getAsTemplateDecl()) + return Template->getDeclName(); + if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) + return Ovl->getDeclName(); + + return DeclarationName(); + } } - + assert(false && "Unknown name kind"); - return DeclarationName(); + return DeclarationName(); } /// isNearlyMatchingFunction - Determine whether the C++ functions @@ -1986,12 +2000,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, DInfo); if (!NewTD) return 0; - if (D.isInvalidType()) - NewTD->setInvalidDecl(); - // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); // Merge the decl with the existing one if appropriate. If the decl is @@ -2013,7 +2024,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); - NewTD->setUnderlyingType(FixedTy); + NewTD->setTypeDeclaratorInfo(Context.getTrivialDeclaratorInfo(FixedTy)); } else { if (SizeIsNegative) Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); @@ -2516,7 +2527,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isInline |= IsFunctionDefinition; } - if (D.getKind() == Declarator::DK_Constructor) { + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && "Constructors can only be declared in a member context"); @@ -2529,7 +2540,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, DInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); - } else if (D.getKind() == Declarator::DK_Destructor) { + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, SC); @@ -2551,7 +2562,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /*hasPrototype=*/true); D.setInvalidType(); } - } else if (D.getKind() == Declarator::DK_Conversion) { + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); @@ -2795,10 +2806,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), @@ -3101,7 +3112,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // C99 6.7.4p4: In a hosted environment, the inline function specifier // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. - bool isInline = FD->isInline(); + bool isInline = FD->isInlineSpecified(); bool isStatic = FD->getStorageClass() == FunctionDecl::Static; if (isInline || isStatic) { unsigned diagID = diag::warn_unusual_main_decl; @@ -3442,7 +3453,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (getLangOptions().CPlusPlus) { QualType InitType = Type; if (const ArrayType *Array = Context.getAsArrayType(Type)) - InitType = Array->getElementType(); + InitType = Context.getBaseElementType(Array); if ((!Var->hasExternalStorage() && !Var->isExternC()) && InitType->isRecordType() && !InitType->isDependentType()) { if (!RequireCompleteType(Var->getLocation(), InitType, @@ -3465,7 +3476,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, else { // FIXME: Cope with initialization of arrays if (!Constructor->isTrivial() && - InitializeVarWithConstructor(Var, Constructor, InitType, + InitializeVarWithConstructor(Var, Constructor, move_arg(ConstructorArgs))) Var->setInvalidDecl(); @@ -3626,8 +3637,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DeclaratorInfo *DInfo = 0; TagDecl *OwnedDecl = 0; - QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, - &OwnedDecl); + QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, &OwnedDecl); if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { // C++ [dcl.fct]p6: @@ -3668,16 +3678,9 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { QualType T = adjustParameterType(parmDeclType); - ParmVarDecl *New; - if (T == parmDeclType) // parameter type did not need adjustment - New = ParmVarDecl::Create(Context, CurContext, - D.getIdentifierLoc(), II, - parmDeclType, DInfo, StorageClass, - 0); - else // keep track of both the adjusted and unadjusted types - New = OriginalParmVarDecl::Create(Context, CurContext, - D.getIdentifierLoc(), II, T, DInfo, - parmDeclType, StorageClass, 0); + ParmVarDecl *New + = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, + T, DInfo, StorageClass, 0); if (D.isInvalidType()) New->setInvalidDecl(); @@ -3776,6 +3779,9 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, } Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { + // Clear the last template instantiation error context. + LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); + if (!D) return D; FunctionDecl *FD = 0; @@ -4104,15 +4110,21 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } } -TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { +TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + DeclaratorInfo *DInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + if (!DInfo) { + assert(D.isInvalidType() && "no declarator info for valid type"); + DInfo = Context.getTrivialDeclaratorInfo(T); + } + // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getIdentifierLoc(), D.getIdentifier(), - T); + DInfo); if (const TagType *TT = T->getAs<TagType>()) { TagDecl *TD = TT->getDecl(); @@ -4321,9 +4333,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (PrevDecl) { - // Check whether the previous declaration is usable. - (void)DiagnoseUseOfDecl(PrevDecl, NameLoc); - if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -4955,12 +4964,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXDefaultConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; - for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci) - if (!ci->isImplicitlyDefined(Context)) { + for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ + const FunctionDecl *body = 0; + ci->getBody(body); + if (!body || + !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) { SourceLocation CtorLoc = ci->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } + } assert(0 && "found no user-declared constructors"); return; @@ -5038,7 +5051,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { // Check for nontrivial bases (and recurse). for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) { const RecordType *BaseRT = bi->getType()->getAs<RecordType>(); - assert(BaseRT); + assert(BaseRT && "Don't know how to handle dependent bases"); CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl()); if (!(BaseRecTy->*hasTrivial)()) { SourceLocation BaseLoc = bi->getSourceRange().getBegin(); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 341d49e..18f57da 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -193,7 +193,8 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, // This will run the reguired checks. QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); if (!T.isNull()) { - tDecl->setUnderlyingType(T); + // FIXME: preserve the old source info. + tDecl->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(T)); // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(tDecl); @@ -278,8 +279,11 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) VD->setType(CurType); - else - cast<TypedefDecl>(D)->setUnderlyingType(CurType); + else { + // FIXME: preserve existing source info. + DeclaratorInfo *DInfo = S.Context.getTrivialDeclaratorInfo(CurType); + cast<TypedefDecl>(D)->setTypeDeclaratorInfo(DInfo); + } } static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -897,7 +901,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllimport attribute is ignored for inlined functions. // Warning is emitted. - if (FD->isInline()) { + if (FD->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; return; } @@ -942,7 +946,7 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (FD->isInline()) { + if (FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; @@ -1028,6 +1032,22 @@ static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) StdCallAttr()); } +/// Diagnose the use of a non-standard calling convention on the given +/// function. +static void DiagnoseCConv(FunctionDecl *D, const char *CConv, + SourceLocation Loc, Sema &S) { + if (!D->hasPrototype()) { + S.Diag(Loc, diag::err_cconv_knr) << CConv; + return; + } + + const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>(); + if (T->isVariadic()) { + S.Diag(Loc, diag::err_cconv_varargs) << CConv; + return; + } +} + static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Attribute has no arguments. if (Attr.getNumArgs() != 0) { @@ -1041,6 +1061,8 @@ static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } + DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S); + // stdcall and fastcall attributes are mutually incompatible. if (d->getAttr<StdCallAttr>()) { S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) @@ -1636,9 +1658,10 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { } // Install the new type. - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) - TD->setUnderlyingType(NewTy); - else + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + // FIXME: preserve existing source info. + TD->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(NewTy)); + } else cast<ValueDecl>(D)->setType(NewTy); } @@ -1688,7 +1711,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!Fn->isInline()) { + if (!Fn->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } @@ -1944,3 +1967,62 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { if (const AttributeList *Attrs = PD.getAttributes()) ProcessDeclAttributeList(S, D, Attrs); } + +/// PushParsingDeclaration - Enter a new "scope" of deprecation +/// warnings. +/// +/// The state token we use is the start index of this scope +/// on the warning stack. +Action::ParsingDeclStackState Sema::PushParsingDeclaration() { + ParsingDeclDepth++; + return (ParsingDeclStackState) DelayedDeprecationWarnings.size(); +} + +static bool isDeclDeprecated(Decl *D) { + do { + if (D->hasAttr<DeprecatedAttr>()) + return true; + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + +void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { + assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); + ParsingDeclDepth--; + + if (DelayedDeprecationWarnings.empty()) + return; + + unsigned SavedIndex = (unsigned) S; + assert(SavedIndex <= DelayedDeprecationWarnings.size() && + "saved index is out of bounds"); + + if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) { + for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) { + SourceLocation Loc = DelayedDeprecationWarnings[I].first; + NamedDecl *&ND = DelayedDeprecationWarnings[I].second; + if (ND) { + Diag(Loc, diag::warn_deprecated) << ND->getDeclName(); + + // Prevent this from triggering multiple times. + ND = 0; + } + } + } + + DelayedDeprecationWarnings.set_size(SavedIndex); +} + +void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) { + // Delay if we're currently parsing a declaration. + if (ParsingDeclDepth) { + DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D)); + return; + } + + // Otherwise, don't warn if our current context is deprecated. + if (isDeclDeprecated(cast<Decl>(CurContext))) + return; + + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); +} diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6d1f4ea..bc25513 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1123,7 +1123,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, } void -Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, +Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, @@ -1179,7 +1179,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); AllToInit.push_back(Value); @@ -1187,18 +1187,26 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, else { CXXRecordDecl *VBaseDecl = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null"); + assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); - if (!Ctor) + if (!Ctor) { Bases.push_back(VBase); - else - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + continue; + } + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0, - Ctor, - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(VBase->getType(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); AllToInit.push_back(Member); } } @@ -1216,7 +1224,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); AllToInit.push_back(Value); @@ -1224,18 +1232,26 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, else { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context); - if (!Ctor) + if (!Ctor) { Bases.push_back(Base); - else - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + continue; + } + + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0, - BaseDecl->getDefaultConstructor(Context), - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(Base->getType(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); AllToInit.push_back(Member); } } @@ -1268,7 +1284,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, QualType FT = (*Field)->getType(); if (const RecordType* RT = FT->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl()); - assert(FieldRecDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(FieldRecDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = FieldRecDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); @@ -1281,13 +1297,22 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (const RecordType* RT = FT->getAs<RecordType>()) { CXXConstructorDecl *Ctor = cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); - if (!Ctor && !FT->isDependentType()) + if (!Ctor && !FT->isDependentType()) { Fields.push_back(*Field); + continue; + } + + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0, - Ctor, - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); + AllToInit.push_back(Member); if (Ctor) MarkDeclarationReferenced(Constructor->getLocation(), Ctor); @@ -1327,10 +1352,10 @@ Sema::BuildBaseOrMemberInitializers(ASTContext &C, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers ) { - llvm::SmallVector<CXXBaseSpecifier *, 4>Bases; - llvm::SmallVector<FieldDecl *, 4>Members; + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + llvm::SmallVector<FieldDecl *, 4> Members; - setBaseOrMemberInitializers(Constructor, + SetBaseOrMemberInitializers(Constructor, Initializers, NumInitializers, Bases, Members); for (unsigned int i = 0; i < Bases.size(); i++) Diag(Bases[i]->getSourceRange().getBegin(), @@ -1976,6 +2001,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) { + assert(!Base->getType()->isDependentType() && + "Cannot generate implicit members for class with dependent bases."); const CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); const CXXMethodDecl *MD = 0; @@ -2268,7 +2295,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // (7.1.3); however, a typedef-name that names a class shall not // be used as the identifier in the declarator for a destructor // declaration. - QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (isa<TypedefType>(DeclaratorType)) { Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType; @@ -2394,7 +2421,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -3152,10 +3179,9 @@ Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor, bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, MultiExprArg Exprs) { OwningExprResult TempResult = - BuildCXXConstructExpr(VD->getLocation(), DeclInitType, Constructor, + BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, move(Exprs)); if (TempResult.isInvalid()) return true; @@ -3235,7 +3261,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // class type. QualType DeclInitType = VDecl->getType(); if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) - DeclInitType = Array->getElementType(); + DeclInitType = Context.getBaseElementType(Array); // FIXME: This isn't the right place to complete the type. if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), @@ -3260,7 +3286,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, RealDecl->setInvalidDecl(); else { VDecl->setCXXDirectInitializer(true); - if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, + if (InitializeVarWithConstructor(VDecl, Constructor, move_arg(ConstructorArgs))) RealDecl->setInvalidDecl(); FinalizeVarWithDestructor(VDecl, DeclInitType); @@ -4269,8 +4295,7 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, /// We permit this as a special case; if there are any template /// parameters present at all, require proper matching, i.e. /// template <> template <class T> friend class A<int>::B; -Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, - const DeclSpec &DS, +Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getSourceRange().getBegin(); @@ -4280,9 +4305,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. - bool invalid = false; - QualType T = ConvertDeclSpecToType(DS, Loc, invalid); - if (invalid) return DeclPtrTy(); + Declarator TheDeclarator(DS, Declarator::MemberContext); + QualType T = GetTypeForDeclarator(TheDeclarator, S); + if (TheDeclarator.isInvalidType()) + return DeclPtrTy(); // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just @@ -4489,12 +4515,12 @@ Sema::ActOnFriendFunctionDecl(Scope *S, if (DC->isFileContext()) { // This implies that it has to be an operator or function. - if (D.getKind() == Declarator::DK_Constructor || - D.getKind() == Declarator::DK_Destructor || - D.getKind() == Declarator::DK_Conversion) { + if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || + D.getName().getKind() == UnqualifiedId::IK_DestructorName || + D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) { Diag(Loc, diag::err_introducing_special_friend) << - (D.getKind() == Declarator::DK_Constructor ? 0 : - D.getKind() == Declarator::DK_Destructor ? 1 : 2); + (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 : + D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2); return DeclPtrTy(); } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 22a5179..93f8d0d 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1707,29 +1707,22 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { - QualType ArgType, UnpromotedArgType; + QualType ArgType; + DeclaratorInfo *DI; if (ArgInfo[i].Type == 0) { - UnpromotedArgType = ArgType = Context.getObjCIdType(); + ArgType = Context.getObjCIdType(); + DI = 0; } else { - UnpromotedArgType = ArgType = GetTypeFromParser(ArgInfo[i].Type); + ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI); // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = adjustParameterType(ArgType); } - ParmVarDecl* Param; - if (ArgType == UnpromotedArgType) - Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, - ArgInfo[i].Name, ArgType, - /*DInfo=*/0, //FIXME: Pass info here. - VarDecl::None, 0); - else - Param = OriginalParmVarDecl::Create(Context, ObjCMethod, - ArgInfo[i].NameLoc, - ArgInfo[i].Name, ArgType, - /*DInfo=*/0, //FIXME: Pass info here. - UnpromotedArgType, - VarDecl::None, 0); + ParmVarDecl* Param + = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, + ArgInfo[i].Name, ArgType, DI, + VarDecl::None, 0); if (ArgType->isObjCInterfaceType()) { Diag(ArgInfo[i].NameLoc, @@ -1755,6 +1748,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); + const ObjCMethodDecl *InterfaceMD = 0; + // For implementations (which can be very "coarse grain"), we add the // method now. This allows the AST to implement lookup methods that work // incrementally (without waiting until we parse the @end). It also allows @@ -1768,6 +1763,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = ImpDecl->getClassMethod(Sel); ImpDecl->addClassMethod(ObjCMethod); } + InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, + MethodType == tok::minus); if (AttrList) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = @@ -1788,6 +1785,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } + + // If the interface declared this method, and it was deprecated there, + // mark it deprecated here. + if (InterfaceMD && InterfaceMD->hasAttr<DeprecatedAttr>()) + ObjCMethod->addAttr(::new (Context) DeprecatedAttr()); + return DeclPtrTy::make(ObjCMethod); } @@ -1900,33 +1903,34 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // handling. if ((CCPrimary = CDecl->getClassInterface())) { // Find the property in continuation class's primary class only. - ObjCPropertyDecl *PIDecl = 0; IdentifierInfo *PropertyId = FD.D.getIdentifier(); - for (ObjCInterfaceDecl::prop_iterator - I = CCPrimary->prop_begin(), E = CCPrimary->prop_end(); - I != E; ++I) - if ((*I)->getIdentifier() == PropertyId) { - PIDecl = *I; - break; - } - - if (PIDecl) { + if (ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { // property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributes(); if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) != - (PIkind & ObjCPropertyDecl::OBJC_PR_nonatomic)) + unsigned assignRetainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_nonatomic); + if ((Attributes & assignRetainCopyNonatomic) != + (PIkind & assignRetainCopyNonatomic)) { Diag(AtLoc, diag::warn_property_attr_mismatch); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); if (Attributes & ObjCDeclSpec::DQ_PR_copy) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); - } else + } else { Diag(AtLoc, diag::err_use_continuation_class) << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary // class's list. @@ -2054,6 +2058,14 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); return DeclPtrTy(); } + if (const ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { + if (CD->getIdentifier()) { + Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); + Diag(property->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + } } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { if (Synthesize) { Diag(AtLoc, diag::error_synthesize_category_decl); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ae45429..ac7cced 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -37,40 +37,24 @@ using namespace clang; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// +/// If IgnoreDeprecated is set to true, this should not want about deprecated +/// decls. +/// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. +/// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // See if the decl is deprecated. if (D->getAttr<DeprecatedAttr>()) { - // Implementing deprecated stuff requires referencing deprecated - // stuff. Don't warn if we are implementing a deprecated - // construct. - bool isSilenced = false; - - if (NamedDecl *ND = getCurFunctionOrMethodDecl()) { - // If this reference happens *in* a deprecated function or method, don't - // warn. - isSilenced = ND->getAttr<DeprecatedAttr>(); - - // If this is an Objective-C method implementation, check to see if the - // method was deprecated on the declaration, not the definition. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) { - // The semantic decl context of a ObjCMethodDecl is the - // ObjCImplementationDecl. - if (ObjCImplementationDecl *Impl - = dyn_cast<ObjCImplementationDecl>(MD->getParent())) { - - MD = Impl->getClassInterface()->getMethod(MD->getSelector(), - MD->isInstanceMethod()); - isSilenced |= MD && MD->getAttr<DeprecatedAttr>(); - } - } - } - - if (!isSilenced) - Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + EmitDeprecationWarning(D, Loc); } + // See if the decl is unavailable + if (D->getAttr<UnavailableAttr>()) { + Diag(Loc, diag::warn_unavailable) << D->getDeclName(); + Diag(D->getLocation(), diag::note_unavailable_here) << 0; + } + // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { @@ -80,12 +64,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { } } - // See if the decl is unavailable - if (D->getAttr<UnavailableAttr>()) { - Diag(Loc, diag::warn_unavailable) << D->getDeclName(); - Diag(D->getLocation(), diag::note_unavailable_here) << 0; - } - return false; } @@ -432,23 +410,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, -/// ActOnIdentifierExpr - The parser read an identifier in expression context, -/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this -/// identifier is used in a function call context. -/// SS is only used for a C++ qualified-id (foo::bar) to indicate the -/// class or namespace that the identifier must be a member of. -Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand) { - return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS, - isAddressOfOperand); -} - -/// BuildDeclRefExpr - Build either a DeclRefExpr or a -/// QualifiedDeclRefExpr based on whether or not SS is a -/// nested-name-specifier. +/// BuildDeclRefExpr - Build a DeclRefExpr. Sema::OwningExprResult Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, @@ -476,15 +438,11 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, MarkDeclarationReferenced(Loc, D); - Expr *E; - if (SS && !SS->isEmpty()) { - E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, - ValueDependent, SS->getRange(), - static_cast<NestedNameSpecifier *>(SS->getScopeRep())); - } else - E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent); - - return Owned(E); + return Owned(DeclRefExpr::Create(Context, + SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, + SS? SS->getRange() : SourceRange(), + D, Loc, + Ty, TypeDependent, ValueDependent)); } /// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or @@ -656,15 +614,43 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return Owned(Result); } +Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Name, + bool HasTrailingLParen, + bool IsAddressOfOperand) { + if (Name.getKind() == UnqualifiedId::IK_TemplateId) { + ASTTemplateArgsPtr TemplateArgsPtr(*this, + Name.TemplateId->getTemplateArgs(), + Name.TemplateId->getTemplateArgIsType(), + Name.TemplateId->NumArgs); + return ActOnTemplateIdExpr(SS, + TemplateTy::make(Name.TemplateId->Template), + Name.TemplateId->TemplateNameLoc, + Name.TemplateId->LAngleLoc, + TemplateArgsPtr, + Name.TemplateId->getTemplateArgLocations(), + Name.TemplateId->RAngleLoc); + } + + // FIXME: We lose a bunch of source information by doing this. Later, + // we'll want to merge ActOnDeclarationNameExpr's logic into + // ActOnIdExpression. + return ActOnDeclarationNameExpr(S, + Name.StartLocation, + GetNameFromUnqualifiedId(Name), + HasTrailingLParen, + &SS, + IsAddressOfOperand); +} + /// ActOnDeclarationNameExpr - The parser has read some kind of name /// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine /// performs lookup on that name and returns an expression that refers /// to that name. This routine isn't directly called from the parser, /// because the parser doesn't know about DeclarationName. Rather, -/// this routine is called by ActOnIdentifierExpr, -/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr, -/// which form the DeclarationName from the corresponding syntactic -/// forms. +/// this routine is called by ActOnIdExpression, which contains a +/// parsed UnqualifiedId. /// /// HasTrailingLParen indicates whether this identifier is used in a /// function call context. LookupCtx is only used for a C++ @@ -745,8 +731,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // FIXME: This should use a new expr for a direct reference, don't // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); - OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(), - II, false); + UnqualifiedId SelfName; + SelfName.setIdentifier(&II, SourceLocation()); + CXXScopeSpec SelfScopeSpec; + OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, + SelfName, false, false); MarkDeclarationReferenced(Loc, IV); return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, @@ -1083,7 +1072,8 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) { - if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const && + if (Context.getCanonicalType(Dcl->getType()).getCVRQualifiers() + == Qualifiers::Const && Dcl->getInit()) { ValueDependent = Dcl->getInit()->isValueDependent(); } @@ -1300,7 +1290,7 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return false; // C99 6.5.3.4p1: - if (isa<FunctionType>(exprType)) { + if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. if (isSizeof) Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; @@ -1358,17 +1348,20 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, /// \brief Build a sizeof or alignof expression given a type operand. Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, +Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo, + SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - if (T.isNull()) + if (!DInfo) return ExprError(); + QualType T = DInfo->getType(); + if (!T->isDependentType() && CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T, + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo, Context.getSizeType(), OpLoc, R.getEnd())); } @@ -1410,12 +1403,11 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (TyOrEx == 0) return ExprError(); if (isType) { - // FIXME: Preserve type source info. - QualType ArgTy = GetTypeFromParser(TyOrEx); - return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange); + DeclaratorInfo *DInfo; + (void) GetTypeFromParser(TyOrEx, &DInfo); + return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange); } - // Get the end location. Expr *ArgEx = (Expr *)TyOrEx; Action::OwningExprResult Result = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); @@ -1602,103 +1594,18 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, LHSExp->getType()->isEnumeralType() || RHSExp->getType()->isRecordType() || RHSExp->getType()->isEnumeralType())) { - // Add the appropriate overloaded operators (C++ [over.match.oper]) - // to the candidate set. - OverloadCandidateSet CandidateSet; - Expr *Args[2] = { LHSExp, RHSExp }; - AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet, - SourceRange(LLoc, RLoc)); - - // Perform overload resolution. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, LLoc, Best)) { - case OR_Success: { - // We found a built-in operator or an overloaded operator. - FunctionDecl *FnDecl = Best->Function; - - if (FnDecl) { - // We matched an overloaded operator. Build a call to that - // operator. - - // Convert the arguments. - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (PerformObjectArgumentInitialization(LHSExp, Method) || - PerformCopyInitialization(RHSExp, - FnDecl->getParamDecl(0)->getType(), - "passing")) - return ExprError(); - } else { - // Convert the arguments. - if (PerformCopyInitialization(LHSExp, - FnDecl->getParamDecl(0)->getType(), - "passing") || - PerformCopyInitialization(RHSExp, - FnDecl->getParamDecl(1)->getType(), - "passing")) - return ExprError(); - } - - // Determine the result type - QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); - - // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); - - Base.release(); - Idx.release(); - Args[0] = LHSExp; - Args[1] = RHSExp; - - ExprOwningPtr<CXXOperatorCallExpr> - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr, Args, 2, - ResultTy, RLoc)); - if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), - FnDecl)) - return ExprError(); - - return Owned(TheCall.release()); - } else { - // We matched a built-in operator. Convert the arguments, then - // break out so that we will build the appropriate built-in - // operator node. - if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0], - "passing") || - PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1], - "passing")) - return ExprError(); - - break; - } - } - - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; + return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, move(Base),move(Idx)); + } - case OR_Ambiguous: - Diag(LLoc, diag::err_ovl_ambiguous_oper) - << "[]" - << LHSExp->getSourceRange() << RHSExp->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); + return CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); +} - case OR_Deleted: - Diag(LLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << "[]" - << LHSExp->getSourceRange() << RHSExp->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - } - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, fall through to trying to - // build a built-in operation. - } +Action::OwningExprResult +Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, + ExprArg Idx, SourceLocation RLoc) { + Expr *LHSExp = static_cast<Expr*>(Base.get()); + Expr *RHSExp = static_cast<Expr*>(Idx.get()); // Perform default conversions. DefaultFunctionArrayConversion(LHSExp); @@ -1961,7 +1868,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, DeclarationName MemberName, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS, @@ -2549,13 +2456,77 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } -Action::OwningExprResult -Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, - DeclarationName(&Member), ObjCImpDecl, SS); +Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &Member, + DeclPtrTy ObjCImpDecl, + bool HasTrailingLParen) { + if (Member.getKind() == UnqualifiedId::IK_TemplateId) { + TemplateName Template + = TemplateName::getFromVoidPointer(Member.TemplateId->Template); + + // FIXME: We're going to end up looking up the template based on its name, + // twice! + DeclarationName Name; + if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) + Name = ActualTemplate->getDeclName(); + else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) + Name = Ovl->getDeclName(); + else { + DependentTemplateName *DTN = Template.getAsDependentTemplateName(); + if (DTN->isIdentifier()) + Name = DTN->getIdentifier(); + else + Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator()); + } + + // Translate the parser's template argument list in our AST format. + ASTTemplateArgsPtr TemplateArgsPtr(*this, + Member.TemplateId->getTemplateArgs(), + Member.TemplateId->getTemplateArgIsType(), + Member.TemplateId->NumArgs); + + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsPtr, + Member.TemplateId->getTemplateArgLocations(), + TemplateArgs); + TemplateArgsPtr.release(); + + // Do we have the save the actual template name? We might need it... + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + Member.TemplateId->TemplateNameLoc, + Name, true, Member.TemplateId->LAngleLoc, + TemplateArgs.data(), TemplateArgs.size(), + Member.TemplateId->RAngleLoc, DeclPtrTy(), + &SS); + } + + // FIXME: We lose a lot of source information by mapping directly to the + // DeclarationName. + OwningExprResult Result + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + Member.getSourceRange().getBegin(), + GetNameFromUnqualifiedId(Member), + ObjCImpDecl, &SS); + + if (Result.isInvalid() || HasTrailingLParen || + Member.getKind() != UnqualifiedId::IK_DestructorName) + return move(Result); + + // The only way a reference to a destructor can be used is to + // immediately call them. Since the next token is not a '(', produce a + // diagnostic and build the call now. + Expr *E = (Expr *)Result.get(); + SourceLocation ExpectedLParenLoc + = PP.getLocForEndOfToken(Member.getSourceRange().getEnd()); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa<CXXPseudoDestructorExpr>(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, + MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -2713,7 +2684,7 @@ void Sema::DeconstructCallFunction(Expr *FnExpr, SourceRange &QualifierRange, bool &ArgumentDependentLookup, bool &HasExplicitTemplateArguments, - const TemplateArgument *&ExplicitTemplateArgs, + const TemplateArgumentLoc *&ExplicitTemplateArgs, unsigned &NumExplicitTemplateArgs) { // Set defaults for all of the output parameters. Function = 0; @@ -2738,16 +2709,12 @@ void Sema::DeconstructCallFunction(Expr *FnExpr, cast<UnaryOperator>(FnExpr)->getOpcode() == UnaryOperator::AddrOf) { FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); - } else if (QualifiedDeclRefExpr *QDRExpr - = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) { - // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). - ArgumentDependentLookup = false; - Qualifier = QDRExpr->getQualifier(); - QualifierRange = QDRExpr->getQualifierRange(); - Function = dyn_cast<NamedDecl>(QDRExpr->getDecl()); - break; } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) { Function = dyn_cast<NamedDecl>(DRExpr->getDecl()); + if ((Qualifier = DRExpr->getQualifier())) { + ArgumentDependentLookup = false; + QualifierRange = DRExpr->getQualifierRange(); + } break; } else if (UnresolvedFunctionNameExpr *DepName = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) { @@ -2866,24 +2833,29 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { - const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType()); - QualType ResultTy = FPT->getResultType().getNonReferenceType(); + if (const FunctionProtoType *FPT = + dyn_cast<FunctionProtoType>(BO->getType())) { + QualType ResultTy = FPT->getResultType().getNonReferenceType(); - ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, - NumArgs, ResultTy, - RParenLoc)); + ExprOwningPtr<CXXMemberCallExpr> + TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, + NumArgs, ResultTy, + RParenLoc)); - if (CheckCallReturnType(FPT->getResultType(), - BO->getRHS()->getSourceRange().getBegin(), - TheCall.get(), 0)) - return ExprError(); + if (CheckCallReturnType(FPT->getResultType(), + BO->getRHS()->getSourceRange().getBegin(), + TheCall.get(), 0)) + return ExprError(); - if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, - RParenLoc)) - return ExprError(); + if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + RParenLoc)) + return ExprError(); - return Owned(MaybeBindToTemporary(TheCall.release()).release()); + return Owned(MaybeBindToTemporary(TheCall.release()).release()); + } + return ExprError(Diag(Fn->getLocStart(), + diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); } } } @@ -2893,7 +2865,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // lookup and whether there were any explicitly-specified template arguments. bool ADL = true; bool HasExplicitTemplateArgs = 0; - const TemplateArgument *ExplicitTemplateArgs = 0; + const TemplateArgumentLoc *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -2932,19 +2904,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (!FDecl) return ExprError(); - // Update Fn to refer to the actual function selected. - Expr *NewFn = 0; - if (Qualifier) - NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), - Fn->getLocStart(), - false, false, - QualifierRange, - Qualifier); - else - NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(), - Fn->getLocStart()); - Fn->Destroy(Context); - Fn = NewFn; + Fn = FixOverloadedFunctionReference(Fn, FDecl); } } @@ -3543,7 +3503,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else { + } else if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) + ; + else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); @@ -4080,7 +4043,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // This check seems unnatural, however it is necessary to ensure the proper // conversion of functions/arrays. If the conversion were done for all - // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary + // DeclExpr's (created by ActOnIdExpression), it would mess up the unary // expressions that surpress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. @@ -4428,6 +4391,10 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) return InvalidOperands(Loc, lex, rex); + // Vector shifts promote their scalar inputs to vector type. + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(Loc, lex, rex); + // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 QualType LHSTy = Context.isPromotableBitField(lex); @@ -5083,7 +5050,6 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, static NamedDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: return cast<DeclRefExpr>(E)->getDecl(); case Stmt::MemberExprClass: // If this is an arrow operator, the address is an offset from @@ -5199,7 +5165,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. - if (isa<QualifiedDeclRefExpr>(op)) { + if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (FD->getType()->isReferenceType()) { @@ -5216,7 +5182,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) { // Okay: we can take the address of a function. // As above. - if (isa<QualifiedDeclRefExpr>(op) && MD->isInstance()) + if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier() && + MD->isInstance()) return Context.getMemberPointerType(op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); } else if (!isa<FunctionDecl>(dcl)) @@ -5426,6 +5393,72 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, OpLoc)); } +/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// ParenRange in parentheses. +static void SuggestParentheses(Sema &Self, SourceLocation Loc, + const PartialDiagnostic &PD, + SourceRange ParenRange) +{ + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); + if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Self.Diag(Loc, PD); + return; + } + + Self.Diag(Loc, PD) + << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") + << CodeModificationHint::CreateInsertion(EndLoc, ")"); +} + +/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison +/// operators are mixed in a way that suggests that the programmer forgot that +/// comparison operators have higher precedence. The most typical example of +/// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". +static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc,Expr *lhs,Expr *rhs){ + typedef BinaryOperator BinOp; + BinOp::Opcode lhsopc = static_cast<BinOp::Opcode>(-1), + rhsopc = static_cast<BinOp::Opcode>(-1); + if (BinOp *BO = dyn_cast<BinOp>(lhs)) + lhsopc = BO->getOpcode(); + if (BinOp *BO = dyn_cast<BinOp>(rhs)) + rhsopc = BO->getOpcode(); + + // Subs are not binary operators. + if (lhsopc == -1 && rhsopc == -1) + return; + + // Bitwise operations are sometimes used as eager logical ops. + // Don't diagnose this. + if ((BinOp::isComparisonOp(lhsopc) || BinOp::isBitwiseOp(lhsopc)) && + (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) + return; + + if (BinOp::isComparisonOp(lhsopc)) + SuggestParentheses(Self, OpLoc, + PDiag(diag::warn_precedence_bitwise_rel) + << SourceRange(lhs->getLocStart(), OpLoc) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), + SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); + else if (BinOp::isComparisonOp(rhsopc)) + SuggestParentheses(Self, OpLoc, + PDiag(diag::warn_precedence_bitwise_rel) + << SourceRange(OpLoc, rhs->getLocEnd()) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), + SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); +} + +/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky +/// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3". +/// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does. +static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + if (BinaryOperator::isBitwiseOp(Opc)) + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); +} + // Binary Operators. 'Tok' is the token for the operator. Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, @@ -5436,6 +5469,9 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, assert((lhs != 0) && "ActOnBinOp(): missing left expression"); assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" + DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { @@ -5451,7 +5487,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, Expr *Args[2] = { lhs, rhs }; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, Args, 2, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); } // Build the (potentially-overloaded, potentially-dependent) @@ -5569,7 +5605,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, Functions); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, &Input, 1, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); } return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); @@ -5673,6 +5709,10 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (!Dependent) { bool DidWarnAboutNonPOD = false; + if (RequireCompleteType(TypeLoc, Res->getType(), + diag::err_offsetof_incomplete_type)) + return ExprError(); + // FIXME: Dependent case loses a lot of information here. And probably // leaks like a sieve. for (unsigned i = 0; i != NumComponents; ++i) { @@ -6240,21 +6280,21 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody() && - Function->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { + if (!Function->getBody() && Function->isImplicitlyInstantiable()) { bool AlreadyInstantiated = false; if (FunctionTemplateSpecializationInfo *SpecInfo = Function->getTemplateSpecializationInfo()) { if (SpecInfo->getPointOfInstantiation().isInvalid()) SpecInfo->setPointOfInstantiation(Loc); - else + else if (SpecInfo->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } else if (MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo()) { if (MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(Loc); - else + else if (MSInfo->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d4d031f..4868c14 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -22,41 +22,6 @@ #include "llvm/ADT/STLExtras.h" using namespace clang; -/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function -/// name (e.g., 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. -Sema::OwningExprResult -Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, - TypeTy *Ty, bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand) { - //FIXME: Preserve type source info. - QualType ConvType = GetTypeFromParser(Ty); - CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName - = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); - return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, - &SS, isAddressOfOperand); -} - -/// ActOnCXXOperatorFunctionIdExpr - 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. -Sema::OwningExprResult -Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand) { - DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op); - return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS, - isAddressOfOperand); -} - /// ActOnCXXTypeidOfType - Parse typeid( type-id ). Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, @@ -212,7 +177,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, PDiag(diag::err_invalid_incomplete_type_use) << FullRange)) return ExprError(); - + if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); @@ -288,7 +253,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, << FullRange); assert(NumExprs == 0 && "Expected 0 expressions"); - // C++ [expr.type.conv]p2: // The expression T(), where T is a simple-type-specifier for a non-array // complete object type or the (possibly cv-qualified) void type, creates an @@ -312,7 +276,6 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { Expr *ArraySize = 0; - unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { @@ -323,14 +286,25 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); + + if (ParenTypeId) { + // Can't have dynamic array size when the type-id is in parentheses. + Expr *NumElts = (Expr *)Chunk.Arr.NumElts; + if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() && + !NumElts->isIntegerConstantExpr(Context)) { + Diag(D.getTypeObject(0).Loc, diag::err_new_paren_array_nonconst) + << NumElts->getSourceRange(); + return ExprError(); + } + } + ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); - Skip = 1; + D.DropFirstTypeObject(); } // Every dimension shall be of constant size. - if (D.getNumTypeObjects() > 0 && - D.getTypeObject(0).Kind == DeclaratorChunk::Array) { - for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) { + if (ArraySize) { + for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) break; @@ -345,10 +319,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } } - + //FIXME: Store DeclaratorInfo in CXXNew expression. DeclaratorInfo *DInfo = 0; - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip); + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo); if (D.isInvalidType()) return ExprError(); @@ -935,7 +909,7 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, // FIXME: Store DeclaratorInfo in the expression. DeclaratorInfo *DInfo = 0; TagDecl *OwnedTag = 0; - QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl @@ -1139,6 +1113,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); } + + if (ICS.UserDefined.After.Second == ICK_Pointer_Member && + ToType.getNonReferenceType()->isMemberFunctionPointerType()) + CastKind = CastExpr::CK_BaseToDerivedMemberPointer; From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), CastKind, CastArg.takeAs<Expr>(), @@ -1390,7 +1368,8 @@ QualType Sema::CheckPointerToMemberOperands( LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) - << OpSpelling << 1 << LType << lex->getSourceRange(); + << OpSpelling << 1 << LType + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } @@ -1403,8 +1382,10 @@ QualType Sema::CheckPointerToMemberOperands( // overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { + const char *ReplaceStr = isIndirect ? ".*" : "->*"; Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType() << lex->getSourceRange(); + << (int)isIndirect << lex->getType() << + CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr); return QualType(); } } @@ -2105,110 +2086,6 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, return move(Base); } -Sema::OwningExprResult -Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - IdentifierInfo *ClassName, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - if (SS.isInvalid()) - return ExprError(); - - QualType BaseType; - if (isUnknownSpecialization(SS)) - BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(), - ClassName); - else { - TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); - - // FIXME: If Base is dependent, we might not be able to resolve it here. - if (!BaseTy) { - Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << ClassName; - return ExprError(); - } - - BaseType = GetTypeFromParser(BaseTy); - } - - return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind, - SourceRange(ClassNameLoc), - BaseType.getAsOpaquePtr(), - SS, HasTrailingLParen); -} - -Sema::OwningExprResult -Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceRange TypeRange, - TypeTy *T, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - QualType Type = QualType::getFromOpaquePtr(T); - CanQualType CanType = Context.getCanonicalType(Type); - DeclarationName DtorName = - Context.DeclarationNames.getCXXDestructorName(CanType); - - OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, - TypeRange.getBegin(), DtorName, DeclPtrTy(), - &SS); - if (Result.isInvalid() || HasTrailingLParen) - return move(Result); - - // The only way a reference to a destructor can be used is to - // immediately call them. Since the next token is not a '(', produce a - // diagnostic and build the call now. - Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd()); - Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa<CXXPseudoDestructorExpr>(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - - return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, - MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); -} - -Sema::OwningExprResult -Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - OverloadedOperatorKind OverOpKind, - const CXXScopeSpec *SS) { - if (SS && SS->isInvalid()) - return ExprError(); - - DeclarationName Name = - Context.DeclarationNames.getCXXOperatorName(OverOpKind); - - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - Name, DeclPtrTy(), SS); -} - -Sema::OwningExprResult -Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - TypeTy *Ty, - const CXXScopeSpec *SS) { - if (SS && SS->isInvalid()) - return ExprError(); - - //FIXME: Preserve type source info. - QualType ConvType = GetTypeFromParser(Ty); - CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName = - Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); - - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - ConvName, DeclPtrTy(), SS); -} - CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { MemberExpr *ME = @@ -2333,6 +2210,7 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl))) Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + // FIXME: Do we have to know if there are explicit template arguments? if (Method && !Method->isStatic()) { Ctx = Method->getParent(); if (isa<CXXMethodDecl>(D) && !FunTmpl) @@ -2350,6 +2228,12 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, // Determine whether the declaration(s) we found are actually in a base // class. If not, this isn't an implicit member reference. ThisType = MD->getThisType(Context); + + // If the type of "this" is dependent, we can't tell if the member is in a + // base class or not, so treat this as a dependent implicit member reference. + if (ThisType->isDependentType()) + return true; + QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx)); QualType ClassType = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent())); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index dd877c1..93752e1 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1239,6 +1239,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, BaseEnd = Class->bases_end(); Base != BaseEnd; ++Base) { const RecordType *BaseType = Base->getType()->getAs<RecordType>(); + // In dependent contexts, we do ADL twice, and the first time around, + // the base type might be a dependent TemplateSpecializationType, or a + // TemplateTypeParmType. If that happens, simply ignore it. + // FIXME: If we want to support export, we probably need to add the + // namespace of the template in a TemplateSpecializationType, or even + // the classes and namespaces of known non-dependent arguments. + if (!BaseType) + continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (AssociatedClasses.insert(BaseDecl)) { // Find the associated namespace for this base class. @@ -1561,7 +1569,7 @@ static void CollectFunctionDecl(Sema::FunctionSet &Functions, Functions.insert(FunTmpl); } -void Sema::ArgumentDependentLookup(DeclarationName Name, +void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, FunctionSet &Functions) { // Find all of the associated namespaces and classes based on the @@ -1572,6 +1580,13 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, AssociatedNamespaces, AssociatedClasses); + QualType T1, T2; + if (Operator) { + T1 = Args[0]->getType(); + if (NumArgs >= 2) + T2 = Args[1]->getType(); + } + // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent @@ -1608,7 +1623,10 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, continue; } - CollectFunctionDecl(Functions, D); + FunctionDecl *Fn; + if (!Operator || !(Fn = dyn_cast<FunctionDecl>(D)) || + IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context)) + CollectFunctionDecl(Functions, D); } } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ebcf3ad..946e282 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -999,6 +999,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // here. That is handled by CheckPointerConversion. if (getLangOptions().CPlusPlus && FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + !RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) && IsDerivedFrom(FromPointeeType, ToPointeeType)) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, @@ -2444,7 +2445,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2489,7 +2490,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2761,7 +2762,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); if (S) LookupOverloadedOperatorName(Op, S, T1, T2, Functions); - ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions); AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); @@ -3119,9 +3120,8 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, } } -/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers -/// , if any, found in visible type conversion functions found in ArgExpr's -/// type. +/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers, +/// if any, found in visible type conversion functions found in ArgExpr's type. static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { Qualifiers VRQuals; const RecordType *TyRec; @@ -3139,7 +3139,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); OverloadedFunctionDecl *Conversions = - ClassDecl->getVisibleConversionFunctions(); + ClassDecl->getVisibleConversionFunctions(); for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(); @@ -3887,7 +3887,7 @@ void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading) { @@ -3908,7 +3908,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, } // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, Args, NumArgs, Functions); + ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions); // Erase all of the candidates we already knew about. // FIXME: This is suboptimal. Is there a better way? @@ -4279,7 +4279,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } bool HasExplicitTemplateArgs = false; - const TemplateArgument *ExplicitTemplateArgs = 0; + const TemplateArgumentLoc *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; // Try to dig out the overloaded function. @@ -4287,10 +4287,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) { Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl()); + HasExplicitTemplateArgs = DR->hasExplicitTemplateArgumentList(); + ExplicitTemplateArgs = DR->getTemplateArgs(); + NumExplicitTemplateArgs = DR->getNumTemplateArgs(); } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) { Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl()); - // FIXME: Explicit template arguments + HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList(); + ExplicitTemplateArgs = ME->getTemplateArgs(); + NumExplicitTemplateArgs = ME->getNumTemplateArgs(); } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) { TemplateName Name = TIRE->getTemplateName(); Ovl = Name.getAsOverloadedFunctionDecl(); @@ -4367,6 +4372,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // when converting to member pointer. if (Method->isStatic() == IsMember) continue; + + // If we have explicit template arguments, skip non-templates. + if (HasExplicitTemplateArgs) + continue; } else if (IsMember) continue; @@ -4443,7 +4452,7 @@ static void AddOverloadedCallCandidate(Sema &S, AnyFunctionDecl Callee, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -4475,7 +4484,7 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, DeclarationName &UnqualifiedName, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -4543,7 +4552,7 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -4934,6 +4943,134 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } +Action::OwningExprResult +Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + ExprArg Base, ExprArg Idx) { + Expr *Args[2] = { static_cast<Expr*>(Base.get()), + static_cast<Expr*>(Idx.get()) }; + DeclarationName OpName = + Context.DeclarationNames.getCXXOperatorName(OO_Subscript); + + // If either side is type-dependent, create an appropriate dependent + // expression. + if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { + + OverloadedFunctionDecl *Overloads + = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + + DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, + LLoc, false, false); + + Base.release(); + Idx.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn, + Args, 2, + Context.DependentTy, + RLoc)); + } + + // Build an empty overload set. + OverloadCandidateSet CandidateSet; + + // Subscript can only be overloaded as a member function. + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + + // Add builtin operator candidates. + AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, LLoc, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); + if (PerformObjectArgumentInitialization(Args[0], Method) || + PerformCopyInitialization(Args[1], + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAs<FunctionType>()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + LLoc); + UsualUnaryConversions(FnExpr); + + Base.release(); + Idx.release(); + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, + FnExpr, Args, 2, + ResultTy, RLoc)); + + if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), + FnDecl)) + return ExprError(); + + return MaybeBindToTemporary(TheCall.release()); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "passing") || + PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: { + // No viable function; try to create a built-in operation, which will + // produce an error. Then, show the non-viable candidates. + OwningExprResult Result = + CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); + assert(Result.isInvalid() && + "C++ subscript operator overloading is missing candidates!"); + if (Result.isInvalid()) + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, + "[]", LLoc); + return move(Result); + } + + case OR_Ambiguous: + Diag(LLoc, diag::err_ovl_ambiguous_oper) + << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + "[]", LLoc); + return ExprError(); + + case OR_Deleted: + Diag(LLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() << "[]" + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // We matched a built-in operator; build it. + Base.release(); + Idx.release(); + return CreateBuiltinArraySubscriptExpr(Owned(Args[0]), LLoc, + Owned(Args[1]), RLoc); +} + /// BuildCallToMemberFunction - Build a call to a member /// function. MemExpr is the expression that refers to the member /// function (and includes the object parameter), Args/NumArgs are the @@ -4967,10 +5104,15 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; Func != FuncEnd; ++Func) { - if ((Method = dyn_cast<CXXMethodDecl>(*Func))) + if ((Method = dyn_cast<CXXMethodDecl>(*Func))) { + // If explicit template arguments were provided, we can't call a + // non-template member function. + if (MemExpr->hasExplicitTemplateArgumentList()) + continue; + AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); - else + } else AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), MemExpr->hasExplicitTemplateArgumentList(), MemExpr->getTemplateArgs(), @@ -5361,8 +5503,14 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); - NewExpr->setType(PE->getSubExpr()->getType()); - return NewExpr; + PE->setSubExpr(NewExpr); + PE->setType(NewExpr->getType()); + } else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + Expr *NewExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + assert(Context.hasSameType(ICE->getSubExpr()->getType(), + NewExpr->getType()) && + "Implicit cast type cannot be determined from overload"); + ICE->setSubExpr(NewExpr); } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); @@ -5370,18 +5518,19 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (Method->isStatic()) { // Do nothing: static member functions aren't any different // from non-member functions. - } else if (QualifiedDeclRefExpr *DRE - = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) { - // We have taken the address of a pointer to member - // function. Perform the computation here so that we get the - // appropriate pointer to member type. - DRE->setDecl(Fn); - DRE->setType(Fn->getType()); - QualType ClassType - = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); - E->setType(Context.getMemberPointerType(Fn->getType(), - ClassType.getTypePtr())); - return E; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr())) { + if (DRE->getQualifier()) { + // We have taken the address of a pointer to member + // function. Perform the computation here so that we get the + // appropriate pointer to member type. + DRE->setDecl(Fn); + DRE->setType(Fn->getType()); + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); + E->setType(Context.getMemberPointerType(Fn->getType(), + ClassType.getTypePtr())); + return E; + } } // FIXME: TemplateIdRefExpr referring to a member function template // specialization! @@ -5393,26 +5542,35 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { return UnOp; } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { assert((isa<OverloadedFunctionDecl>(DR->getDecl()) || - isa<FunctionTemplateDecl>(DR->getDecl())) && - "Expected overloaded function or function template"); + isa<FunctionTemplateDecl>(DR->getDecl()) || + isa<FunctionDecl>(DR->getDecl())) && + "Expected function or function template"); DR->setDecl(Fn); E->setType(Fn->getType()); } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { MemExpr->setMemberDecl(Fn); E->setType(Fn->getType()); } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(E)) { - // FIXME: We should capture the template arguments here. - if (NestedNameSpecifier *Qualifier = TID->getQualifier()) - E = new (Context) QualifiedDeclRefExpr(Fn, Fn->getType(), - TID->getTemplateNameLoc(), - /*FIXME?*/false, /*FIXME?*/false, - TID->getQualifierRange(), - Qualifier); - else - E = new (Context) DeclRefExpr(Fn, Fn->getType(), - TID->getTemplateNameLoc()); + E = DeclRefExpr::Create(Context, + TID->getQualifier(), TID->getQualifierRange(), + Fn, TID->getTemplateNameLoc(), + true, + TID->getLAngleLoc(), + TID->getTemplateArgs(), + TID->getNumTemplateArgs(), + TID->getRAngleLoc(), + Fn->getType(), + /*FIXME?*/false, /*FIXME?*/false); - TID->Destroy(Context); + // FIXME: Don't destroy TID here, since we need its template arguments + // to survive. + // TID->Destroy(Context); + } else if (isa<UnresolvedFunctionNameExpr>(E)) { + return DeclRefExpr::Create(Context, + /*Qualifier=*/0, + /*QualifierRange=*/SourceRange(), + Fn, E->getLocStart(), + Fn->getType(), false, false); } else { assert(false && "Invalid reference to overloaded function"); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 1453424..6a65bd1 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -70,7 +70,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { SourceLocation Loc; SourceRange R1, R2; - if (!E->isUnusedResultAWarning(Loc, R1, R2)) + if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) return; // Okay, we have an unused result. Depending on what the base expression is, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0f22320..3c56358 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -98,29 +98,43 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { } TemplateNameKind Sema::isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult) { + DeclarationName TName; + + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + TName = DeclarationName(Name.Identifier); + break; + + case UnqualifiedId::IK_OperatorFunctionId: + TName = Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator); + break; + + default: + return TNK_Non_template; + } + // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (ObjectTypePtr) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. - assert((!SS || !SS->isSet()) && - "ObjectType and scope specifier cannot coexist"); + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); - } else if (SS && SS->isSet()) { + } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. - LookupCtx = computeDeclContext(*SS, EnteringContext); - isDependent = isDependentScopeSpecifier(*SS); + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = isDependentScopeSpecifier(SS); } LookupResult Found; @@ -132,10 +146,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) return TNK_Non_template; - LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName); + LookupQualifiedName(Found, LookupCtx, TName, LookupOrdinaryName); if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) { // C++ [basic.lookup.classref]p1: @@ -150,7 +164,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // // FIXME: When we're instantiating a template, do we actually have to // look in the scope of the template? Seems fishy... - LookupName(Found, S, &II, LookupOrdinaryName); + LookupName(Found, S, TName, LookupOrdinaryName); ObjectTypeSearchedInScope = true; } } else if (isDependent) { @@ -158,7 +172,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TNK_Non_template; } else { // Perform unqualified name lookup in the current scope. - LookupName(Found, S, &II, LookupOrdinaryName); + LookupName(Found, S, TName, LookupOrdinaryName); } // FIXME: Cope with ambiguous name-lookup results. @@ -177,7 +191,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // postfix-expression and [...] // LookupResult FoundOuter; - LookupName(FoundOuter, S, &II, LookupOrdinaryName); + LookupName(FoundOuter, S, TName, LookupOrdinaryName); // FIXME: Handle ambiguities in this lookup better NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context)); @@ -194,8 +208,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) { - Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) - << &II; + Diag(Name.getSourceRange().getBegin(), + diag::err_nested_name_member_ref_lookup_ambiguous) + << TName + << Name.getSourceRange(); Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type) << QualType::getFromOpaquePtr(ObjectTypePtr); Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope); @@ -206,9 +222,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, } } - if (SS && SS->isSet() && !SS->isInvalid()) { + if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(Template)) TemplateResult @@ -321,8 +337,11 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, TypeTy *DefaultT) { TemplateTypeParmDecl *Parm = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); - // FIXME: Preserve type source info. - QualType Default = GetTypeFromParser(DefaultT); + + DeclaratorInfo *DefaultDInfo; + GetTypeFromParser(DefaultT, &DefaultDInfo); + + assert(DefaultDInfo && "expected source information for type"); // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of @@ -337,12 +356,12 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the template argument itself. - if (CheckTemplateArgument(Parm, Default, DefaultLoc)) { + if (CheckTemplateArgument(Parm, DefaultDInfo)) { Parm->setInvalidDecl(); return; } - Parm->setDefaultArgument(Default, DefaultLoc, false); + Parm->setDefaultArgument(DefaultDInfo, false); } /// \brief Check that the type of a non-type template parameter is @@ -610,11 +629,19 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SemanticContext = PrevDecl->getDeclContext(); } else { // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semntic context for our new + // context we computed is the semantic context for our new // declaration. PrevDecl = 0; SemanticContext = OutermostContext; } + + if (CurContext->isDependentContext()) { + // If this is a dependent context, we don't want to link the friend + // class template to the template in scope, because that would perform + // checking of the template parameter lists that can't be performed + // until the outer context is instantiated. + PrevDecl = 0; + } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = 0; @@ -843,7 +870,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, SawParameterPack = true; ParameterPackLoc = NewTypeParm->getLocation(); } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && - NewTypeParm->hasDefaultArgument()) { + NewTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; @@ -853,8 +880,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge the default argument from the old declaration to the // new declaration. SawDefaultArgument = true; - NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(), - OldTypeParm->getDefaultArgumentLoc(), + NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgumentInfo(), true); PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc(); } else if (NewTypeParm->hasDefaultArgument()) { @@ -1096,24 +1122,28 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, SourceLocation *TemplateArgLocs, - llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) { + llvm::SmallVector<TemplateArgumentLoc, 16> &TemplateArgs) { TemplateArgs.reserve(TemplateArgsIn.size()); void **Args = TemplateArgsIn.getArgs(); bool *ArgIsType = TemplateArgsIn.getArgIsType(); for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { - TemplateArgs.push_back( - ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], - //FIXME: Preserve type source info. - Sema::GetTypeFromParser(Args[Arg])) - : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg]))); + if (ArgIsType[Arg]) { + DeclaratorInfo *DI; + QualType T = Sema::GetTypeFromParser(Args[Arg], &DI); + if (!DI) DI = Context.getTrivialDeclaratorInfo(T, TemplateArgLocs[Arg]); + TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(T), DI)); + } else { + Expr *E = reinterpret_cast<Expr *>(Args[Arg]); + TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E)); + } } } QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { TemplateDecl *Template = Name.getAsTemplateDecl(); @@ -1155,7 +1185,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Converted.flatSize()); // FIXME: CanonType is not actually the canonical type, and unfortunately - // it is a TemplateTypeSpecializationType that we will never use again. + // it is a TemplateSpecializationType that we will never use again. // In the future, we need to teach getTemplateSpecializationType to only // build the canonical type and return that to us. CanonType = Context.getCanonicalType(CanonType); @@ -1190,7 +1220,6 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - //FIXME: Preserve type source info. return Context.getTemplateSpecializationType(Name, TemplateArgs, NumTemplateArgs, CanonType); } @@ -1199,13 +1228,13 @@ Action::TypeResult Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, + SourceLocation *TemplateArgLocsIn, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocsIn, TemplateArgs); QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc, TemplateArgs.data(), @@ -1216,7 +1245,16 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, if (Result.isNull()) return true; - return Result.getAsOpaquePtr(); + DeclaratorInfo *DI = Context.CreateDeclaratorInfo(Result); + TemplateSpecializationTypeLoc TL + = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); + TL.setTemplateNameLoc(TemplateLoc); + TL.setLAngleLoc(LAngleLoc); + TL.setRAngleLoc(RAngleLoc); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); + + return CreateLocInfoType(Result, DI).getAsOpaquePtr(); } Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, @@ -1226,7 +1264,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, if (TypeResult.isInvalid()) return Sema::TypeResult(); - QualType Type = QualType::getFromOpaquePtr(TypeResult.get()); + // FIXME: preserve source info, ideally without copying the DI. + DeclaratorInfo *DI; + QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); @@ -1256,7 +1296,7 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { // FIXME: Can we do any checking at this point? I guess we could check the @@ -1296,13 +1336,13 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, + SourceLocation *TemplateArgSLs, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgSLs, TemplateArgs); TemplateArgsIn.release(); return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), @@ -1312,41 +1352,6 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, RAngleLoc); } -Sema::OwningExprResult -Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - TemplateTy TemplateD, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { - TemplateName Template = TemplateD.getAsVal<TemplateName>(); - - // FIXME: We're going to end up looking up the template based on its name, - // twice! - DeclarationName Name; - if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) - Name = ActualTemplate->getDeclName(); - else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) - Name = Ovl->getDeclName(); - else - Name = Template.getAsDependentTemplateName()->getName(); - - // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); - TemplateArgsIn.release(); - - // Do we have the save the actual template name? We might need it... - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc, - Name, true, LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, DeclPtrTy(), &SS); -} - /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template @@ -1356,9 +1361,8 @@ Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, /// of the "template" keyword, and "apply" is the \p Name. Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType) { if ((ObjectType && computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || @@ -1380,11 +1384,13 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; - TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType, + TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, false, Template); if (TNK == TNK_Non_template) { - Diag(NameLoc, diag::err_template_kw_refers_to_non_template) - << &Name; + Diag(Name.getSourceRange().getBegin(), + diag::err_template_kw_refers_to_non_template) + << GetNameFromUnqualifiedId(Name) + << Name.getSourceRange(); return TemplateTy(); } @@ -1393,12 +1399,32 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); + + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Name.Identifier)); + + case UnqualifiedId::IK_OperatorFunctionId: + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Name.OperatorFunctionId.Operator)); + + default: + break; + } + + Diag(Name.getSourceRange().getBegin(), + diag::err_template_kw_refers_to_non_template) + << GetNameFromUnqualifiedId(Name) + << Name.getSourceRange(); + return TemplateTy(); } bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgument &Arg, + const TemplateArgumentLoc &AL, TemplateArgumentListBuilder &Converted) { + const TemplateArgument &Arg = AL.getArgument(); + // Check template type parameter. if (Arg.getKind() != TemplateArgument::Type) { // C++ [temp.arg.type]p1: @@ -1407,19 +1433,19 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, // We have a template type parameter but the template argument // is not a type. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); + SourceRange SR = AL.getSourceRange(); + Diag(SR.getBegin(), diag::err_template_arg_must_be_type) << SR; Diag(Param->getLocation(), diag::note_template_param_here); return true; } - if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation())) + if (CheckTemplateArgument(Param, AL.getSourceDeclaratorInfo())) return true; // Add the converted template type argument. Converted.Append( - TemplateArgument(Arg.getLocation(), - Context.getCanonicalType(Arg.getAsType()))); + TemplateArgument(Context.getCanonicalType(Arg.getAsType()))); return false; } @@ -1428,7 +1454,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, bool PartialTemplateArgs, @@ -1474,7 +1500,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // Decode the template argument - TemplateArgument Arg; + TemplateArgumentLoc Arg; + if (ArgIdx >= NumArgs) { // Retrieve the default template argument from the template // parameter. @@ -1489,11 +1516,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TTP->hasDefaultArgument()) break; - QualType ArgType = TTP->getDefaultArgument(); + DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. - if (ArgType->isDependentType()) { + if (ArgType->getType()->isDependentType()) { InstantiatingTemplate Inst(*this, TemplateLoc, Template, Converted.getFlatArguments(), Converted.flatSize(), @@ -1507,10 +1534,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TTP->getDeclName()); } - if (ArgType.isNull()) + if (!ArgType) return true; - Arg = TemplateArgument(TTP->getLocation(), ArgType); + Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) @@ -1530,7 +1557,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (E.isInvalid()) return true; - Arg = TemplateArgument(E.takeAs<Expr>()); + Expr *Ex = E.takeAs<Expr>(); + Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); } else { TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); @@ -1539,7 +1567,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // FIXME: Subst default argument - Arg = TemplateArgument(TempParm->getDefaultArgument()); + Arg = TemplateArgumentLoc(TemplateArgument(TempParm->getDefaultArgument()), + TempParm->getDefaultArgument()); } } else { // Retrieve the template argument produced by the user. @@ -1592,13 +1621,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } } - switch (Arg.getKind()) { + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; case TemplateArgument::Expression: { - Expr *E = Arg.getAsExpr(); + Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) Invalid = true; @@ -1611,10 +1640,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Integral: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.Append(Arg); + Converted.Append(Arg.getArgument()); break; - case TemplateArgument::Type: + case TemplateArgument::Type: { // We have a non-type template parameter but the template // argument is a type. @@ -1625,14 +1654,17 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // // We warn specifically about this case, since it can be rather // confusing for users. - if (Arg.getAsType()->isFunctionType()) - Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig) - << Arg.getAsType(); + QualType T = Arg.getArgument().getAsType(); + SourceRange SR = Arg.getSourceRange(); + if (T->isFunctionType()) + Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) + << SR << T; else - Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr); + Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR; Diag((*Param)->getLocation(), diag::note_template_param_here); Invalid = true; break; + } case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); @@ -1643,13 +1675,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - switch (Arg.getKind()) { + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; case TemplateArgument::Expression: { - Expr *ArgExpr = Arg.getAsExpr(); + Expr *ArgExpr = Arg.getArgument().getAsExpr(); if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) @@ -1658,7 +1690,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Add the converted template argument. Decl *D = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl(); - Converted.Append(TemplateArgument(Arg.getLocation(), D)); + Converted.Append(TemplateArgument(D)); continue; } } @@ -1675,7 +1707,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Declaration: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.Append(Arg); + Converted.Append(Arg.getArgument()); break; case TemplateArgument::Integral: @@ -1698,7 +1730,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - QualType Arg, SourceLocation ArgLoc) { + DeclaratorInfo *ArgInfo) { + assert(ArgInfo && "invalid DeclaratorInfo"); + QualType Arg = ArgInfo->getType(); + // C++ [temp.arg.type]p2: // A local type, a type with no linkage, an unnamed type or a type // compounded from any of these types shall not be used as a @@ -1710,12 +1745,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, Tag = EnumT; else if (const RecordType *RecordT = Arg->getAs<RecordType>()) Tag = RecordT; - if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) - return Diag(ArgLoc, diag::err_template_arg_local_type) - << QualType(Tag, 0); - else if (Tag && !Tag->getDecl()->getDeclName() && + if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { + SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + return Diag(SR.getBegin(), diag::err_template_arg_local_type) + << QualType(Tag, 0) << SR; + } else if (Tag && !Tag->getDecl()->getDeclName() && !Tag->getDecl()->getTypedefForAnonDecl()) { - Diag(ArgLoc, diag::err_template_arg_unnamed_type); + SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR; Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); return true; } @@ -1845,7 +1882,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { // template-parameter shall be one of: [...] // // -- a pointer to member expressed as described in 5.3.1. - QualifiedDeclRefExpr *DRE = 0; + DeclRefExpr *DRE = 0; // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { @@ -1860,8 +1897,11 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { } if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) - if (UnOp->getOpcode() == UnaryOperator::AddrOf) - DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr()); + if (UnOp->getOpcode() == UnaryOperator::AddrOf) { + DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); + if (DRE && !DRE->getQualifier()) + DRE = 0; + } if (!DRE) return Diag(Arg->getSourceRange().getBegin(), @@ -2012,7 +2052,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return false; } - Converted = TemplateArgument(StartLoc, Value, + Converted = TemplateArgument(Value, ParamType->isEnumeralType() ? ParamType : IntegerType); return false; @@ -2086,7 +2126,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Member) Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Member); + Converted = TemplateArgument(Member); return false; } @@ -2096,7 +2136,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Entity) Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2136,7 +2176,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Entity) Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2177,7 +2217,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2207,7 +2247,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Member) Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Member); + Converted = TemplateArgument(Member); return false; } @@ -2719,7 +2759,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TTP->hasDefaultArgument()) { Diag(TTP->getDefaultArgumentLoc(), diag::err_default_arg_in_partial_spec); - TTP->setDefaultArgument(QualType(), SourceLocation(), false); + TTP->removeDefaultArgument(); } } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { @@ -2778,7 +2818,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); // Check that the template argument list is well-formed for this @@ -2877,8 +2917,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted.flatSize()); // Create a new class template partial specialization declaration node. - TemplateParameterList *TemplateParams - = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); ClassTemplatePartialSpecializationDecl *Partial @@ -2888,6 +2926,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParams, ClassTemplate, Converted, + TemplateArgs.data(), + TemplateArgs.size(), PrevPartial); if (PrevPartial) { @@ -2898,6 +2938,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } Specialization = Partial; + // If we are providing an explicit specialization of a member class + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + PrevPartial->setMemberSpecialization(); + // Check that all of the template parameters of the class template // partial specialization are deducible from the template // arguments. If not, this class template partial specialization @@ -2905,6 +2950,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, llvm::SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); unsigned NumNonDeducible = 0; for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) @@ -3070,8 +3116,6 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. /// -/// \param S the semantic analysis object. -/// /// \param NewLoc the location of the new explicit specialization or /// instantiation. /// @@ -3089,14 +3133,13 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// /// \returns true if there was an error that should prevent the introduction of /// the new declaration into the AST, false otherwise. -static bool -CheckSpecializationInstantiationRedecl(Sema &S, - SourceLocation NewLoc, - TemplateSpecializationKind NewTSK, - NamedDecl *PrevDecl, - TemplateSpecializationKind PrevTSK, - SourceLocation PrevPointOfInstantiation, - bool &SuppressNew) { +bool +Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew) { SuppressNew = false; switch (NewTSK) { @@ -3134,9 +3177,9 @@ CheckSpecializationInstantiationRedecl(Sema &S, // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. - S.Diag(NewLoc, diag::err_specialization_after_instantiation) + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; - S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) + Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) << (PrevTSK != TSK_ImplicitInstantiation); return true; @@ -3169,10 +3212,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // If an entity is the subject of both an explicit instantiation // declaration and an explicit instantiation definition in the same // translation unit, the definition shall follow the declaration. - S.Diag(NewLoc, - diag::err_explicit_instantiation_declaration_after_definition); - S.Diag(PrevPointOfInstantiation, - diag::note_explicit_instantiation_definition_here); + Diag(NewLoc, + diag::err_explicit_instantiation_declaration_after_definition); + Diag(PrevPointOfInstantiation, + diag::note_explicit_instantiation_definition_here); assert(PrevPointOfInstantiation.isValid() && "Explicit instantiation without point of instantiation?"); SuppressNew = true; @@ -3198,10 +3241,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // In C++98/03 mode, we only give an extension warning here, because it // is not not harmful to try to explicitly instantiate something that // has been explicitly specialized. - if (!S.getLangOptions().CPlusPlus0x) { - S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) + if (!getLangOptions().CPlusPlus0x) { + Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) << PrevDecl; - S.Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_previous_template_specialization); } SuppressNew = true; @@ -3217,10 +3260,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // For a given template and a given set of template-arguments, // - an explicit instantiation definition shall appear at most once // in a program, - S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate) + Diag(NewLoc, diag::err_explicit_instantiation_duplicate) << PrevDecl; - S.Diag(PrevPointOfInstantiation, - diag::note_previous_explicit_instantiation); + Diag(PrevPointOfInstantiation, + diag::note_previous_explicit_instantiation); SuppressNew = true; return false; } @@ -3264,7 +3307,7 @@ bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, NamedDecl *&PrevDecl) { @@ -3333,7 +3376,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that spe- cialization shall be declared + // explicitly specialized then that specialization shall be declared // before the first use of that specialization that would cause an implicit // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. @@ -3620,7 +3663,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); // Check that the template argument list is well-formed for this @@ -3659,7 +3702,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK, PrevDecl, PrevDecl->getSpecializationKind(), PrevDecl->getPointOfInstantiation(), @@ -3723,8 +3766,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); - Specialization->setPointOfInstantiation(TemplateNameLoc); - // C++ [temp.explicit]p3: // A definition of a class template or class member template // shall be in scope at the point of the explicit instantiation of @@ -3736,8 +3777,12 @@ Sema::ActOnExplicitInstantiation(Scope *S, = cast_or_null<ClassTemplateSpecializationDecl>( Specialization->getDefinition(Context)); if (!Def) - InstantiateClassTemplateSpecialization(Specialization, TSK); - else // Instantiate the members of this class template specialization. + InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); + + // Instantiate the members of this class template specialization. + Def = cast_or_null<ClassTemplateSpecializationDecl>( + Specialization->getDefinition(Context)); + if (Def) InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); return DeclPtrTy::make(Specialization); @@ -3819,7 +3864,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); bool SuppressNew = false; assert(MSInfo && "No member specialization information?"); - if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, PrevDecl, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), @@ -3843,13 +3888,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, Diag(Pattern->getLocation(), diag::note_forward_declaration) << Pattern; return true; - } else if (InstantiateClass(NameLoc, Record, Def, - getTemplateInstantiationArgs(Record), - TSK)) - return true; - } else // Instantiate all of the members of the class. - InstantiateClassMembers(NameLoc, RecordDef, - getTemplateInstantiationArgs(Record), TSK); + } else { + if (InstantiateClass(NameLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) + return true; + + RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + if (!RecordDef) + return true; + } + } + + // Instantiate all of the members of the class. + InstantiateClassMembers(NameLoc, RecordDef, + getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it @@ -3968,8 +4021,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); assert(MSInfo && "Missing static data member specialization info?"); bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, - Prev, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), SuppressNew)) @@ -3990,9 +4042,9 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), @@ -4068,7 +4120,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, PrevDecl, PrevDecl->getTemplateSpecializationKind(), PrevDecl->getPointOfInstantiation(), @@ -4095,7 +4147,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // // C++98 has the same restriction, just worded differently. FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); - if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) Diag(D.getIdentifierLoc(), @@ -4277,6 +4329,13 @@ namespace { /// \brief Returns the name of the entity whose type is being rebuilt. DeclarationName getBaseEntity() { return Entity; } + /// \brief Sets the "base" location and entity when that + /// information is known based on another transformation. + void setBase(SourceLocation Loc, DeclarationName Entity) { + this->Loc = Loc; + this->Entity = Entity; + } + /// \brief Transforms an expression by returning the expression itself /// (an identity function). /// @@ -4290,25 +4349,13 @@ namespace { /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL); - QualType TransformTypenameType(TypenameType *T); }; } QualType CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL) { - QualType Result = TransformTypenameType(TL.getTypePtr()); - if (Result.isNull()) - return QualType(); - - TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - -QualType -CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { + TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), @@ -4322,12 +4369,14 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { CXXScopeSpec SS; SS.setRange(SourceRange(getBaseLocation())); SS.setScopeRep(NNS); + + QualType Result; if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0) - return QualType(T, 0); + Result = QualType(T, 0); // Rebuild the typename type, which will probably turn into a // QualifiedNameType. - if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = TransformType(QualType(TemplateId, 0)); if (NewTemplateId.isNull()) @@ -4335,12 +4384,16 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { if (NNS == T->getQualifier() && NewTemplateId == QualType(TemplateId, 0)) - return QualType(T, 0); - - return getDerived().RebuildTypenameType(NNS, NewTemplateId); - } + Result = QualType(T, 0); + else + Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + } else + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), + SourceRange(TL.getNameLoc())); - return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } /// \brief Rebuilds a type within the context of the current instantiation. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2a44f83..7b5ad7f 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -90,7 +90,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, Value.extOrTrunc(AllowedBits); Value.setIsSigned(T->isSignedIntegerType()); - Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), Value, T); + Deduced[NTTP->getIndex()] = TemplateArgument(Value, T); return Sema::TDK_Success; } @@ -102,7 +102,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, if (PrevValuePtr->isNegative()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(SourceLocation(), Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, NTTP->getType()); return Sema::TDK_Inconsistent; } @@ -115,7 +115,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, if (Value != PrevValue) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(SourceLocation(), Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, NTTP->getType()); return Sema::TDK_Inconsistent; } @@ -433,7 +433,7 @@ DeduceTemplateArguments(ASTContext &Context, if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) { Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; - Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_InconsistentQuals; } @@ -445,7 +445,7 @@ DeduceTemplateArguments(ASTContext &Context, DeducedType = Context.getCanonicalType(DeducedType); if (Deduced[Index].isNull()) - Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType); + Deduced[Index] = TemplateArgument(DeducedType); else { // C++ [temp.deduct.type]p2: // [...] If type deduction cannot be done for any P/A pair, or if for @@ -457,7 +457,7 @@ DeduceTemplateArguments(ASTContext &Context, Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; - Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_Inconsistent; } } @@ -465,8 +465,8 @@ DeduceTemplateArguments(ASTContext &Context, } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn); - Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn); + Info.FirstArg = TemplateArgument(ParamIn); + Info.SecondArg = TemplateArgument(ArgIn); // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { @@ -695,7 +695,7 @@ DeduceTemplateArguments(ASTContext &Context, CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(), BaseEnd = Next->bases_end(); - Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { assert(Base->getType()->isRecordType() && "Base class that isn't a record?"); ToVisit.push_back(Base->getType()->getAs<RecordType>()); @@ -982,18 +982,41 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // and are equivalent to the template arguments originally provided // to the class template. ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); - const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs(); - for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) { + const TemplateArgumentLoc *PartialTemplateArgs + = Partial->getTemplateArgsAsWritten(); + unsigned N = Partial->getNumTemplateArgsAsWritten(); + llvm::SmallVector<TemplateArgumentLoc, 16> InstArgs(N); + for (unsigned I = 0; I != N; ++I) { Decl *Param = const_cast<NamedDecl *>( ClassTemplate->getTemplateParameters()->getParam(I)); - TemplateArgument InstArg - = Subst(PartialTemplateArgs[I], - MultiLevelTemplateArgumentList(*DeducedArgumentList)); - if (InstArg.isNull()) { + if (Subst(PartialTemplateArgs[I], InstArgs[I], + MultiLevelTemplateArgumentList(*DeducedArgumentList))) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = PartialTemplateArgs[I].getArgument(); return TDK_SubstitutionFailure; } + } + + TemplateArgumentListBuilder ConvertedInstArgs( + ClassTemplate->getTemplateParameters(), N); + + if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), + /*LAngle*/ SourceLocation(), + InstArgs.data(), N, + /*RAngle*/ SourceLocation(), + false, ConvertedInstArgs)) { + // FIXME: fail with more useful information? + return TDK_SubstitutionFailure; + } + + for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { + // We don't really care if we overwrite the internal structures of + // the arg list builder, because we're going to throw it all away. + TemplateArgument &InstArg + = const_cast<TemplateArgument&>(ConvertedInstArgs.getFlatArguments()[I]); + + Decl *Param = const_cast<NamedDecl *>( + ClassTemplate->getTemplateParameters()->getParam(I)); if (InstArg.getKind() == TemplateArgument::Expression) { // When the argument is an expression, check the expression result @@ -1004,7 +1027,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } } else if (TemplateTemplateParmDecl *TTP @@ -1013,7 +1036,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr); if (!DRE || CheckTemplateArgument(TTP, DRE)) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } } @@ -1072,7 +1095,7 @@ static bool isSimpleTemplateIdType(QualType T) { Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, llvm::SmallVectorImpl<TemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, @@ -1290,7 +1313,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, @@ -1460,7 +1483,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, @@ -1643,15 +1666,15 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, // performed on the types used for partial ordering: // - If P is a reference type, P is replaced by the type referred to. CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>(); - if (ParamRef) + if (!ParamRef.isNull()) Param = ParamRef->getPointeeType(); // - If A is a reference type, A is replaced by the type referred to. CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>(); - if (ArgRef) + if (!ArgRef.isNull()) Arg = ArgRef->getPointeeType(); - if (QualifierComparisons && ParamRef && ArgRef) { + if (QualifierComparisons && !ParamRef.isNull() && !ArgRef.isNull()) { // C++0x [temp.deduct.partial]p6: // If both P and A were reference types (before being replaced with the // type referred to above), determine which of the two types (if any) is @@ -1690,6 +1713,7 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, + unsigned Level, llvm::SmallVectorImpl<bool> &Deduced); /// \brief Determine whether the function template \p FT1 is at least as @@ -1782,18 +1806,22 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Call: { unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); for (unsigned I = 0; I != NumParams; ++I) - ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + TemplateParams->getDepth(), UsedParameters); break; } case TPOC_Conversion: - ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + TemplateParams->getDepth(), UsedParameters); break; case TPOC_Other: - ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters); + ::MarkUsedTemplateParameters(S, FD2->getType(), false, + TemplateParams->getDepth(), + UsedParameters); break; } @@ -2065,6 +2093,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used); /// \brief Mark the template parameters that are used by the given @@ -2073,6 +2102,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const Expr *E, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. @@ -2085,7 +2115,8 @@ MarkUsedTemplateParameters(Sema &SemaRef, if (!NTTP) return; - Used[NTTP->getIndex()] = true; + if (NTTP->getDepth() == Depth) + Used[NTTP->getIndex()] = true; } /// \brief Mark the template parameters that are used by the given @@ -2094,13 +2125,15 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, NestedNameSpecifier *NNS, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (!NNS) return; - MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth, + Used); MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); } /// \brief Mark the template parameters that are used by the given @@ -2109,16 +2142,20 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, TemplateName Name, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Template)) - Used[TTP->getIndex()] = true; + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } return; } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) - MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, + Depth, Used); } /// \brief Mark the template parameters that are used by the given @@ -2126,6 +2163,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (T.isNull()) return; @@ -2140,6 +2178,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<PointerType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; @@ -2147,6 +2186,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<BlockPointerType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; @@ -2155,69 +2195,74 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<ReferenceType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; case Type::MemberPointer: { const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr()); MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced, - Used); + Depth, Used); MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; } case Type::DependentSizedArray: MarkUsedTemplateParameters(SemaRef, cast<DependentSizedArrayType>(T)->getSizeExpr(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); // Fall through to check the element type case Type::ConstantArray: case Type::IncompleteArray: MarkUsedTemplateParameters(SemaRef, cast<ArrayType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::Vector: case Type::ExtVector: MarkUsedTemplateParameters(SemaRef, cast<VectorType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *VecType = cast<DependentSizedExtVectorType>(T); MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced, - Used); + Depth, Used); MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, - Used); + Depth, Used); break; } case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced, - Used); + Depth, Used); for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced, - Used); + Depth, Used); break; } - case Type::TemplateTypeParm: - Used[cast<TemplateTypeParmType>(T)->getIndex()] = true; + case Type::TemplateTypeParm: { + const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T); + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; break; + } case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec = cast<TemplateSpecializationType>(T); MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, - Used); + Depth, Used); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, + Used); break; } @@ -2225,14 +2270,14 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, cast<ComplexType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::Typename: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, cast<TypenameType>(T)->getQualifier(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; // None of these types have any template parameters in them. @@ -2259,6 +2304,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { switch (TemplateArg.getKind()) { case TemplateArgument::Null: @@ -2267,25 +2313,27 @@ MarkUsedTemplateParameters(Sema &SemaRef, case TemplateArgument::Type: MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced, - Used); + Depth, Used); break; case TemplateArgument::Declaration: if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) - Used[TTP->getIndex()] = true; + = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } break; case TemplateArgument::Expression: MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, - Used); + Depth, Used); break; case TemplateArgument::Pack: for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(), PEnd = TemplateArg.pack_end(); P != PEnd; ++P) - MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used); break; } } @@ -2301,10 +2349,11 @@ MarkUsedTemplateParameters(Sema &SemaRef, /// deduced. void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, - bool OnlyDeduced, + bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used); + ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, + Depth, Used); } /// \brief Marks all of the template parameters that will be deduced by a @@ -2319,5 +2368,5 @@ void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), - true, Deduced); + true, TemplateParams->getDepth(), Deduced); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 53d1580..dfe37d8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -392,6 +392,13 @@ namespace { /// \brief Returns the name of the entity being instantiated, if any. DeclarationName getBaseEntity() { return Entity; } + /// \brief Sets the "base" location and entity when that + /// information is known based on another transformation. + void setBase(SourceLocation Loc, DeclarationName Entity) { + this->Loc = Loc; + this->Entity = Entity; + } + /// \brief Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(Decl *D); @@ -415,8 +422,10 @@ namespace { /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); - Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); - Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand); + Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. @@ -528,7 +537,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, } Sema::OwningExprResult -TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { +TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand) { if (!E->isTypeDependent()) return SemaRef.Owned(E->Retain()); @@ -551,62 +561,64 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { } Sema::OwningExprResult -TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand) { // FIXME: Clean this up a bit NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { - if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) { - assert(false && "Cannot reduce non-type template parameter depth yet"); - return getSema().ExprError(); - } - - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), - NTTP->getPosition())) - return SemaRef.Owned(E->Retain()); - - const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), - NTTP->getPosition()); - - // The template argument itself might be an expression, in which - // case we just return that expression. - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()->Retain()); - - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - - VD = cast_or_null<ValueDecl>( + if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { + + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), + NTTP->getPosition())) + return SemaRef.Owned(E->Retain()); + + const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), + NTTP->getPosition()); + + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()->Retain()); + + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + + VD = cast_or_null<ValueDecl>( getSema().FindInstantiatedDecl(VD, TemplateArgs)); - if (!VD) - return SemaRef.ExprError(); + if (!VD) + return SemaRef.ExprError(); - return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), - /*FIXME:*/false, /*FIXME:*/false); - } + return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), + /*FIXME:*/false, /*FIXME:*/false); + } - assert(Arg.getKind() == TemplateArgument::Integral); - QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) - return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), - T, - E->getSourceRange().getBegin())); - if (T->isBooleanType()) - return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( - Arg.getAsIntegral()->getBoolValue(), - T, - E->getSourceRange().getBegin())); - - assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); - return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( - *Arg.getAsIntegral(), + assert(Arg.getKind() == TemplateArgument::Integral); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), T, E->getSourceRange().getBegin())); + if (T->isBooleanType()) + return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + E->getSourceRange().getBegin())); + + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + *Arg.getAsIntegral(), + T, + E->getSourceRange().getBegin())); + } + + // We have a non-type template parameter that isn't fully substituted; + // FindInstantiatedDecl will find it in the local instantiation scope. } NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); @@ -618,11 +630,22 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this? InstD = InstD->getUnderlyingDecl(); - // FIXME: nested-name-specifier for QualifiedDeclRefExpr + CXXScopeSpec SS; + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + + SS.setScopeRep(Qualifier); + SS.setRange(E->getQualifierRange()); + } + return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD, /*FIXME:*/false, - /*FIXME:*/0, - /*FIXME:*/false); + &SS, + isAddressOfOperand); } QualType @@ -838,6 +861,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, = Instantiation->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) { + Spec->setTemplateSpecializationKind(TSK); + Spec->setPointOfInstantiation(PointOfInstantiation); } InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); @@ -892,18 +919,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); - // If this is an explicit instantiation, instantiate our members, too. - if (!Invalid && TSK != TSK_ImplicitInstantiation) { - Inst.Clear(); - InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs, - TSK); - } - return Invalid; } bool Sema::InstantiateClassTemplateSpecialization( + SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain) { @@ -921,10 +942,6 @@ Sema::InstantiateClassTemplateSpecialization( // declaration (C++0x [temp.explicit]p10); go ahead and perform the // explicit instantiation. ClassTemplateSpec->setSpecializationKind(TSK); - InstantiateClassTemplateSpecializationMembers( - /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(), - ClassTemplateSpec, - TSK); return false; } @@ -969,62 +986,72 @@ Sema::InstantiateClassTemplateSpecialization( } } - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - Pattern = Matched[0].first; - ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second); - } else if (Matched.size() > 1) { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the class template is - // ambiguous and the program is ill-formed. + if (Matched.size() >= 1) { llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); - for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->first, Best->first) - == P->first) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - bool Ambiguous = false; - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && - getMoreSpecializedPartialSpecialization(P->first, Best->first) - != Best->first) { - Ambiguous = true; - break; + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the class template is + // ambiguous and the program is ill-formed. + for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (getMoreSpecializedPartialSpecialization(P->first, Best->first) + == P->first) + Best = P; } - } - - if (Ambiguous) { - // Partial ordering did not produce a clear winner. Complain. - ClassTemplateSpec->setInvalidDecl(); - Diag(ClassTemplateSpec->getPointOfInstantiation(), - diag::err_partial_spec_ordering_ambiguous) - << ClassTemplateSpec; - // Print the matching partial specializations. + // Determine if the best partial specialization is more specialized than + // the others. + bool Ambiguous = false; for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->first->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), - *P->second); - - return true; + P != PEnd; ++P) { + if (P != Best && + getMoreSpecializedPartialSpecialization(P->first, Best->first) + != Best->first) { + Ambiguous = true; + break; + } + } + + if (Ambiguous) { + // Partial ordering did not produce a clear winner. Complain. + ClassTemplateSpec->setInvalidDecl(); + Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) + << ClassTemplateSpec; + + // Print the matching partial specializations. + for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + Diag(P->first->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), + *P->second); + + return true; + } } // Instantiate using the best class template partial specialization. - Pattern = Best->first; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first; + while (OrigPartialSpec->getInstantiatedFromMember()) { + // If we've found an explicit specialization of this class template, + // stop here and use that as the pattern. + if (OrigPartialSpec->isMemberSpecialization()) + break; + + OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember(); + } + + Pattern = OrigPartialSpec; ClassTemplateSpec->setInstantiationOf(Best->first, Best->second); } else { // -- If no matches are found, the instantiation is generated @@ -1042,12 +1069,9 @@ Sema::InstantiateClassTemplateSpecialization( Pattern = OrigTemplate->getTemplatedDecl(); } - // Note that this is an instantiation. - ClassTemplateSpec->setSpecializationKind(TSK); - - bool Result = InstantiateClass(ClassTemplateSpec->getPointOfInstantiation(), - ClassTemplateSpec, Pattern, - getTemplateInstantiationArgs(ClassTemplateSpec), + bool Result = InstantiateClass(PointOfInstantiation, ClassTemplateSpec, + Pattern, + getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); @@ -1071,48 +1095,112 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { + bool SuppressNew = false; if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) { - if (Function->getInstantiatedFromMemberFunction()) { - // If this member was explicitly specialized, do nothing. - if (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) + if (FunctionDecl *Pattern + = Function->getInstantiatedFromMemberFunction()) { + MemberSpecializationInfo *MSInfo + = Function->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Function, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) + continue; + + if (Function->getBody()) continue; + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Pattern->getBody()) + continue; - Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + + InstantiateFunctionDefinition(PointOfInstantiation, Function); + } else { + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } } - - if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { if (Var->isStaticDataMember()) { - // If this member was explicitly specialized, do nothing. - if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Var, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); - - if (TSK == TSK_ExplicitInstantiationDefinition) + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Var->getInstantiatedFromStaticDataMember() + ->getOutOfLineDefinition()) + continue; + + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); - } + } else { + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { if (Record->isInjectedClassName()) continue; - assert(Record->getInstantiatedFromMemberClass() && - "Missing instantiated-from-template information"); - - // If this member was explicitly specialized, do nothing. - if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Record, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - if (!Record->getDefinition(Context)) - InstantiateClass(PointOfInstantiation, Record, - Record->getInstantiatedFromMemberClass(), + CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + assert(Pattern && "Missing instantiated-from-template information"); + + if (!Record->getDefinition(Context)) { + if (!Pattern->getDefinition(Context)) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (TSK == TSK_ExplicitInstantiationDeclaration) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + + continue; + } + + InstantiateClass(PointOfInstantiation, Record, Pattern, TemplateArgs, TSK); + } - InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, - TSK); + Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + if (Pattern) + InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, + TSK); } } } @@ -1178,9 +1266,10 @@ Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc, return Instantiator.TransformTemplateName(Name); } -TemplateArgument Sema::Subst(TemplateArgument Arg, - const MultiLevelTemplateArgumentList &TemplateArgs) { +bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, + const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); - return Instantiator.TransformTemplateArgument(Arg); + + return Instantiator.TransformTemplateArgument(Input, Output); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index be4adbc..7288ae2 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -56,12 +56,12 @@ namespace { Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); - Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); // Base case. FIXME: Remove once we can instantiate everything. @@ -82,6 +82,10 @@ namespace { TemplateParameterList * SubstTemplateParams(TemplateParameterList *List); + + bool InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); }; } @@ -99,20 +103,20 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; - QualType T = D->getUnderlyingType(); - if (T->isDependentType()) { - T = SemaRef.SubstType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); - if (T.isNull()) { + DeclaratorInfo *DI = D->getTypeDeclaratorInfo(); + if (DI->getType()->isDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { Invalid = true; - T = SemaRef.Context.IntTy; + DI = SemaRef.Context.getTrivialDeclaratorInfo(SemaRef.Context.IntTy); } } // Create the new typedef TypedefDecl *Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T); + D->getIdentifier(), DI); if (Invalid) Typedef->setInvalidDecl(); @@ -161,7 +165,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // which they were instantiated. if (Var->isStaticDataMember()) SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, - TSK_ImplicitInstantiation); + TSK_ImplicitInstantiation); if (D->getInit()) { OwningExprResult Init @@ -389,7 +393,25 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } +namespace { + class SortDeclByLocation { + SourceManager &SourceMgr; + + public: + explicit SortDeclByLocation(SourceManager &SourceMgr) + : SourceMgr(SourceMgr) { } + + bool operator()(const Decl *X, const Decl *Y) const { + return SourceMgr.isBeforeInTranslationUnit(X->getLocation(), + Y->getLocation()); + } + }; +} + Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // Create a local instantiation scope for this class template, which + // will contain the instantiations of the template parameters. + Sema::LocalInstantiationScope Scope(SemaRef); TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -406,32 +428,83 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), InstParams, RecordInst, 0); RecordInst->setDescribedClassTemplate(Inst); - Inst->setAccess(D->getAccess()); + if (D->getFriendObjectKind()) + Inst->setObjectOfFriendDecl(true); + else + Inst->setAccess(D->getAccess()); Inst->setInstantiatedFromMemberTemplate(D); // Trigger creation of the type for the instantiation. SemaRef.Context.getTypeDeclType(RecordInst); + // Finish handling of friends. + if (Inst->getFriendObjectKind()) { + return Inst; + } + Owner->addDecl(Inst); + + // First, we sort the partial specializations by location, so + // that we instantiate them in the order they were declared. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = D->getPartialSpecializations().begin(), + PEnd = D->getPartialSpecializations().end(); + P != PEnd; ++P) + PartialSpecs.push_back(&*P); + std::sort(PartialSpecs.begin(), PartialSpecs.end(), + SortDeclByLocation(SemaRef.SourceMgr)); + + // Instantiate all of the partial specializations of this member class + // template. + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) + InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); + return Inst; } Decl * TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - assert(false &&"Partial specializations of member templates are unsupported"); + ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate(); + + // Lookup the already-instantiated declaration in the instantiation + // of the class template and return that. + DeclContext::lookup_result Found + = Owner->lookup(ClassTemplate->getDeclName()); + if (Found.first == Found.second) + return 0; + + ClassTemplateDecl *InstClassTemplate + = dyn_cast<ClassTemplateDecl>(*Found.first); + if (!InstClassTemplate) + return 0; + + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = InstClassTemplate->getPartialSpecializations().begin(), + PEnd = InstClassTemplate->getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return &*P; + } + return 0; } Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - // FIXME: Dig out the out-of-line definition of this function template? - + // Create a local instantiation scope for this function template, which + // will contain the instantiations of the template parameters and then get + // merged with the local instantiation scope for the function template + // itself. + Sema::LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - + FunctionDecl *Instantiated = 0; if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl())) Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, @@ -516,7 +589,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -530,7 +603,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getDeclName(), T, D->getDeclaratorInfo(), D->getStorageClass(), - D->isInline(), D->hasWrittenPrototype()); + D->isInlineSpecified(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); // Attach the parameters @@ -645,7 +718,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -666,14 +739,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Name, T, Constructor->getDeclaratorInfo(), Constructor->isExplicit(), - Constructor->isInline(), false); + Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXDestructorDecl::Create(SemaRef.Context, Record, Destructor->getLocation(), Name, - T, Destructor->isInline(), false); + T, Destructor->isInlineSpecified(), false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { CanQualType ConvTy = SemaRef.Context.getCanonicalType( @@ -683,12 +756,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, T, Conversion->getDeclaratorInfo(), - Conversion->isInline(), + Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, D->getDeclaratorInfo(), - D->isStatic(), D->isInline()); + D->isStatic(), D->isInlineSpecified()); } if (TemplateParams) { @@ -776,24 +849,27 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - QualType OrigT = SemaRef.SubstType(D->getOriginalType(), TemplateArgs, - D->getLocation(), D->getDeclName()); - if (OrigT.isNull()) + QualType T; + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI) { + DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), + D->getDeclName()); + if (DI) T = DI->getType(); + } else { + T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), + D->getDeclName()); + DI = 0; + } + + if (T.isNull()) return 0; - QualType T = SemaRef.adjustParameterType(OrigT); + T = SemaRef.adjustParameterType(T); // Allocate the parameter - ParmVarDecl *Param = 0; - if (T == OrigT) - Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T, D->getDeclaratorInfo(), - D->getStorageClass(), 0); - else - Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, - D->getLocation(), D->getIdentifier(), - T, D->getDeclaratorInfo(), OrigT, - D->getStorageClass(), 0); + ParmVarDecl *Param + = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), T, DI, D->getStorageClass(), 0); // Mark the default argument as being uninstantiated. if (D->hasUninstantiatedDefaultArg()) @@ -808,15 +884,6 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { return Param; } -Decl * -TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - // Since parameter types can decay either before or after - // instantiation, we simply treat OriginalParmVarDecls as - // ParmVarDecls the same way, and create one or the other depending - // on what happens after template instantiation. - return VisitParmVarDecl(D); -} - Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *D) { // TODO: don't always clone when decls are refcounted. @@ -826,26 +893,71 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - TTPT->getDepth(), TTPT->getIndex(), + TTPT->getDepth() - 1, TTPT->getIndex(), TTPT->getName(), D->wasDeclaredWithTypename(), D->isParameterPack()); + // FIXME: Do we actually want to perform substitution here? I don't think + // we do. if (D->hasDefaultArgument()) { - QualType DefaultPattern = D->getDefaultArgument(); - QualType DefaultInst + DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo(); + DeclaratorInfo *DefaultInst = SemaRef.SubstType(DefaultPattern, TemplateArgs, D->getDefaultArgumentLoc(), D->getDeclName()); Inst->setDefaultArgument(DefaultInst, - D->getDefaultArgumentLoc(), D->defaultArgumentWasInherited() /* preserve? */); } + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return Inst; } +Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( + NonTypeTemplateParmDecl *D) { + // Substitute into the type of the non-type template parameter. + QualType T; + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI) { + DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), + D->getDeclName()); + if (DI) T = DI->getType(); + } else { + T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), + D->getDeclName()); + DI = 0; + } + if (T.isNull()) + return 0; + + // Check that this type is acceptable for a non-type template parameter. + bool Invalid = false; + T = SemaRef.CheckNonTypeTemplateParameterType(T, D->getLocation()); + if (T.isNull()) { + T = SemaRef.Context.IntTy; + Invalid = true; + } + + NonTypeTemplateParmDecl *Param + = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDepth() - 1, D->getPosition(), + D->getIdentifier(), T, DI); + if (Invalid) + Param->setInvalidDecl(); + + Param->setDefaultArgument(D->getDefaultArgument()); + + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); + return Param; +} + Decl * TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { NestedNameSpecifier *NNS = @@ -913,6 +1025,136 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { return InstL; } +/// \brief Instantiate the declaration of a class template partial +/// specialization. +/// +/// \param ClassTemplate the (instantiated) class template that is partially +// specialized by the instantiation of \p PartialSpec. +/// +/// \param PartialSpec the (uninstantiated) class template partial +/// specialization that we are instantiating. +/// +/// \returns true if there was an error, false otherwise. +bool +TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec) { + // Create a local instantiation scope for this class template partial + // specialization, which will contain the instantiations of the template + // parameters. + Sema::LocalInstantiationScope Scope(SemaRef); + + // Substitute into the template parameters of the class template partial + // specialization. + TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return true; + + // Substitute into the template arguments of the class template partial + // specialization. + const TemplateArgumentLoc *PartialSpecTemplateArgs + = PartialSpec->getTemplateArgsAsWritten(); + unsigned N = PartialSpec->getNumTemplateArgsAsWritten(); + + llvm::SmallVector<TemplateArgumentLoc, 4> InstTemplateArgs(N); + for (unsigned I = 0; I != N; ++I) { + if (SemaRef.Subst(PartialSpecTemplateArgs[I], InstTemplateArgs[I], + TemplateArgs)) + return true; + } + + + // Check that the template argument list is well-formed for this + // class template. + TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), + InstTemplateArgs.size()); + if (SemaRef.CheckTemplateArgumentList(ClassTemplate, + PartialSpec->getLocation(), + /*FIXME:*/PartialSpec->getLocation(), + InstTemplateArgs.data(), + InstTemplateArgs.size(), + /*FIXME:*/PartialSpec->getLocation(), + false, + Converted)) + return true; + + // Figure out where to insert this class template partial specialization + // in the member template's set of class template partial specializations. + llvm::FoldingSetNodeID ID; + ClassTemplatePartialSpecializationDecl::Profile(ID, + Converted.getFlatArguments(), + Converted.flatSize(), + SemaRef.Context); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl + = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, + InsertPos); + + // Build the canonical type that describes the converted template + // arguments of the class template partial specialization. + QualType CanonType + = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), + Converted.getFlatArguments(), + Converted.flatSize()); + + // Build the fully-sugared type for this class template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + QualType WrittenTy + = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), + InstTemplateArgs.data(), + InstTemplateArgs.size(), + CanonType); + + if (PrevDecl) { + // We've already seen a partial specialization with the same template + // parameters and template arguments. This can happen, for example, when + // substituting the outer template arguments ends up causing two + // class template partial specializations of a member class template + // to have identical forms, e.g., + // + // template<typename T, typename U> + // struct Outer { + // template<typename X, typename Y> struct Inner; + // template<typename Y> struct Inner<T, Y>; + // template<typename Y> struct Inner<U, Y>; + // }; + // + // Outer<int, int> outer; // error: the partial specializations of Inner + // // have the same signature. + SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) + << WrittenTy; + SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) + << SemaRef.Context.getTypeDeclType(PrevDecl); + return true; + } + + + // Create the class template partial specialization declaration. + ClassTemplatePartialSpecializationDecl *InstPartialSpec + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, + PartialSpec->getLocation(), + InstParams, + ClassTemplate, + Converted, + InstTemplateArgs.data(), + InstTemplateArgs.size(), + 0); + InstPartialSpec->setInstantiatedFromMember(PartialSpec); + InstPartialSpec->setTypeAsWritten(WrittenTy); + + // Add this partial specialization to the set of class template partial + // specializations. + ClassTemplate->getPartialSpecializations().InsertNode(InstPartialSpec, + InsertPos); + return false; +} + /// \brief Does substitution on the type of the given function, including /// all of the function parameters. /// @@ -1065,20 +1307,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; // Find the function body that we'll be substituting. - const FunctionDecl *PatternDecl = 0; - if (FunctionTemplateDecl *Primary = Function->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(); - } - - PatternDecl = Primary->getTemplatedDecl(); - } else - PatternDecl = Function->getInstantiatedFromMemberFunction(); + const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); Stmt *Pattern = 0; if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); @@ -1108,7 +1337,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // to which they refer. if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration && - PatternDecl->isOutOfLine() && !PatternDecl->isInline()) + !PatternDecl->isInlined()) return; InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); @@ -1199,24 +1428,17 @@ void Sema::InstantiateStaticDataMemberDefinition( // Find the out-of-line definition of this static data member. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - bool FoundOutOfLineDef = false; assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - for (VarDecl::redecl_iterator RD = Def->redecls_begin(), - RDEnd = Def->redecls_end(); - RD != RDEnd; ++RD) { - if (RD->getLexicalDeclContext()->isFileContext()) { - Def = *RD; - FoundOutOfLineDef = true; - } - } + assert(Def->isStaticDataMember() && "Not a static data member?"); + Def = Def->getOutOfLineDefinition(); - if (!FoundOutOfLineDef) { + if (!Def) { // We did not find an out-of-line definition of this static data member, // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. if (DefinitionRequired) { + Def = Var->getInstantiatedFromStaticDataMember(); Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 2 << Var->getDeclName() << Var->getDeclContext(); @@ -1379,6 +1601,22 @@ static bool isInstantiationOf(FunctionTemplateDecl *Pattern, return false; } +static bool +isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, + ClassTemplatePartialSpecializationDecl *Instance) { + Pattern + = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl()); + do { + Instance = cast<ClassTemplatePartialSpecializationDecl>( + Instance->getCanonicalDecl()); + if (Pattern == Instance) + return true; + Instance = Instance->getInstantiatedFromMember(); + } while (Instance); + + return false; +} + static bool isInstantiationOf(CXXRecordDecl *Pattern, CXXRecordDecl *Instance) { Pattern = Pattern->getCanonicalDecl(); @@ -1469,6 +1707,11 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other)) return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp); + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other)) + return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D), + PartialSpec); + if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) { if (!Field->getDeclName()) { // This is an unnamed field. @@ -1550,7 +1793,9 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, } DeclContext *ParentDC = D->getDeclContext(); - if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) { + if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || + isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || + ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 49f7119..0003b1b 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -31,36 +31,58 @@ using namespace clang; /// C++ [dcl.fct]p3). The adjusted parameter type is returned. QualType Sema::adjustParameterType(QualType T) { // C99 6.7.5.3p7: - if (T->isArrayType()) { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) return Context.getArrayDecayedType(T); - } else if (T->isFunctionType()) - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) return Context.getPointerType(T); return T; } + + +/// isOmittedBlockReturnType - Return true if this declarator is missing a +/// return type because this is a omitted return type on a block literal. +static bool isOmittedBlockReturnType(const Declarator &D) { + if (D.getContext() != Declarator::BlockLiteralContext || + D.getDeclSpec().hasTypeSpecifier()) + return false; + + if (D.getNumTypeObjects() == 0) + return true; // ^{ ... } + + if (D.getNumTypeObjects() == 1 && + D.getTypeObject(0).Kind == DeclaratorChunk::Function) + return true; // ^(int X, float Y) { ... } + + return false; +} + /// \brief Convert the specified declspec to the appropriate type /// object. -/// \param DS the declaration specifiers -/// \param DeclLoc The location of the declarator identifier or invalid if none. +/// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, - SourceLocation DeclLoc, - bool &isInvalid) { +static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. - QualType Result; + const DeclSpec &DS = TheDeclarator.getDeclSpec(); + SourceLocation DeclLoc = TheDeclarator.getIdentifierLoc(); + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + + ASTContext &Context = TheSema.Context; + QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; @@ -80,13 +102,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { - Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); - Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } @@ -109,6 +131,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, DS.getNumProtocolQualifiers()); break; } + + // If this is a missing declspec in a block literal return context, then it + // is inferred from the return statements inside the block. + if (isOmittedBlockReturnType(TheDeclarator)) { + Result = Context.DependentTy; + break; + } // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, @@ -117,13 +146,11 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. - if (getLangOptions().ImplicitInt) { + if (TheSema.getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - Diag(DeclLoc, diag::ext_missing_declspec) + TheSema.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); @@ -134,19 +161,17 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - - if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) { - Diag(DeclLoc, diag::err_missing_type_specifier) + if (TheSema.getLangOptions().CPlusPlus && + !TheSema.getLangOptions().Microsoft) { + TheSema.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); // When this occurs in C++ code, often something is very broken with the // value being declared, poison it as invalid so we don't get chains of // errors. - isInvalid = true; + TheDeclarator.setInvalidType(true); } else { - Diag(DeclLoc, diag::ext_missing_type_specifier) + TheSema.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); } } @@ -158,14 +183,28 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; case DeclSpec::TSW_short: Result = Context.ShortTy; break; case DeclSpec::TSW_long: Result = Context.LongTy; break; - case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; + case DeclSpec::TSW_longlong: + Result = Context.LongLongTy; + + // long long is a C99 feature. + if (!TheSema.getLangOptions().C99 && + !TheSema.getLangOptions().CPlusPlus0x) + TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + break; } } else { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; - case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; + case DeclSpec::TSW_longlong: + Result = Context.UnsignedLongLongTy; + + // long long is a C99 feature. + if (!TheSema.getLangOptions().C99 && + !TheSema.getLangOptions().CPlusPlus0x) + TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + break; } } break; @@ -181,44 +220,47 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 - Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + TheSema.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { - Decl *D = static_cast<Decl *>(DS.getTypeRep()); + TypeDecl *D = cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep())); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } + // If the type is deprecated or unavailable, diagnose it. + TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == 0 && - "Can't handle qualifiers on typedef names yet!"); + DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); + // TypeQuals handled by caller. - Result = Context.getTypeDeclType(cast<TypeDecl>(D)); + Result = Context.getTypeDeclType(D); // In C++, make an ElaboratedType. - if (getLangOptions().CPlusPlus) { + if (TheSema.getLangOptions().CPlusPlus) { TagDecl::TagKind Tag = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); Result = Context.getElaboratedType(Result, Tag); } if (D->isInvalidDecl()) - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); - Result = GetTypeFromParser(DS.getTypeRep()); + Result = TheSema.GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { if (const ObjCInterfaceType * @@ -240,31 +282,22 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result->isObjCClassType()) { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); // Class<protocol-list> Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); } else { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) + TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); - isInvalid = true; + TheDeclarator.setInvalidType(true); } } - // If this is a reference to an invalid typedef, propagate the invalidity. - if (TypedefType *TDT = dyn_cast<TypedefType>(Result)) - if (TDT->getDecl()->isInvalidDecl()) - isInvalid = true; - // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. - Result = GetTypeFromParser(DS.getTypeRep()); + Result = TheSema.GetTypeFromParser(DS.getTypeRep()); assert(!Result.isNull() && "Didn't get a type for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); @@ -280,10 +313,10 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Expr *E = static_cast<Expr *>(DS.getTypeRep()); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = BuildDecltypeType(E); + Result = TheSema.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); } break; } @@ -295,14 +328,14 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_error: Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { - if (getLangOptions().Freestanding) - Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + if (TheSema.getLangOptions().Freestanding) + TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } @@ -312,7 +345,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) - ProcessTypeAttributeList(Result, AL); + TheSema.ProcessTypeAttributeList(Result, AL); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -329,13 +362,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { - Diag(DS.getRestrictSpecLoc(), + TheSema.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { - Diag(DS.getRestrictSpecLoc(), + TheSema.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. @@ -357,7 +390,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, "Has CVR quals but not C, V, or R?"); Loc = DS.getRestrictSpecLoc(); } - Diag(Loc, diag::warn_typecheck_function_qualifiers) + TheSema.Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } @@ -407,7 +440,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... Diag(Loc, diag::err_illegal_decl_pointer_to_reference) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } @@ -535,14 +568,14 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } // C++ 8.3.2p4: There shall be no ... arrays of references ... if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_array_of_references) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } @@ -746,7 +779,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // with reference type, or "cv void." if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_mempointer_to_reference) - << (Entity? Entity.getAsString() : "type name"); + << (Entity? Entity.getAsString() : "type name") << T; return QualType(); } @@ -805,6 +838,11 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { QualType QT = QualType::getFromOpaquePtr(Ty); + if (QT.isNull()) { + if (DInfo) *DInfo = 0; + return QualType(); + } + DeclaratorInfo *DI = 0; if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { QT = LIT->getType(); @@ -816,58 +854,31 @@ QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { } /// GetTypeForDeclarator - Convert the type for the specified -/// declarator to Type instances. Skip the outermost Skip type -/// objects. +/// declarator to Type instances. /// /// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq /// owns the declaration of a type (e.g., the definition of a struct /// type), then *OwnedDecl will receive the owned declaration. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo, unsigned Skip, + DeclaratorInfo **DInfo, TagDecl **OwnedDecl) { - bool OmittedReturnType = false; - - if (D.getContext() == Declarator::BlockLiteralContext - && Skip == 0 - && !D.getDeclSpec().hasTypeSpecifier() - && (D.getNumTypeObjects() == 0 - || (D.getNumTypeObjects() == 1 - && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) - OmittedReturnType = true; - - // long long is a C99 feature. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && - D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) - Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); - // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - switch (D.getKind()) { - case Declarator::DK_Abstract: - case Declarator::DK_Normal: - case Declarator::DK_Operator: - case Declarator::DK_TemplateId: { - const DeclSpec &DS = D.getDeclSpec(); - if (OmittedReturnType) { - // We default to a dependent type initially. Can be modified by - // the first return statement. - T = Context.DependentTy; - } else { - bool isInvalid = false; - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); - if (isInvalid) - D.setInvalidType(true); - else if (OwnedDecl && DS.isTypeSpecOwned()) - *OwnedDecl = cast<TagDecl>((Decl *)DS.getTypeRep()); - } + switch (D.getName().getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_TemplateId: + T = ConvertDeclSpecToType(D, *this); + + if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) + *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); break; - } - case Declarator::DK_Constructor: - case Declarator::DK_Destructor: - case Declarator::DK_Conversion: + case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_DestructorName: + case UnqualifiedId::IK_ConversionFunctionId: // Constructors and destructors don't have return types. Use // "void" instead. Conversion operators will check their return // types separately. @@ -926,8 +937,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: @@ -1190,7 +1201,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (getLangOptions().CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); - assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); + assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type // for a nonstatic member function, the function type to which a pointer @@ -1224,7 +1235,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.isInvalidType()) *DInfo = 0; else - *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip); + *DInfo = GetDeclaratorInfoForDeclarator(D, T); } return T; @@ -1289,6 +1300,21 @@ namespace { Visit(TL.getBaseTypeLoc()); } } + void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + DeclaratorInfo *DInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &DInfo); + + // If we got no declarator info from previous Sema routines, + // just fill with the typespec loc. + if (!DInfo) { + TL.initialize(DS.getTypeSpecTypeLoc()); + return; + } + + TemplateSpecializationTypeLoc OldTL = + cast<TemplateSpecializationTypeLoc>(DInfo->getTypeLoc()); + TL.copy(OldTL); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1366,11 +1392,11 @@ namespace { /// /// \param T QualType referring to the type as written in source code. DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { +Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -1463,7 +1489,7 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { DeclaratorInfo *DInfo = 0; TagDecl *OwnedTag = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + QualType T = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); if (D.isInvalidType()) return true; @@ -1655,13 +1681,10 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (const RecordType *Record = T->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { - if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { - if (Loc.isValid()) - ClassTemplateSpec->setPointOfInstantiation(Loc); - return InstantiateClassTemplateSpecialization(ClassTemplateSpec, + if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) + return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, /*Complain=*/diag != 0); - } } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { @@ -1669,13 +1692,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, assert(MSInfo && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSInfo->getTemplateSpecializationKind() - != TSK_ExplicitSpecialization) { - MSInfo->setPointOfInstantiation(Loc); + != TSK_ExplicitSpecialization) return InstantiateClass(Loc, Rec, Pattern, getTemplateInstantiationArgs(Rec), TSK_ImplicitInstantiation, /*Complain=*/diag != 0); - } } } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7e0972f..5713da9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -290,23 +290,43 @@ public: /// declaration stored within the template argument and constructs a /// new template argument from the transformed result. Subclasses may /// override this function to provide alternate behavior. - TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); + /// + /// Returns true if there was an error. + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output); + + /// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument. + void InventTemplateArgumentLoc(const TemplateArgument &Arg, + TemplateArgumentLoc &ArgLoc); + + /// \brief Fakes up a DeclaratorInfo for a type. + DeclaratorInfo *InventDeclaratorInfo(QualType T) { + return SemaRef.Context.getTrivialDeclaratorInfo(T, + getDerived().getBaseLocation()); + } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); + QualType TransformTemplateSpecializationType(const TemplateSpecializationType *T, QualType ObjectType); + + QualType + TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + QualType ObjectType); OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ - OwningExprResult Transform##Node(Node *E); + OwningExprResult Transform##Node(Node *E, bool isAddressOfOperand); #define ABSTRACT_EXPR(Node, Parent) #include "clang/AST/StmtNodes.def" @@ -314,35 +334,37 @@ public: /// /// By default, performs semantic analysis when building the pointer type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildPointerType(QualType PointeeType); + QualType RebuildPointerType(QualType PointeeType, SourceLocation Sigil); /// \brief Build a new block pointer type given its pointee type. /// /// By default, performs semantic analysis when building the block pointer /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildBlockPointerType(QualType PointeeType); + QualType RebuildBlockPointerType(QualType PointeeType, SourceLocation Sigil); - /// \brief Build a new lvalue reference type given the type it references. + /// \brief Build a new reference type given the type it references. /// - /// By default, performs semantic analysis when building the lvalue reference - /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildLValueReferenceType(QualType ReferentType); - - /// \brief Build a new rvalue reference type given the type it references. + /// By default, performs semantic analysis when building the + /// reference type. Subclasses may override this routine to provide + /// different behavior. /// - /// By default, performs semantic analysis when building the rvalue reference - /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildRValueReferenceType(QualType ReferentType); + /// \param LValue whether the type was written with an lvalue sigil + /// or an rvalue sigil. + QualType RebuildReferenceType(QualType ReferentType, + bool LValue, + SourceLocation Sigil); /// \brief Build a new member pointer type given the pointee type and the /// class type it refers into. /// /// By default, performs semantic analysis when building the member pointer /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, + SourceLocation Sigil); /// \brief Build a new Objective C object pointer type. - QualType RebuildObjCObjectPointerType(QualType PointeeType); + QualType RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Sigil); /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type @@ -366,7 +388,8 @@ public: QualType RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, - unsigned IndexTypeQuals); + unsigned IndexTypeQuals, + SourceRange BracketsRange); /// \brief Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. @@ -375,7 +398,8 @@ public: /// Subclasses may override this routine to provide different behavior. QualType RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals); + unsigned IndexTypeQuals, + SourceRange BracketsRange); /// \brief Build a new variable-length array type given the element type, /// size modifier, size expression, and index type qualifiers. @@ -478,8 +502,11 @@ public: /// specialization type. Subclasses may override this routine to provide /// different behavior. QualType RebuildTemplateSpecializationType(TemplateName Template, - const TemplateArgument *Args, - unsigned NumArgs); + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + SourceLocation RAngleLoc); /// \brief Build a new qualified name type. /// @@ -509,9 +536,9 @@ public: /// (or qualified name type). Subclasses may override this routine to provide /// different behavior. QualType RebuildTypenameType(NestedNameSpecifier *NNS, - const IdentifierInfo *Id) { - return SemaRef.CheckTypenameType(NNS, *Id, - SourceRange(getDerived().getBaseLocation())); + const IdentifierInfo *Id, + SourceRange SR) { + return SemaRef.CheckTypenameType(NNS, *Id, SR); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -578,7 +605,17 @@ public: const IdentifierInfo &II, QualType ObjectType); - + /// \brief Build a new template name given a nested name specifier and the + /// overloaded operator name that is referred to as a template. + /// + /// By default, performs semantic analysis to determine whether the name can + /// be resolved to a specific template, then builds the appropriate kind of + /// template name. Subclasses may override this routine to provide different + /// behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + QualType ObjectType); + /// \brief Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. @@ -781,11 +818,17 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildDeclRefExpr(NamedDecl *ND, SourceLocation Loc) { + OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *ND, SourceLocation Loc, + bool isAddressOfOperand) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(QualifierRange); return getSema().BuildDeclarationNameExpr(Loc, ND, /*FIXME:*/false, - /*SS=*/0, - /*FIXME:*/false); + &SS, + isAddressOfOperand); } /// \brief Build a new expression in parentheses. @@ -841,9 +884,10 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildSizeOfAlignOf(QualType T, SourceLocation OpLoc, + OwningExprResult RebuildSizeOfAlignOf(DeclaratorInfo *DInfo, + SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(T, OpLoc, isSizeOf, R); + return getSema().CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeOf, R); } /// \brief Build a new sizeof or alignof expression with an expression @@ -1002,9 +1046,9 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { - return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, + return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, tok::period, AccessorLoc, - Accessor, + DeclarationName(&Accessor), /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); } @@ -1392,26 +1436,6 @@ public: T.getAsOpaquePtr(), RParenLoc); } - /// \brief Build a new qualified declaration reference expression. - /// - /// By default, performs semantic analysis to build the new expression. - /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildQualifiedDeclRefExpr(NestedNameSpecifier *NNS, - SourceRange QualifierRange, - NamedDecl *ND, - SourceLocation Location, - bool IsAddressOfOperand) { - CXXScopeSpec SS; - SS.setRange(QualifierRange); - SS.setScopeRep(NNS); - return getSema().ActOnDeclarationNameExpr(/*Scope=*/0, - Location, - ND->getDeclName(), - /*Trailing lparen=*/false, - &SS, - IsAddressOfOperand); - } - /// \brief Build a new (previously unresolved) declaration reference /// expression. /// @@ -1442,7 +1466,7 @@ public: TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - TemplateArgument *TemplateArgs, + TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange, @@ -1545,7 +1569,7 @@ public: SourceLocation TemplateNameLoc, NamedDecl *FirstQualifierInScope, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { OwningExprResult Base = move(BaseE); @@ -1556,16 +1580,21 @@ public: SS.setScopeRep(Qualifier); // FIXME: We're going to end up looking up the template based on its name, - // twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr. + // twice! Also, duplicates part of Sema::BuildMemberAccessExpr. DeclarationName Name; if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) Name = ActualTemplate->getDeclName(); else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) Name = Ovl->getDeclName(); - else - Name = Template.getAsDependentTemplateName()->getName(); - + else { + DependentTemplateName *DTN = Template.getAsDependentTemplateName(); + if (DTN->isIdentifier()) + Name = DTN->getIdentifier(); + else + Name = SemaRef.Context.DeclarationNames.getCXXOperatorName( + DTN->getOperator()); + } return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OperatorLoc, OpKind, TemplateNameLoc, Name, true, @@ -1683,7 +1712,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; #define EXPR(Node, Parent) \ - case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); + case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E), \ + isAddressOfOperand); #include "clang/AST/StmtNodes.def" } @@ -1746,6 +1776,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { + TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); if (T.isNull()) return 0; @@ -1860,7 +1891,12 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, ObjectType.isNull()) return Name; - return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); + if (DTN->isIdentifier()) + return getDerived().RebuildTemplateName(NNS, *DTN->getIdentifier(), + ObjectType); + + return getDerived().RebuildTemplateName(NNS, DTN->getOperator(), + ObjectType); } if (TemplateDecl *Template = Name.getAsTemplateDecl()) { @@ -1891,25 +1927,80 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, } template<typename Derived> -TemplateArgument -TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { +void TreeTransform<Derived>::InventTemplateArgumentLoc( + const TemplateArgument &Arg, + TemplateArgumentLoc &Output) { + SourceLocation Loc = getDerived().getBaseLocation(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm::llvm_unreachable("null template argument in TreeTransform"); + break; + + case TemplateArgument::Type: + Output = TemplateArgumentLoc(Arg, + SemaRef.Context.getTrivialDeclaratorInfo(Arg.getAsType(), Loc)); + + break; + + case TemplateArgument::Expression: + Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); + break; + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); + break; + } +} + +template<typename Derived> +bool TreeTransform<Derived>::TransformTemplateArgument( + const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output) { + const TemplateArgument &Arg = Input.getArgument(); switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: - return Arg; + Output = Input; + return false; case TemplateArgument::Type: { - QualType T = getDerived().TransformType(Arg.getAsType()); - if (T.isNull()) - return TemplateArgument(); - return TemplateArgument(Arg.getLocation(), T); + DeclaratorInfo *DI = Input.getSourceDeclaratorInfo(); + if (DI == NULL) + DI = InventDeclaratorInfo(Input.getArgument().getAsType()); + + DI = getDerived().TransformType(DI); + if (!DI) return true; + + Output = TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + return false; } case TemplateArgument::Declaration: { + // FIXME: we should never have to transform one of these. + DeclarationName Name; + if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) + Name = ND->getDeclName(); + TemporaryBase Rebase(*this, SourceLocation(), Name); Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); - if (!D) - return TemplateArgument(); - return TemplateArgument(Arg.getLocation(), D); + if (!D) return true; + + Expr *SourceExpr = Input.getSourceDeclExpression(); + if (SourceExpr) { + EnterExpressionEvaluationContext Unevaluated(getSema(), + Action::Unevaluated); + Sema::OwningExprResult E = getDerived().TransformExpr(SourceExpr); + if (E.isInvalid()) + SourceExpr = NULL; + else { + SourceExpr = E.takeAs<Expr>(); + SourceExpr->Retain(); + } + } + + Output = TemplateArgumentLoc(TemplateArgument(D), SourceExpr); + return false; } case TemplateArgument::Expression: { @@ -1917,10 +2008,17 @@ TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { EnterExpressionEvaluationContext Unevaluated(getSema(), Action::Unevaluated); - Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr()); - if (E.isInvalid()) - return TemplateArgument(); - return TemplateArgument(E.takeAs<Expr>()); + Expr *InputExpr = Input.getSourceExpression(); + if (!InputExpr) InputExpr = Input.getArgument().getAsExpr(); + + Sema::OwningExprResult E + = getDerived().TransformExpr(InputExpr); + if (E.isInvalid()) return true; + + Expr *ETaken = E.takeAs<Expr>(); + ETaken->Retain(); + Output = TemplateArgumentLoc(TemplateArgument(ETaken), ETaken); + return false; } case TemplateArgument::Pack: { @@ -1929,21 +2027,28 @@ TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); A != AEnd; ++A) { - TemplateArgument TA = getDerived().TransformTemplateArgument(*A); - if (TA.isNull()) - return TA; - TransformedArgs.push_back(TA); + // FIXME: preserve source information here when we start + // caring about parameter packs. + + TemplateArgumentLoc InputArg; + TemplateArgumentLoc OutputArg; + getDerived().InventTemplateArgumentLoc(*A, InputArg); + if (getDerived().TransformTemplateArgument(InputArg, OutputArg)) + return true; + + TransformedArgs.push_back(OutputArg.getArgument()); } TemplateArgument Result; Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(), true); - return Result; + Output = TemplateArgumentLoc(Result, Input.getLocInfo()); + return false; } } // Work around bogus GCC warning - return TemplateArgument(); + return true; } //===----------------------------------------------------------------------===// @@ -2048,7 +2153,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { QualType Result = TL.getType(); \ if (getDerived().AlwaysRebuild() || \ PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType); \ + Result = getDerived().Rebuild##TypeClass(PointeeType, \ + TL.getSigilLoc()); \ if (Result.isNull()) \ return QualType(); \ } \ @@ -2059,35 +2165,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { return Result; \ } while(0) -// Reference collapsing forces us to transform reference types -// differently from the other pointer-like types. -#define TransformReferenceType(TypeClass) do { \ - QualType PointeeType \ - = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ - if (PointeeType.isNull()) \ - return QualType(); \ - \ - QualType Result = TL.getType(); \ - if (getDerived().AlwaysRebuild() || \ - PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType); \ - if (Result.isNull()) \ - return QualType(); \ - } \ - \ - /* Workaround: rebuild doesn't always change the type */ \ - /* FIXME: avoid losing this location information. */ \ - if (Result == PointeeType) \ - return Result; \ - ReferenceTypeLoc NewTL; \ - if (isa<LValueReferenceType>(Result)) \ - NewTL = TLB.push<LValueReferenceTypeLoc>(Result); \ - else \ - NewTL = TLB.push<RValueReferenceTypeLoc>(Result); \ - NewTL.setSigilLoc(TL.getSigilLoc()); \ - return Result; \ -} while (0) - template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { @@ -2121,18 +2198,54 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, TransformPointerLikeType(BlockPointerType); } +/// Transforms a reference type. Note that somewhat paradoxically we +/// don't care whether the type itself is an l-value type or an r-value +/// type; we only care if the type was *written* as an l-value type +/// or an r-value type. +template<typename Derived> +QualType +TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, + ReferenceTypeLoc TL) { + const ReferenceType *T = TL.getTypePtr(); + + // Note that this works with the pointee-as-written. + QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != T->getPointeeTypeAsWritten()) { + Result = getDerived().RebuildReferenceType(PointeeType, + T->isSpelledAsLValue(), + TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + // r-value references can be rebuilt as l-value references. + ReferenceTypeLoc NewTL; + if (isa<LValueReferenceType>(Result)) + NewTL = TLB.push<LValueReferenceTypeLoc>(Result); + else + NewTL = TLB.push<RValueReferenceTypeLoc>(Result); + NewTL.setSigilLoc(TL.getSigilLoc()); + + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, LValueReferenceTypeLoc TL) { - TransformReferenceType(LValueReferenceType); + return TransformReferenceType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, RValueReferenceTypeLoc TL) { - TransformReferenceType(RValueReferenceType); + return TransformReferenceType(TLB, TL); } template<typename Derived> @@ -2155,7 +2268,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeType() || ClassType != QualType(T->getClass(), 0)) { - Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType); + Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType, + TL.getStarLoc()); if (Result.isNull()) return QualType(); } @@ -2181,7 +2295,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, Result = getDerived().RebuildConstantArrayType(ElementType, T->getSizeModifier(), T->getSize(), - T->getIndexTypeCVRQualifiers()); + T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2214,7 +2329,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType( ElementType != T->getElementType()) { Result = getDerived().RebuildIncompleteArrayType(ElementType, T->getSizeModifier(), - T->getIndexTypeCVRQualifiers()); + T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2254,7 +2370,7 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, T->getSizeModifier(), move(SizeResult), T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2295,7 +2411,7 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, T->getSizeModifier(), move(SizeResult), T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2331,7 +2447,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - (ElementType != T->getElementType() && Size.get() != T->getSizeExpr())) { + ElementType != T->getElementType() || + Size.get() != T->getSizeExpr()) { Result = getDerived().RebuildDependentSizedExtVectorType(ElementType, move(Size), T->getAttributeLoc()); @@ -2687,46 +2804,76 @@ inline QualType TreeTransform<Derived>::TransformTemplateSpecializationType( TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { - // TODO: figure out how make this work with an ObjectType. - QualType Result - = TransformTemplateSpecializationType(TL.getTypePtr(), QualType()); - if (Result.isNull()) - return QualType(); + return TransformTemplateSpecializationType(TLB, TL, QualType()); +} - TemplateSpecializationTypeLoc NewTL - = TLB.push<TemplateSpecializationTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); +template<typename Derived> +QualType TreeTransform<Derived>::TransformTemplateSpecializationType( + const TemplateSpecializationType *TST, + QualType ObjectType) { + // FIXME: this entire method is a temporary workaround; callers + // should be rewritten to provide real type locs. - return Result; + // Fake up a TemplateSpecializationTypeLoc. + TypeLocBuilder TLB; + TemplateSpecializationTypeLoc TL + = TLB.push<TemplateSpecializationTypeLoc>(QualType(TST, 0)); + + SourceLocation BaseLoc = getDerived().getBaseLocation(); + + TL.setTemplateNameLoc(BaseLoc); + TL.setLAngleLoc(BaseLoc); + TL.setRAngleLoc(BaseLoc); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + const TemplateArgument &TA = TST->getArg(i); + TemplateArgumentLoc TAL; + getDerived().InventTemplateArgumentLoc(TA, TAL); + TL.setArgLocInfo(i, TAL.getLocInfo()); + } + + TypeLocBuilder IgnoredTLB; + return TransformTemplateSpecializationType(IgnoredTLB, TL, ObjectType); } template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( - const TemplateSpecializationType *T, - QualType ObjectType) { + TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + QualType ObjectType) { + const TemplateSpecializationType *T = TL.getTypePtr(); + TemplateName Template = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); if (Template.isNull()) return QualType(); - llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs; - NewTemplateArgs.reserve(T->getNumArgs()); - for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); - Arg != ArgEnd; ++Arg) { - TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg); - if (NewArg.isNull()) + llvm::SmallVector<TemplateArgumentLoc, 4> NewTemplateArgs(T->getNumArgs()); + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) + if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), + NewTemplateArgs[i])) return QualType(); - NewTemplateArgs.push_back(NewArg); - } + // FIXME: maybe don't rebuild if all the template arguments are the same. - // FIXME: early abort if all of the template arguments and such are the - // same. + QualType Result = + getDerived().RebuildTemplateSpecializationType(Template, + TL.getTemplateNameLoc(), + TL.getLAngleLoc(), + NewTemplateArgs.data(), + NewTemplateArgs.size(), + TL.getRAngleLoc()); - // FIXME: We're missing the locations of the template name, '<', and '>'. - return getDerived().RebuildTemplateSpecializationType(Template, - NewTemplateArgs.data(), - NewTemplateArgs.size()); + if (!Result.isNull()) { + TemplateSpecializationTypeLoc NewTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + } + + return Result; } template<typename Derived> @@ -2763,9 +2910,12 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL) { TypenameType *T = TL.getTypePtr(); + + /* FIXME: preserve source information better than this */ + SourceRange SR(TL.getNameLoc()); + NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange(/*FIXME:*/getDerived().getBaseLocation())); + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR); if (!NNS) return QualType(); @@ -2784,7 +2934,7 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); } else { - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier()); + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR); } if (Result.isNull()) return QualType(); @@ -3268,57 +3418,88 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { //===----------------------------------------------------------------------===// template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { +TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { +TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand) { + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + } + NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); if (!ND) return SemaRef.ExprError(); - if (!getDerived().AlwaysRebuild() && ND == E->getDecl()) + if (!getDerived().AlwaysRebuild() && + Qualifier == E->getQualifier() && + ND == E->getDecl() && + !E->hasExplicitTemplateArgumentList()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildDeclRefExpr(ND, E->getLocation()); + // FIXME: We're losing the explicit template arguments in this transformation. + + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) + return SemaRef.ExprError(); + } + + // FIXME: Pass the qualifier/qualifier range along. + return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), + ND, E->getLocation(), + isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { +TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { +TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) { +TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) { +TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { +TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { +TreeTransform<Derived>::TransformParenExpr(ParenExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3332,8 +3513,10 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); +TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E, + bool isAddressOfOperand) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(), + E->getOpcode() == UnaryOperator::AddrOf); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3347,16 +3530,19 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, + bool isAddressOfOperand) { if (E->isArgumentType()) { - QualType T = getDerived().TransformType(E->getArgumentType()); - if (T.isNull()) + DeclaratorInfo *OldT = E->getArgumentTypeInfo(); + + DeclaratorInfo *NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); - if (!getDerived().AlwaysRebuild() && T == E->getArgumentType()) + if (!getDerived().AlwaysRebuild() && OldT == NewT) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildSizeOfAlignOf(T, E->getOperatorLoc(), + return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(), E->isSizeOf(), E->getSourceRange()); } @@ -3383,7 +3569,8 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { +TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E, + bool isAddressOfOperand) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3406,7 +3593,8 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { +TreeTransform<Derived>::TransformCallExpr(CallExpr *E, + bool isAddressOfOperand) { // Transform the callee. OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) @@ -3445,7 +3633,8 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { +TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3484,14 +3673,16 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCastExpr(CastExpr *E) { +TreeTransform<Derived>::TransformCastExpr(CastExpr *E, + bool isAddressOfOperand) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { +TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E, + bool isAddressOfOperand) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3512,13 +3703,15 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( - CompoundAssignOperator *E) { - return getDerived().TransformBinaryOperator(E); + CompoundAssignOperator *E, + bool isAddressOfOperand) { + return getDerived().TransformBinaryOperator(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { +TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E, + bool isAddressOfOperand) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3546,7 +3739,12 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { +TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + + // FIXME: Will we ever have type information here? It seems like we won't, + // so do we even need to transform the type? QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return SemaRef.ExprError(); @@ -3567,14 +3765,16 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { +TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E, + bool isAddressOfOperand) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { +TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E, + bool isAddressOfOperand) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3603,7 +3803,8 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { +TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, + bool isAddressOfOperand) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3632,7 +3833,8 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { +TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3651,7 +3853,8 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { +TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E, + bool isAddressOfOperand) { bool InitChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); @@ -3673,7 +3876,8 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { +TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E, + bool isAddressOfOperand) { Designation Desig; // transform the initializer value @@ -3742,7 +3946,12 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformImplicitValueInitExpr( - ImplicitValueInitExpr *E) { + ImplicitValueInitExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + + // FIXME: Will we ever have proper type location here? Will we actually + // need to transform the type? QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return SemaRef.ExprError(); @@ -3756,7 +3965,8 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { +TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E, + bool isAddressOfOperand) { // FIXME: Do we want the type as written? QualType T; @@ -3783,7 +3993,8 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { +TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E, + bool isAddressOfOperand) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { @@ -3807,13 +4018,16 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { /// the corresponding label statement by semantic analysis. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) { +TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E, + bool isAddressOfOperand) { return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), E->getLabel()); } template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { +Sema::OwningExprResult +TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E, + bool isAddressOfOperand) { OwningStmtResult SubStmt = getDerived().TransformCompoundStmt(E->getSubStmt(), true); if (SubStmt.isInvalid()) @@ -3830,7 +4044,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { +TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, + bool isAddressOfOperand) { QualType T1, T2; { // FIXME: Source location isn't quite accurate. @@ -3856,7 +4071,8 @@ TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { +TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E, + bool isAddressOfOperand) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3882,18 +4098,22 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) { +TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { +TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, + bool isAddressOfOperand) { OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return SemaRef.ExprError(); - OwningExprResult First = getDerived().TransformExpr(E->getArg(0)); + OwningExprResult First + = getDerived().TransformExpr(E->getArg(0), + E->getNumArgs() == 1 && E->getOperator() == OO_Amp); if (First.isInvalid()) return SemaRef.ExprError(); @@ -3919,13 +4139,15 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { - return getDerived().TransformCallExpr(E); +TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCallExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { +TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, + bool isAddressOfOperand) { QualType ExplicitTy; { // FIXME: Source location isn't quite accurate. @@ -3966,33 +4188,38 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXReinterpretCastExpr( - CXXReinterpretCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); + CXXReinterpretCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( - CXXFunctionalCastExpr *E) { + CXXFunctionalCastExpr *E, + bool isAddressOfOperand) { QualType ExplicitTy; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); @@ -4022,7 +4249,8 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { +TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E, + bool isAddressOfOperand) { if (E->isTypeOperand()) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); @@ -4062,20 +4290,23 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { +TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr( - CXXNullPtrLiteralExpr *E) { + CXXNullPtrLiteralExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { +TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4091,7 +4322,8 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { +TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4105,7 +4337,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { +TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, + bool isAddressOfOperand) { ParmVarDecl *Param = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam())); if (!Param) @@ -4120,7 +4353,8 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { +TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4139,7 +4373,8 @@ TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) { +TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E, + bool isAddressOfOperand) { VarDecl *Var = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl())); if (!Var) @@ -4156,7 +4391,8 @@ TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { +TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E, + bool isAddressOfOperand) { // Transform the type that we're allocating TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType AllocType = getDerived().TransformType(E->getAllocatedType()); @@ -4214,7 +4450,8 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { +TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E, + bool isAddressOfOperand) { OwningExprResult Operand = getDerived().TransformExpr(E->getArgument()); if (Operand.isInvalid()) return SemaRef.ExprError(); @@ -4232,7 +4469,8 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( - CXXPseudoDestructorExpr *E) { + CXXPseudoDestructorExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -4269,14 +4507,16 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr( - UnresolvedFunctionNameExpr *E) { + UnresolvedFunctionNameExpr *E, + bool isAddressOfOperand) { // There is no transformation we can apply to an unresolved function name. return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { +TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getQueriedType()); @@ -4300,34 +4540,9 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) { - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!NNS) - return SemaRef.ExprError(); - - NamedDecl *ND - = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); - if (!ND) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - NNS == E->getQualifier() && - ND == E->getDecl()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildQualifiedDeclRefExpr(NNS, - E->getQualifierRange(), - ND, - E->getLocation(), - /*FIXME:*/false); -} - -template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( - UnresolvedDeclRefExpr *E) { + UnresolvedDeclRefExpr *E, + bool isAddressOfOperand) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange()); @@ -4348,12 +4563,15 @@ TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( E->getQualifierRange(), Name, E->getLocation(), - /*FIXME:*/false); + isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { +TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getTemplateNameLoc(), DeclarationName()); + TemplateName Template = getDerived().TransformTemplateName(E->getTemplateName()); if (Template.isNull()) @@ -4367,14 +4585,11 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { return SemaRef.ExprError(); } - llvm::SmallVector<TemplateArgument, 4> TransArgs; + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgument TransArg - = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); - if (TransArg.isNull()) + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) return SemaRef.ExprError(); - - TransArgs.push_back(TransArg); } // FIXME: Would like to avoid rebuilding if nothing changed, but we can't @@ -4393,7 +4608,8 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { +TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4437,7 +4653,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { /// must be unique. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { +TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4455,7 +4672,8 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E) { + CXXExprWithTemporaries *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4468,7 +4686,8 @@ TreeTransform<Derived>::TransformCXXExprWithTemporaries( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( - CXXTemporaryObjectExpr *E) { + CXXTemporaryObjectExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) @@ -4518,7 +4737,8 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( - CXXUnresolvedConstructExpr *E) { + CXXUnresolvedConstructExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getTypeAsWritten()); if (T.isNull()) @@ -4557,7 +4777,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( - CXXUnresolvedMemberExpr *E) { + CXXUnresolvedMemberExpr *E, + bool isAddressOfOperand) { // Transform the base of the expression. OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) @@ -4617,9 +4838,14 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( // FIXME: This is an ugly hack, which forces the same template name to // be looked up multiple times. Yuck! - // FIXME: This also won't work for, e.g., x->template operator+<int> - TemplateName OrigTemplateName - = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo()); + TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName()); + TemplateName OrigTemplateName; + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) + OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II); + else + OrigTemplateName + = SemaRef.Context.getDependentTemplateName(0, + Name.getCXXOverloadedOperator()); TemplateName Template = getDerived().TransformTemplateName(OrigTemplateName, @@ -4627,14 +4853,11 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Template.isNull()) return SemaRef.ExprError(); - llvm::SmallVector<TemplateArgument, 4> TransArgs; + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgument TransArg - = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); - if (TransArg.isNull()) + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) return SemaRef.ExprError(); - - TransArgs.push_back(TransArg); } return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), @@ -4653,13 +4876,15 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { +TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { +TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E, + bool isAddressOfOperand) { // FIXME: poor source location TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); QualType EncodedType = getDerived().TransformType(E->getEncodedType()); @@ -4677,7 +4902,8 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { +TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4685,13 +4911,15 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { +TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { +TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E, + bool isAddressOfOperand) { ObjCProtocolDecl *Protocol = cast_or_null<ObjCProtocolDecl>( getDerived().TransformDecl(E->getProtocol())); @@ -4712,7 +4940,8 @@ TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { +TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4720,7 +4949,8 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { +TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4729,7 +4959,8 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E) { + ObjCImplicitSetterGetterRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4737,7 +4968,8 @@ TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { +TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4745,7 +4977,8 @@ TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { +TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4753,7 +4986,8 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { +TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E, + bool isAddressOfOperand) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { @@ -4776,7 +5010,8 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { +TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform block expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4784,7 +5019,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { +TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform block-related expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4795,48 +5031,42 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { //===----------------------------------------------------------------------===// template<typename Derived> -QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType, + SourceLocation Star) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Star, getDerived().getBaseEntity()); } template<typename Derived> -QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) { - return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType, + SourceLocation Star) { + return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), Star, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); +TreeTransform<Derived>::RebuildReferenceType(QualType ReferentType, + bool WrittenAsLValue, + SourceLocation Sigil) { + return SemaRef.BuildReferenceType(ReferentType, WrittenAsLValue, Qualifiers(), + Sigil, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, - QualType ClassType) { +TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, + QualType ClassType, + SourceLocation Sigil) { return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); + Sigil, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Sigil) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil, getDerived().getBaseEntity()); } @@ -4880,18 +5110,20 @@ QualType TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, - unsigned IndexTypeQuals) { + unsigned IndexTypeQuals, + SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, - IndexTypeQuals, SourceRange()); + IndexTypeQuals, BracketsRange); } template<typename Derived> QualType TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals) { + unsigned IndexTypeQuals, + SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0, - IndexTypeQuals, SourceRange()); + IndexTypeQuals, BracketsRange); } template<typename Derived> @@ -4980,13 +5212,14 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(ExprArg E) { template<typename Derived> QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( - TemplateName Template, - const TemplateArgument *Args, - unsigned NumArgs) { - // FIXME: Missing source locations for the template name, <, >. - return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(), - SourceLocation(), Args, NumArgs, - SourceLocation()); + TemplateName Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + SourceLocation RAngleLoc) { + return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, LAngleLoc, + Args, NumArgs, RAngleLoc); } template<typename Derived> @@ -5058,16 +5291,37 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, CXXScopeSpec SS; SS.setRange(SourceRange(getDerived().getBaseLocation())); SS.setScopeRep(Qualifier); + UnqualifiedId Name; + Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation()); return getSema().ActOnDependentTemplateName( /*FIXME:*/getDerived().getBaseLocation(), - II, - /*FIXME:*/getDerived().getBaseLocation(), SS, + Name, ObjectType.getAsOpaquePtr()) .template getAsVal<TemplateName>(); } template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + QualType ObjectType) { + CXXScopeSpec SS; + SS.setRange(SourceRange(getDerived().getBaseLocation())); + SS.setScopeRep(Qualifier); + UnqualifiedId Name; + SourceLocation SymbolLocations[3]; // FIXME: Bogus location information. + Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(), + Operator, SymbolLocations); + return getSema().ActOnDependentTemplateName( + /*FIXME:*/getDerived().getBaseLocation(), + SS, + Name, + ObjectType.getAsOpaquePtr()) + .template getAsVal<TemplateName>(); +} + +template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation OpLoc, @@ -5076,10 +5330,18 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, ExprArg Second) { Expr *FirstExpr = (Expr *)First.get(); Expr *SecondExpr = (Expr *)Second.get(); + DeclRefExpr *DRE + = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts()); bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus); // Determine whether this should be a builtin operation. - if (SecondExpr == 0 || isPostIncDec) { + if (Op == OO_Subscript) { + if (!FirstExpr->getType()->isOverloadableType() && + !SecondExpr->getType()->isOverloadableType()) + return getSema().CreateBuiltinArraySubscriptExpr(move(First), + DRE->getLocStart(), + move(Second), OpLoc); + } else if (SecondExpr == 0 || isPostIncDec) { if (!FirstExpr->getType()->isOverloadableType()) { // The argument is not of overloadable type, so try to create a // built-in unary operation. @@ -5109,9 +5371,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // used during overload resolution. Sema::FunctionSet Functions; - DeclRefExpr *DRE - = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts()); - // FIXME: Do we have to check // IsAcceptableNonMemberOperatorCandidate for each of these? for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F) @@ -5122,7 +5381,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, unsigned NumArgs = 1 + (SecondExpr != 0); DeclarationName OpName = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); - SemaRef.ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, + Functions); // Create the overloaded operator invocation for unary operators. if (NumArgs == 1 || isPostIncDec) { @@ -5131,6 +5391,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(First)); } + if (Op == OO_Subscript) + return SemaRef.CreateOverloadedArraySubscriptExpr(DRE->getLocStart(), OpLoc, + move(First),move(Second)); + // Create the overloaded operator invocation for binary operators. BinaryOperator::Opcode Opc = BinaryOperator::getOverloadedOpcode(Op); diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m index 818922e..db1a80b 100644 --- a/test/Analysis/misc-ps-eager-assume.m +++ b/test/Analysis/misc-ps-eager-assume.m @@ -77,3 +77,46 @@ void pr3836(int *a, int *b) { *a = 1; // no-warning *b = 1; // no-warning } + + +//===---------------------------------------------------------------------===// +// <rdar://problem/7342806> +// This false positive occured because the symbolic constraint on a short was +// not maintained via sign extension. The analyzer doesn't properly handle +// the sign extension, but now tracks the constraint. This particular +// case relies on -analyzer-eagerly-assume because of the expression +// 'Flag1 != Count > 0'. +//===---------------------------------------------------------------------===// + +void rdar7342806_aux(short x); + +void rdar7342806() { + extern short Count; + extern short Flag1; + + short *Pointer = 0; + short Flag2 = !!Pointer; // Flag2 is false (0). + short Ok = 1; + short Which; + + if( Flag1 != Count > 0 ) + // Static analyzer skips this so either + // Flag1 is true and Count > 0 + // or + // Flag1 is false and Count <= 0 + Ok = 0; + + if( Flag1 != Flag2 ) + // Analyzer skips this so Flag1 and Flag2 have the + // same value, both are false because Flag2 is false. And + // from that we know Count must be <= 0. + Ok = 0; + + for( Which = 0; + Which < Count && Ok; + Which++ ) + // This statement can only execute if Count > 0 which can only + // happen when Flag1 and Flag2 are both true and Flag2 will only + // be true when Pointer is not NULL. + rdar7342806_aux(*Pointer); // no-warning +} diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index b6fff10..4cde772 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -372,3 +372,62 @@ void doSomething_7312221_with_struct(struct rdar_7312221_container *Self) { } } +//===----------------------------------------------------------------------===// +// <rdar://problem/7332673> - Just more tests cases for regions +//===----------------------------------------------------------------------===// + +void rdar_7332673_test1() { + char value[1]; + if ( *(value) != 1 ) {} // expected-warning{{The left operand of '!=' is a garbage value}} +} +void rdar_rdar_7332673_test2_aux(char *x); +void rdar_7332673_test2() { + char *value; + if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{Pass-by-value argument in function call is undefined}} +} + +//===----------------------------------------------------------------------===// +// <rdar://problem/7347252>: Because of a bug in +// RegionStoreManager::RemoveDeadBindings(), the symbol for s->session->p +// would incorrectly be pruned from the state after the call to +// rdar7347252_malloc1(), and would incorrectly result in a warning about +// passing a null pointer to rdar7347252_memcpy(). +//===----------------------------------------------------------------------===// + +struct rdar7347252_AA { char *p;}; +typedef struct { + struct rdar7347252_AA *session; + int t; + char *q; +} rdar7347252_SSL1; + +int rdar7347252_f(rdar7347252_SSL1 *s); +char *rdar7347252_malloc1(int); +char *rdar7347252_memcpy1(char *d, char *s, int n) __attribute__((nonnull (1,2))); + +int rdar7347252(rdar7347252_SSL1 *s) { + rdar7347252_f(s); // the SymbolicRegion of 's' is set a default binding of conjured symbol + if (s->session->p == ((void*)0)) { + if ((s->session->p = rdar7347252_malloc1(10)) == ((void*)0)) { + return 0; + } + rdar7347252_memcpy1(s->session->p, "aa", 2); // no-warning + } + return 0; +} + +//===----------------------------------------------------------------------===// +// PR 5316 - "crash when accessing field of lazy compound value" +// Previously this caused a crash at the MemberExpr '.chr' when loading +// a field value from a LazyCompoundVal +//===----------------------------------------------------------------------===// + +typedef unsigned int pr5316_wint_t; +typedef pr5316_wint_t pr5316_REFRESH_CHAR; +typedef struct { + pr5316_REFRESH_CHAR chr; +} +pr5316_REFRESH_ELEMENT; +static void pr5316(pr5316_REFRESH_ELEMENT *dst, const pr5316_REFRESH_ELEMENT *src) { + while ((*dst++ = *src++).chr != L'\0') ; +} diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index fcc13a3..947b41a 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -121,12 +121,12 @@ void check_zero_sized_VLA(int x) { if (x) return; - int vla[x]; // expected-warning{{Variable-length array 'vla' has zero elements (undefined behavior)}} + int vla[x]; // expected-warning{{Declare variable-length array (VLA) of zero size}} } void check_uninit_sized_VLA() { int x; - int vla[x]; // expected-warning{{Variable-length array 'vla' garbage value for array size}} + int vla[x]; // expected-warning{{Declare variable-length array (VLA) of undefined size}} } // sizeof(void) @@ -154,6 +154,12 @@ void handle_sizeof_void(unsigned flag) { *p = 1; // no-warning } +// check deference of undefined values +void check_deref_undef(void) { + int *p; + *p = 0xDEADBEEF; // expected-warning{{Dereference of undefined pointer value}} +} + // PR 3422 void pr3422_helper(char *p); void pr3422() { diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c index 568f143..e676ea3 100644 --- a/test/Analysis/outofbound.c +++ b/test/Analysis/outofbound.c @@ -1,5 +1,5 @@ // RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s -// XFAIL +// XFAIL: * char f1() { char* s = "abcd"; diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m index 2833b02..e27cfe7 100644 --- a/test/Analysis/retain-release-gc-only.m +++ b/test/Analysis/retain-release-gc-only.m @@ -92,6 +92,7 @@ typedef struct _NSZone NSZone; + (id)allocWithZone:(NSZone *)zone; + (id)alloc; - (void)dealloc; +- (void)release; @end @interface NSObject (NSCoderMethods) - (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; @@ -322,6 +323,16 @@ void rdar_7174400(QCView *view, QCRenderer *renderer, CIContext *context, } //===----------------------------------------------------------------------===// +// <rdar://problem/6250216> Warn against using -[NSAutoreleasePool release] in +// GC mode +//===----------------------------------------------------------------------===// + +void rdar_6250216(void) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + [pool release]; // expected-warning{{Use -drain instead of -release when using NSAutoreleasePool and garbage collection}} +} + +//===----------------------------------------------------------------------===// // Tests of ownership attributes. //===----------------------------------------------------------------------===// diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index e620037..879e8a0 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -1098,6 +1098,32 @@ CVReturn rdar_7283567_2(CFAllocatorRef allocator, size_t width, size_t height, } //===----------------------------------------------------------------------===// +// <rdar://problem/7358899> False leak associated with +// CGBitmapContextCreateWithData +//===----------------------------------------------------------------------===// +typedef uint32_t CGBitmapInfo; +typedef void (*CGBitmapContextReleaseDataCallback)(void *releaseInfo, void *data); + +CGContextRef CGBitmapContextCreateWithData(void *data, + size_t width, size_t height, size_t bitsPerComponent, + size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo, + CGBitmapContextReleaseDataCallback releaseCallback, void *releaseInfo); + +void rdar_7358899(void *data, + size_t width, size_t height, size_t bitsPerComponent, + size_t bytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo, + CGBitmapContextReleaseDataCallback releaseCallback) { + + // For the allocated object, it doesn't really matter what type it is + // for the purpose of this test. All we want to show is that + // this is freed later by the callback. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + + CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, // expected-warning{{leak}} + bytesPerRow, space, bitmapInfo, releaseCallback, number); +} + +//===----------------------------------------------------------------------===// // <rdar://problem/7265711> allow 'new', 'copy', 'alloc', 'init' prefix to // start before '_' when determining Cocoa fundamental rule // diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c index 1561f11..e927a92 100644 --- a/test/Analysis/uninit-vals-ps-region.c +++ b/test/Analysis/uninit-vals-ps-region.c @@ -24,9 +24,20 @@ void test_uninit_pos() { struct TestUninit v1 = { 0, 0 }; struct TestUninit v2 = test_uninit_aux(); int z; - v1.y = z; - test_unit_aux2(v2.x + v1.y); // expected-warning{{The right operand of '+' is a garbage value}} + v1.y = z; // expected-warning{{Assigned value is garbage or undefined}} + test_unit_aux2(v2.x + v1.y); } +void test_uninit_pos_2() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2; + test_unit_aux2(v2.x + v1.y); // expected-warning{{The left operand of '+' is a garbage value}} +} +void test_uninit_pos_3() { + struct TestUninit v1 = { 0, 0 }; + struct TestUninit v2; + test_unit_aux2(v1.y + v2.x); // expected-warning{{The right operand of '+' is a garbage value}} +} + void test_uninit_neg() { struct TestUninit v1 = { 0, 0 }; struct TestUninit v2 = test_uninit_aux(); diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m index aacd44e..9e9360d 100644 --- a/test/Analysis/unused-ivars.m +++ b/test/Analysis/unused-ivars.m @@ -43,3 +43,25 @@ b(); } @end + +//===----------------------------------------------------------------------===// +// <rdar://problem/6260004> Detect that ivar is in use, if used in category +// in the same file as the implementation +//===----------------------------------------------------------------------===// + +@protocol Protocol6260004 +- (id) getId; +@end + +@interface RDar6260004 { +@private + id x; // no-warning +} +@end +@implementation RDar6260004 @end +@implementation RDar6260004 (Protocol6260004) +- (id) getId { + return x; +} +@end + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 66f05bf..a83a199 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,7 @@ set(CLANG_TEST_DIRECTORIES include(FindPythonInterp) if(PYTHONINTERP_FOUND) + get_target_triple(TARGET_TRIPLE) get_target_property(LLVM_TOOLS_PATH clang RUNTIME_OUTPUT_DIRECTORY) get_target_property(LLVM_LIBS_PATH clang LIBRARY_OUTPUT_DIRECTORY) set(CLANG_TEST_EXTRA_ARGS) @@ -32,16 +33,17 @@ if(PYTHONINTERP_FOUND) endif() foreach(testdir ${CLANG_TEST_DIRECTORIES}) - add_custom_target(clang-test-${testdir} + add_custom_target(clang-test-${testdir} COMMAND sed -e "s#\@LLVM_SOURCE_DIR\@#${LLVM_MAIN_SRC_DIR}#" -e "s#\@LLVM_BINARY_DIR\@#${LLVM_BINARY_DIR}#" -e "s#\@LLVM_TOOLS_DIR\@#${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}#" -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#" -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#" -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#" + -e "s#\@TARGET_TRIPLE\@#${TARGET_TRIPLE}#" ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in > ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${PYTHON_EXECUTABLE} ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR}/${testdir} @@ -56,9 +58,10 @@ if(PYTHONINTERP_FOUND) -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#" -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#" -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#" + -e "s#\@TARGET_TRIPLE\@#${TARGET_TRIPLE}#" ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in > ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${PYTHON_EXECUTABLE} ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR} @@ -72,12 +75,13 @@ if(PYTHONINTERP_FOUND) -e "s#\@LLVM_LIBS_DIR\@#${LLVM_LIBS_PATH}/${CMAKE_CFG_INTDIR}#" -e "s#\@CLANG_SOURCE_DIR\@#${CMAKE_CURRENT_SOURCE_DIR}/..#" -e "s#\@CLANG_BINARY_DIR\@#${CMAKE_CURRENT_BINARY_DIR}/..#" + -e "s#\@TARGET_TRIPLE\@#${TARGET_TRIPLE}#" ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in > ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${PYTHON_EXECUTABLE} ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests") -endif() +endif() diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp index b9b136c..141a573 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * namespace N { struct S {}; diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp index 9572aaa..cebc3e9 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * class C { public: diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp index 15c2634..9c969c5 100644 --- a/test/CXX/class/class.union/p1.cpp +++ b/test/CXX/class/class.union/p1.cpp @@ -16,6 +16,9 @@ class VirtualBase : virtual Okay { // expected-note 3 {{because type 'class Virt class Ctor { Ctor() { abort(); } // expected-note 3 {{because type 'class Ctor' has a user-declared constructor}} }; +class Ctor2 { + Ctor2(); // expected-note 3 {{because type 'class Ctor2' has a user-declared constructor}} +}; class CopyCtor { CopyCtor(CopyCtor &cc) { abort(); } // expected-note 3 {{because type 'class CopyCtor' has a user-declared copy constructor}} @@ -34,6 +37,7 @@ union U1 { Virtual v; // expected-error {{union member 'v' has a non-trivial copy constructor}} VirtualBase vbase; // expected-error {{union member 'vbase' has a non-trivial copy constructor}} Ctor ctor; // expected-error {{union member 'ctor' has a non-trivial constructor}} + Ctor2 ctor2; // expected-error {{union member 'ctor2' has a non-trivial constructor}} CopyCtor copyctor; // expected-error {{union member 'copyctor' has a non-trivial copy constructor}} CopyAssign copyassign; // expected-error {{union member 'copyassign' has a non-trivial copy assignment operator}} Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial destructor}} @@ -51,6 +55,9 @@ union U2 { Ctor ctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial constructor}} } m3; // expected-error {{union member 'm3' has a non-trivial constructor}} struct { + Ctor2 ctor2; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial constructor}} + } m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}} + struct { CopyCtor copyctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}} } m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}} struct { @@ -71,6 +78,8 @@ union U3 { } m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}} struct s3 : Ctor { // expected-note {{because type 'struct U3::s3' has a base class with a non-trivial constructor}} } m3; // expected-error {{union member 'm3' has a non-trivial constructor}} + struct s3a : Ctor2 { // expected-note {{because type 'struct U3::s3a' has a base class with a non-trivial constructor}} + } m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}} struct s4 : CopyCtor { // expected-note {{because type 'struct U3::s4' has a base class with a non-trivial copy constructor}} } m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}} struct s5 : CopyAssign { // expected-note {{because type 'struct U3::s5' has a base class with a non-trivial copy assignment operator}} diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p3.cpp index 3b0e345..dabe13a 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p3.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -verify %s -// XFAIL +// XFAIL: * void f0(void) { inline void f1(); // expected-error {{'inline' is not allowed on block scope function declaration}} diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp index 0142dcb..7dc65c7 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -verify %s -// XFAIL +// XFAIL: * void f0() { } diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp index c5f0a51..7a1ba3e 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -verify %s -// XFAIL +// XFAIL: * class A { public: diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p10.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p10.cpp index 62ae7bf..d125149 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p10.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p10.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -verify %s -// XFAIL +// XFAIL: * typedef const int T0; typedef int& T1; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp index f1413f9..69e8437 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -verify %s -// XFAIL +// XFAIL: * struct S { typedef struct A {} A; // expected-note {{previous definition is here}} diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp new file mode 100644 index 0000000..98e1d30 --- /dev/null +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp @@ -0,0 +1,145 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++ [dcl.ref]p5: +// There shall be no references to references, no arrays of +// references, and no pointers to references. + +// The crazy formatting in here is to enforce the exact report locations. + +typedef int &intref; +typedef intref &intrefref; + +template <class T> class RefMem { + T + & + member; +}; + +struct RefRef { + int + & + & // expected-error {{declared as a reference to a reference}} + refref0; + + intref + & + refref1; // collapses + + intrefref + & + refref2; // collapses + + RefMem + < + int + & + > + refref3; // collapses +}; + + +template <class T> class PtrMem { + T + * // expected-error {{declared as a pointer to a reference}} + member; +}; + +struct RefPtr { + typedef + int + & + * // expected-error {{declared as a pointer to a reference}} + intrefptr; + + typedef + intref + * // expected-error {{declared as a pointer to a reference}} + intrefptr2; + + int + & + * // expected-error {{declared as a pointer to a reference}} + refptr0; + + intref + * // expected-error {{declared as a pointer to a reference}} + refptr1; + + PtrMem + < + int + & + > + refptr2; // expected-note {{in instantiation}} +}; + +template <class T> class ArrMem { + T + member + [ // expected-error {{declared as array of references}} + 10 + ]; +}; +template <class T, unsigned N> class DepArrMem { + T + member + [ // expected-error {{declared as array of references}} + N + ]; +}; + +struct RefArr { + typedef + int + & + intrefarr + [ // expected-error {{declared as array of references}} + 2 + ]; + + typedef + intref + intrefarr + [ // expected-error {{declared as array of references}} + 2 + ]; + + int + & + refarr0 + [ // expected-error {{declared as array of references}} + 2 + ]; + intref + refarr1 + [ // expected-error {{declared as array of references}} + 2 + ]; + ArrMem + < + int + & + > + refarr2; // expected-note {{in instantiation}} + DepArrMem + < + int + &, + 10 + > + refarr3; // expected-note {{in instantiation}} +}; + + +// The declaration of a reference shall contain an initializer +// (8.5.3) except when the declaration contains an explicit extern +// specifier (7.1.1), is a class member (9.2) declaration within a +// class definition, or is the declaration of a parameter or a +// return type (8.3.5); see 3.1. A reference shall be initialized to +// refer to a valid object or function. [ Note: in particular, a +// null reference cannot exist in a well-defined program, because +// the only way to create such a reference would be to bind it to +// the "object" obtained by dereferencing a null pointer, which +// causes undefined behavior. As described in 9.6, a reference +// cannot be bound directly to a bit-field. + diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp index afe6ab2..79d6c54 100644 --- a/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp +++ b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp @@ -1,5 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify %s +// Test class template partial specializations of member templates. template<typename T> struct X0 { template<typename U> struct Inner0 { @@ -16,5 +17,39 @@ struct X0<T>::Inner0<const U*> { static const unsigned value = 2; }; -// FIXME: Test instantiation of these partial specializations (once they are -// implemented). +int array0[X0<int>::Inner0<int>::value == 0? 1 : -1]; +int array1[X0<int>::Inner0<int*>::value == 1? 1 : -1]; +int array2[X0<int>::Inner0<const int*>::value == 2? 1 : -1]; + +// Make sure we can provide out-of-line class template partial specializations +// for member templates (and instantiate them). +template<class T> struct A { + struct C { + template<class T2> struct B; + }; +}; + +// partial specialization of A<T>::C::B<T2> +template<class T> template<class T2> struct A<T>::C::B<T2*> { }; + +A<short>::C::B<int*> absip; + +// Check for conflicts during template instantiation. +template<typename T, typename U> +struct Outer { + template<typename X, typename Y> struct Inner; + template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous}} + template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}} +}; + +Outer<int, int> outer; // expected-note{{instantiation}} + +// Test specialization of class template partial specialization members. +template<> template<typename Z> +struct X0<float>::Inner0<Z*> { + static const unsigned value = 3; +}; + +int array3[X0<float>::Inner0<int>::value == 0? 1 : -1]; +int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1]; +int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1]; diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp index f1142a4..74895c4 100644 --- a/test/CXX/temp/temp.decls/temp.friend/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp @@ -9,3 +9,5 @@ class B { template <class T> friend class A<T>::Member; }; +A<int> a; +B b; diff --git a/test/CXX/temp/temp.param/p14.cpp b/test/CXX/temp/temp.param/p14.cpp index 07e6bfe..150e0ad 100644 --- a/test/CXX/temp/temp.param/p14.cpp +++ b/test/CXX/temp/temp.param/p14.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * // A template-parameter shall not be used in its own default argument. template<typename T = typename T::type> struct X; // expected-error{{default}} diff --git a/test/CXX/temp/temp.res/temp.dep.res/temp.point/p1.cpp b/test/CXX/temp/temp.res/temp.dep.res/temp.point/p1.cpp index 6505010..a41b46f 100644 --- a/test/CXX/temp/temp.res/temp.dep.res/temp.point/p1.cpp +++ b/test/CXX/temp/temp.res/temp.dep.res/temp.point/p1.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * // Note: we fail this test because we perform template instantiation // at the end of the translation unit, so argument-dependent lookup diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp index 2bd1400..33fb93b 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp @@ -4,8 +4,7 @@ namespace N { template<class T> class X; } -// FIXME: this diagnostic is terrible (PR3844). -template<> class X<int> { /* ... */ }; // expected-error {{unqualified-id}} +template<> class X<int> { /* ... */ }; // expected-error {{non-template class 'X'}} namespace N { diff --git a/test/CXX/temp/temp.spec/temp.explicit/p10.cpp b/test/CXX/temp/temp.spec/temp.explicit/p10.cpp new file mode 100644 index 0000000..900b0b3 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p10.cpp @@ -0,0 +1,33 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X0 { + void f(T&); + + struct Inner; + + static T static_var; +}; + +template<typename T> +void X0<T>::f(T& t) { + t = 1; // expected-error{{incompatible type}} +} + +template<typename T> +struct X0<T>::Inner { + T member; +}; + +template<typename T> +T X0<T>::static_var = 1; // expected-error{{incompatible type}} + +extern template struct X0<void*>; +template struct X0<void*>; // expected-note 2{{instantiation}} + +template struct X0<int>; // expected-note 4{{explicit instantiation definition is here}} + +extern template void X0<int>::f(int&); // expected-error{{follows explicit instantiation definition}} +extern template struct X0<int>::Inner; // expected-error{{follows explicit instantiation definition}} +extern template int X0<int>::static_var; // expected-error{{follows explicit instantiation definition}} +extern template struct X0<int>; // expected-error{{follows explicit instantiation definition}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p12.cpp b/test/CXX/temp/temp.spec/temp.explicit/p12.cpp new file mode 100644 index 0000000..fdf4393 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p12.cpp @@ -0,0 +1,6 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +char* p = 0; +template<class T> T g(T x = &p) { return x; } +template int g<int>(int); // OK even though &p isn’t an int. + diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp index 2bd781b..9057971 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp @@ -9,15 +9,13 @@ template void f0(int); // okay // template shall be in scope at the point of the explicit instantiation of // the member function template. struct X0; // expected-note 2{{forward declaration}} -template<typename> struct X1; // expected-note 2{{declared here}} \ - // expected-note 3{{forward declaration}} +template<typename> struct X1; // expected-note 5{{declared here}} // FIXME: Repeated diagnostics here! template void X0::f0<int>(int); // expected-error 2{{incomplete type}} \ - // expected-error{{invalid token after}} -template void X1<int>::f0<int>(int); // expected-error{{implicit instantiation of undefined template}} \ - // expected-error{{incomplete type}} \\ - // expected-error{{invalid token}} + // expected-error{{does not refer}} +template void X1<int>::f0<int>(int); // expected-error 2{{implicit instantiation of undefined template}} \ + // expected-error{{does not refer}} // A definition of a class template or class member template shall be in scope // at the point of the explicit instantiation of the class template or class @@ -37,10 +35,10 @@ template struct X2<int>::Inner<float>; // expected-error{{explicit instantiation // A definition of a class template shall be in scope at the point of an // explicit instantiation of a member function or a static data member of the // class template. -template void X1<int>::f1(int); // expected-error{{incomplete type}} \ +template void X1<int>::f1(int); // expected-error{{undefined template}} \ // expected-error{{does not refer}} -template int X1<int>::member; // expected-error{{incomplete type}} \ +template int X1<int>::member; // expected-error{{undefined template}} \ // expected-error{{does not refer}} // A definition of a member class of a class template shall be in scope at the diff --git a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp new file mode 100644 index 0000000..a992648 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace N { + template<class T> class Y { // expected-note{{explicit instantiation refers here}} + void mf() { } + }; +} + +template class Z<int>; // expected-error{{explicit instantiation of non-template class 'Z'}} + +// FIXME: This example from the standard is wrong; note posted to CWG reflector +// on 10/27/2009 +using N::Y; +template class Y<int>; // expected-error{{must occur in}} + +template class N::Y<char*>; +template void N::Y<double>::mf(); diff --git a/test/CXX/temp/temp.spec/temp.explicit/p6.cpp b/test/CXX/temp/temp.spec/temp.explicit/p6.cpp new file mode 100644 index 0000000..763d679 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p6.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<class T> class Array { /* ... */ }; +template<class T> void sort(Array<T>& v) { } + +// instantiate sort(Array<int>&) - template-argument deduced +template void sort<>(Array<int>&); + +template void sort(Array<long>&); + +template<typename T, typename U> void f0(T, U*) { } + +template void f0<int>(int, float*); +template void f0<>(double, float*); diff --git a/test/CXX/temp/temp.spec/temp.explicit/p7.cpp b/test/CXX/temp/temp.spec/temp.explicit/p7.cpp new file mode 100644 index 0000000..ffd653d --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p7.cpp @@ -0,0 +1,36 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X0 { + struct MemberClass { + T member; // expected-error{{with function type}} + }; + + T* f0(T* ptr) { + return ptr + 1; // expected-error{{pointer to function}} + } + + static T* static_member; +}; + +template<typename T> +T* X0<T>::static_member = ((T*)0) + 1; // expected-error{{pointer to function}} + +template class X0<int>; // okay + +template class X0<int(int)>; // expected-note 3{{requested here}} + +// Specialize everything, so that the explicit instantiation does not trigger +// any diagnostics. +template<> +struct X0<int(long)>::MemberClass { }; + +typedef int int_long_func(long); +template<> +int_long_func *X0<int_long_func>::f0(int_long_func *) { return 0; } + +template<> +int_long_func *X0<int(long)>::static_member; + +template class X0<int(long)>; + diff --git a/test/CXX/temp/temp.spec/temp.explicit/p8.cpp b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp new file mode 100644 index 0000000..9a5bd32 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X0 { + struct MemberClass; + + T* f0(T* ptr); + + static T* static_member; +}; + +template class X0<int>; // okay +template class X0<int(int)>; // okay; nothing gets instantiated. + +template<typename T> +struct X0<T>::MemberClass { + T member; +}; + +template<typename T> +T* X0<T>::f0(T* ptr) { + return ptr + 1; +} + +template<typename T> +T* X0<T>::static_member = 0; + diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp new file mode 100644 index 0000000..59705d8 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp @@ -0,0 +1,66 @@ +// RUN: clang-cc -emit-llvm -std=c++0x -o - %s | FileCheck %s + +template<typename T> +struct X0 { + void f(T &t) { + t = 0; + } + + void g(T &t); + + void h(T &t); + + static T static_var; +}; + +template<typename T> +inline void X0<T>::g(T & t) { + t = 0; +} + +template<typename T> +void X0<T>::h(T & t) { + t = 0; +} + +template<typename T> +T X0<T>::static_var = 0; + +extern template struct X0<int*>; + +int *&test(X0<int*> xi, int *ip) { + // CHECK: define available_externally void @_ZN2X0IPiE1fERS0_ + xi.f(ip); + // CHECK: define available_externally void @_ZN2X0IPiE1gERS0_ + xi.g(ip); + // CHECK: declare void @_ZN2X0IPiE1hERS0_ + xi.h(ip); + return X0<int*>::static_var; +} + +template<typename T> +void f0(T& t) { + t = 0; +} + +template<typename T> +inline void f1(T& t) { + t = 0; +} + +extern template void f0<>(int *&); +extern template void f1<>(int *&); + +void test_f0(int *ip, float *fp) { + // CHECK: declare void @_Z2f0IPiEvRT_ + f0(ip); + // CHECK: define linkonce_odr void @_Z2f0IPfEvRT_ + f0(fp); +} + +void test_f1(int *ip, float *fp) { + // CHECK: define available_externally void @_Z2f1IPiEvRT_ + f1(ip); + // CHECK: define linkonce_odr void @_Z2f1IPfEvRT_ + f1(fp); +} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p9.cpp b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp new file mode 100644 index 0000000..a53113f --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p9.cpp @@ -0,0 +1,59 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s + +template<typename T> +struct X0 { + void f(T &t) { + t = 1; // expected-error{{incompatible type}} + } + + void g(T &t); + + void h(T &t); + + static T static_var; +}; + +template<typename T> +inline void X0<T>::g(T & t) { + t = 1; // expected-error{{incompatible type}} +} + +template<typename T> +void X0<T>::h(T & t) { + t = 1; +} + +template<typename T> +T X0<T>::static_var = 1; + +extern template struct X0<int*>; + +int *&test(X0<int*> xi, int *ip) { + xi.f(ip); // expected-note{{instantiation}} + xi.g(ip); // expected-note{{instantiation}} + xi.h(ip); + return X0<int*>::static_var; +} + +template<typename T> +void f0(T& t) { + t = 1; // expected-error{{incompatible type}} +} + +template<typename T> +inline void f1(T& t) { + t = 1; // expected-error 2{{incompatible type}} +} + +extern template void f0<>(int *&); +extern template void f1<>(int *&); + +void test_f0(int *ip, float *fp) { + f0(ip); + f0(fp); // expected-note{{instantiation}} +} + +void test_f1(int *ip, float *fp) { + f1(ip); // expected-note{{instantiation}} + f1(fp); // expected-note{{instantiation}} +} diff --git a/test/CodeCompletion/macros.c b/test/CodeCompletion/macros.c new file mode 100644 index 0000000..d5c1f8f --- /dev/null +++ b/test/CodeCompletion/macros.c @@ -0,0 +1,37 @@ +#define FOO +#define BAR(X, Y) X, Y +#define IDENTITY(X) X +#define WIBBLE(...) + +enum Color { + Red, Green, Blue +}; + +struct Point { + float x, y, z; + enum Color color; +}; + +void test(struct Point *p) { + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:17:14 %s -o - | FileCheck -check-prefix=CC1 %s && + switch (p->IDENTITY(color)) { + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC2 %s && + case + } + // CC1: color + // CC1: x + // CC1: y + // CC1: z + // CC1: BAR(<#X#>, <#Y#>) + // CC1: FOO + // CC1: IDENTITY(<#X#>) + // CC1: WIBBLE + // CC2: Blue + // CC2: Green + // CC2: Red + // CC2: BAR(<#X#>, <#Y#>) + // CC2: FOO + // CC2: IDENTITY(<#X#>) + // CC2: WIBBLE + // RUN: true +} diff --git a/test/CodeGen/2008-07-21-mixed-var-fn-decl.c b/test/CodeGen/2008-07-21-mixed-var-fn-decl.c index c55c86b..59a3f38 100644 --- a/test/CodeGen/2008-07-21-mixed-var-fn-decl.c +++ b/test/CodeGen/2008-07-21-mixed-var-fn-decl.c @@ -1,5 +1,8 @@ -// RUN: clang-cc -emit-llvm -o - %s | grep -e "@g[0-9] " | count 2 +// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s int g0, f0(); int f1(), g1; +// CHECK: @g0 = common global i32 0, align 4 +// CHECK: @g1 = common global i32 0, align 4 + diff --git a/test/CodeGen/2008-07-29-override-alias-decl.c b/test/CodeGen/2008-07-29-override-alias-decl.c index 4a36e0f..8729500 100644 --- a/test/CodeGen/2008-07-29-override-alias-decl.c +++ b/test/CodeGen/2008-07-29-override-alias-decl.c @@ -1,7 +1,13 @@ -// RUN: clang-cc -emit-llvm -o - %s | grep -e "^@f" | count 1 +// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s int x() { return 1; } +// CHECK: %retval = alloca i32 +// CHECK: store i32 1, i32* %retval +// CHECK: %0 = load i32* %retval +// CHECK: ret i32 %0 + + int f() __attribute__((weak, alias("x"))); /* Test that we link to the alias correctly instead of making a new @@ -10,3 +16,10 @@ int f(); int h() { return f(); } + +// CHECK: %retval = alloca i32 +// CHECK: %call = call i32 (...)* @f() +// CHECK: store i32 %call, i32* %retval +// CHECK: %0 = load i32* %retval +// CHECK: ret i32 %0 + diff --git a/test/CodeGen/asm-inout.c b/test/CodeGen/asm-inout.c index 0d8dbdf..bd287ad 100644 --- a/test/CodeGen/asm-inout.c +++ b/test/CodeGen/asm-inout.c @@ -1,6 +1,6 @@ // RUN: clang-cc -triple i386-unknown-unknown -emit-llvm %s -o %t && // RUN: grep "load i8\*\*\* %p.addr" %t | count 1 -// XFAIL +// XFAIL: * // PR3800 void f(void **p) diff --git a/test/CodeGen/blocks-2.c b/test/CodeGen/blocks-2.c index bc6c2b9..acbaafd 100644 --- a/test/CodeGen/blocks-2.c +++ b/test/CodeGen/blocks-2.c @@ -1,7 +1,7 @@ // RUN: clang-cc -g %s -emit-llvm -o %t -fblocks && // RUN: grep "func.start" %t | count 4 // 1 declaration, 1 bar, 1 test_block_dbg and 1 for the block. -// XFAIL +// XFAIL: * static __inline__ __attribute__((always_inline)) int bar(int va, int vb) { return (va == vb); } diff --git a/test/CodeGen/builtin-unwind-init.c b/test/CodeGen/builtin-unwind-init.c index 49a016a..56872f7 100644 --- a/test/CodeGen/builtin-unwind-init.c +++ b/test/CodeGen/builtin-unwind-init.c @@ -1,4 +1,5 @@ -// RUN: clang-cc -emit-llvm < %s -o - | grep -F "llvm.eh.unwind.init" +// RUN: clang-cc -emit-llvm < %s -o - | FileCheck %s -int a() { __builtin_unwind_init(); } +void a() { __builtin_unwind_init(); } +// CHECK: call void @llvm.eh.unwind.init() diff --git a/test/CodeGen/cast-to-union.c b/test/CodeGen/cast-to-union.c index 6742992..1f7e045 100644 --- a/test/CodeGen/cast-to-union.c +++ b/test/CodeGen/cast-to-union.c @@ -1,5 +1,5 @@ // RUN: clang-cc -emit-llvm %s -o - | FileCheck %s -// CHECK: w = global %0 { i32 2, [4 x i8] zeroinitializer } +// CHECK: w = global %0 { i32 2, [4 x i8] undef } // CHECK: y = global %union.u { double 7.300000e+0{{[0]*}}1 } // CHECK: store i32 351, i32 diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c index d2d3b03..b09b28b 100644 --- a/test/CodeGen/function-attributes.c +++ b/test/CodeGen/function-attributes.c @@ -1,12 +1,12 @@ -// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o %t %s && -// RUN: grep 'define signext i8 @f0(i32 %x) nounwind' %t && -// RUN: grep 'define zeroext i8 @f1(i32 %x) nounwind' %t && -// RUN: grep 'define void @f2(i8 signext %x) nounwind' %t && -// RUN: grep 'define void @f3(i8 zeroext %x) nounwind' %t && -// RUN: grep 'define signext i16 @f4(i32 %x) nounwind' %t && -// RUN: grep 'define zeroext i16 @f5(i32 %x) nounwind' %t && -// RUN: grep 'define void @f6(i16 signext %x) nounwind' %t && -// RUN: grep 'define void @f7(i16 zeroext %x) nounwind' %t && +// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -Os -o - %s | FileCheck %s +// CHECK: define signext i8 @f0(i32 %x) nounwind +// CHECK: define zeroext i8 @f1(i32 %x) nounwind +// CHECK: define void @f2(i8 signext %x) nounwind +// CHECK: define void @f3(i8 zeroext %x) nounwind +// CHECK: define signext i16 @f4(i32 %x) nounwind +// CHECK: define zeroext i16 @f5(i32 %x) nounwind +// CHECK: define void @f6(i16 signext %x) nounwind +// CHECK: define void @f7(i16 zeroext %x) nounwind signed char f0(int x) { return x; } @@ -24,15 +24,22 @@ void f6(signed short x) { } void f7(unsigned short x) { } -// RUN: grep 'define void @f8() nounwind alwaysinline' %t && +// CHECK: define void @f8() +// CHECK: nounwind +// CHECK: alwaysinline +// CHECK: { void __attribute__((always_inline)) f8(void) { } -// RUN: grep 'call void @f9_t() noreturn' %t && +// CHECK: call void @f9_t() +// CHECK: noreturn +// CHECK: { void __attribute__((noreturn)) f9_t(void); void f9(void) { f9_t(); } // FIXME: We should be setting nounwind on calls. -// RUN: grep 'call i32 @f10_t() readnone' %t && +// CHECK: call i32 @f10_t() +// CHECK: readnone +// CHECK: { int __attribute__((const)) f10_t(void); int f10(void) { return f10_t(); } int f11(void) { @@ -43,13 +50,15 @@ int f12(int arg) { return arg ? 0 : f10_t(); } -// RUN: grep 'define void @f13() nounwind readnone' %t && +// CHECK: define void @f13() nounwind readnone void f13(void) __attribute__((pure)) __attribute__((const)); void f13(void){} // Ensure that these get inlined: rdar://6853279 -// RUN: not grep '@ai_' %t && +// CHECK: define void @f14 +// CHECK-NOT: @ai_ +// CHECK: call void @f14_end static __inline__ __attribute__((always_inline)) int ai_1() { return 4; } @@ -58,12 +67,17 @@ struct { int a, b, c, d, e; } ai_2() { while (1) {} } - -int foo() { - ai_2(); - return ai_1(); +void f14(int a) { + extern void f14_end(void); + if (a) + ai_2(); + ai_1(); + f14_end(); } - - -// RUN: true +// <rdar://problem/7102668> [irgen] clang isn't setting the optsize bit on functions +// CHECK: define void @f15 +// CHECK: optsize +// CHECK: { +void f15(void) { +} diff --git a/test/CodeGen/indirect-goto.c b/test/CodeGen/indirect-goto.c index b9a6019..6804f57 100644 --- a/test/CodeGen/indirect-goto.c +++ b/test/CodeGen/indirect-goto.c @@ -1,9 +1,7 @@ -// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t && -// RUN: grep "ret i32" %t | count 1 && -// RUN: grep "ret i32 210" %t | count 1 +// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts -S | grep "ret i32 2520" static int foo(unsigned i) { - const void *addrs[] = { &&L1, &&L2, &&L3, &&L4, &&L5 }; + void *addrs[] = { &&L1, &&L2, &&L3, &&L4, &&L5 }; int res = 1; goto *addrs[i]; @@ -15,6 +13,19 @@ static int foo(unsigned i) { return res; } -int bar() { - return foo(3); +static int foo2(unsigned i) { + static const void *addrs[] = { &&L1, &&L2, &&L3, &&L4, &&L5 }; + int res = 1; + + goto *addrs[i]; +L5: res *= 11; +L4: res *= 7; +L3: res *= 5; +L2: res *= 3; +L1: res *= 2; + return res; +} + +int main() { + return foo(3)+foo2(4); } diff --git a/test/CodeGen/mangle.c b/test/CodeGen/mangle.c index 17d74ba..6f42f6f 100644 --- a/test/CodeGen/mangle.c +++ b/test/CodeGen/mangle.c @@ -1,22 +1,20 @@ -// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s && -// RUN: grep '@_Z2f0i' %t && -// RUN: grep '@_Z2f0l' %t && +// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s -// Make sure we mangle overloadable, even in C system headers. +// CHECK: @"\01foo" +// Make sure we mangle overloadable, even in C system headers. # 1 "somesystemheader.h" 1 3 4 +// CHECK: @_Z2f0i void __attribute__((__overloadable__)) f0(int a) {} +// CHECK: @_Z2f0l void __attribute__((__overloadable__)) f0(long b) {} - +// CHECK: @"\01bar" // These should get merged. void foo() __asm__("bar"); void foo2() __asm__("bar"); -// RUN: grep '@"\\01foo"' %t && -// RUN: grep '@"\\01bar"' %t - int nux __asm__("foo"); extern float nux2 __asm__("foo"); @@ -52,3 +50,12 @@ void foo6() { int foo7 __asm__("foo7") __attribute__((used)); float foo8 __asm__("foo7") = 42; + +// PR4412 +int func(void); +extern int func (void) __asm__ ("FUNC"); + +// CHECK: @"\01FUNC" +int func(void) { + return 42; +} diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c new file mode 100644 index 0000000..61d8541 --- /dev/null +++ b/test/CodeGen/object-size.c @@ -0,0 +1,126 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o - | FileCheck %s + +#define strcpy(dest, src) \ + ((__builtin_object_size(dest, 0) != -1ULL) \ + ? __builtin___strcpy_chk (dest, src, __builtin_object_size(dest, 1)) \ + : __inline_strcpy_chk(dest, src)) + +static char *__inline_strcpy_chk (char *dest, const char *src) { + return __builtin___strcpy_chk(dest, src, __builtin_object_size(dest, 1)); +} + +char gbuf[63]; +char *gp; +int gi, gj; + +void test1() { + // CHECK: movabsq $59, %rdx + // CHECK-NEXT: movq %rax, %rdi + // CHECK-NEXT: movq %rcx, %rsi + // CHECK-NEXT: call ___strcpy_chk + strcpy(&gbuf[4], "Hi there"); +} + +void test2() { + // CHECK: movabsq $63, %rdx + // CHECK-NEXT: movq %rax, %rdi + // CHECK-NEXT: movq %rcx, %rsi + // CHECK-NEXT: call ___strcpy_chk + strcpy(gbuf, "Hi there"); +} + +void test3() { + // CHECK: movabsq $0, %rdx + // CHECK-NEXT: movq %rax, %rdi + // CHECK-NEXT: movq %rcx, %rsi + // CHECK-NEXT: call ___strcpy_chk + strcpy(&gbuf[100], "Hi there"); +} + +void test4() { + // CHECK: movabsq $0, %rdx + // CHECK-NEXT: movq %rax, %rdi + // CHECK-NEXT: movq %rcx, %rsi + // CHECK-NEXT: call ___strcpy_chk + strcpy((char*)(void*)&gbuf[-1], "Hi there"); +} + +void test5() { + // CHECK: movb $0, %al + // CHECK-NEXT: testb %al, %al + // CHECK: call ___inline_strcpy_chk + strcpy(gp, "Hi there"); +} + +void test6() { + char buf[57]; + + // CHECK: movabsq $53, %rdx + // CHECK-NEXT: movq %rax, %rdi + // CHECK-NEXT: movq %rcx, %rsi + // CHECK-NEXT: call ___strcpy_chk + strcpy(&buf[4], "Hi there"); +} + +void test7() { + int i; + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy((++i, gbuf), "Hi there"); +} + +void test8() { + char *buf[50]; + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(buf[++gi], "Hi there"); +} + +void test9() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy((char *)((++gi) + gj), "Hi there"); +} + +char **p; +void test10() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(*(++p), "Hi there"); +} + +void test11() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(gp = gbuf, "Hi there"); +} + +void test12() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(++gp, "Hi there"); +} + +void test13() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(gp++, "Hi there"); +} + +void test14() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(--gp, "Hi there"); +} + +void test15() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(gp--, "Hi there"); +} + +void test16() { + // CHECK-NOT: call ___strcpy_chk + // CHECK: call ___inline_strcpy_chk + strcpy(gp += 1, "Hi there"); +} diff --git a/test/CodeGen/union-init2.c b/test/CodeGen/union-init2.c index 184d75f..e782425 100644 --- a/test/CodeGen/union-init2.c +++ b/test/CodeGen/union-init2.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm %s -o - -triple i686-pc-linux-gnu | grep "bitcast (%0\* @r to %union.x\*), \[4 x i8\] zeroinitializer" +// RUN: clang-cc -emit-llvm %s -o - -triple i686-pc-linux-gnu | grep "bitcast (%0\* @r to %union.x\*), \[4 x i8\] undef" // Make sure we generate something sane instead of a ptrtoint union x {long long b;union x* a;} r = {.a = &r}; diff --git a/test/CodeGen/volatile.c b/test/CodeGen/volatile.c index 87cb5ff..e176690 100644 --- a/test/CodeGen/volatile.c +++ b/test/CodeGen/volatile.c @@ -1,8 +1,8 @@ // RUN: clang-cc -emit-llvm < %s -o %t && -// RUN: grep volatile %t | count 25 && +// RUN: grep volatile %t | count 29 && // RUN: grep memcpy %t | count 7 -// The number 25 comes from the current codegen for volatile loads; +// The number 29 comes from the current codegen for volatile loads; // if this number changes, it's not necessarily something wrong, but // something has changed to affect volatile load/store codegen @@ -38,6 +38,9 @@ volatile extv4 vVE; volatile struct {int x;} aggFct(void); +typedef volatile int volatile_int; +volatile_int vtS; + int main() { int i; @@ -62,6 +65,7 @@ int main() { i=VE.yx[1]; i=vVE.zy[1]; i = aggFct().x; + i=vtS; // store @@ -81,12 +85,14 @@ int main() { vBF.x=i; V[3]=i; vV[3]=i; + vtS=i; // other ops: ++S; ++vS; i+=S; i+=vS; + ++vtS; (void)vF2; vF2 = vF2; vF2 = vF2 = vF2; diff --git a/test/CodeGenCXX/array-construction.cpp b/test/CodeGenCXX/array-construction.cpp new file mode 100644 index 0000000..b444221 --- /dev/null +++ b/test/CodeGenCXX/array-construction.cpp @@ -0,0 +1,40 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true + +extern "C" int printf(...); + +static int count; +static float fcount; + +class xpto { +public: + xpto() : i(count++), f(fcount++) { + printf("xpto::xpto()\n"); + } + int i; + float f; + +/** + NYI + ~xpto() { + printf("xpto::~xpto()\n"); + } +*/ +}; + +int main() { + xpto array[2][3][4]; + for (int h = 0; h < 2; h++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + printf("array[%d][%d][%d] = {%d, %f}\n", + h, i, j, array[h][i][j].i, array[h][i][j].f); +} + +// CHECK-LP64: call __ZN4xptoC1Ev + +// CHECK-LP32: call L__ZN4xptoC1Ev + diff --git a/test/CodeGenCXX/ptr-to-datamember.cpp b/test/CodeGenCXX/ptr-to-datamember.cpp index eee03c0..a7b4cc2 100644 --- a/test/CodeGenCXX/ptr-to-datamember.cpp +++ b/test/CodeGenCXX/ptr-to-datamember.cpp @@ -51,6 +51,21 @@ void test_aggr_pdata(A& a1) { pr(a1.*af); } +void test_aggr_pdata_1(A* pa) { + F A::* af = &A::Af; + pr(pa->*af); + + (pa->*af).iF = 100; + (pa->*af).fF = 200.00; + printf(" %d %f\n", (pa->*af).iF, (pa->*af).fF); + pr(pa->*af); + + (pa->*af).iF++; + (pa->*af).fF--; + --(pa->*af).fF; + pr(pa->*af); +} + int main() { A a1; @@ -67,4 +82,5 @@ int main() printf("%d\n", &A::B1::V::iV); printf("%d, %f, %f \n", a1.*pa, a1.*pf, a1.*pd); test_aggr_pdata(a1); + test_aggr_pdata_1(&a1); } diff --git a/test/CodeGenCXX/ptr-to-member-function.cpp b/test/CodeGenCXX/ptr-to-member-function.cpp new file mode 100644 index 0000000..1e396e9 --- /dev/null +++ b/test/CodeGenCXX/ptr-to-member-function.cpp @@ -0,0 +1,53 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true +// 13.3.3.2 Ranking implicit conversion sequences + +extern "C" int printf(...); + +struct A { +int Ai; +}; + +struct B : public A { + void bf() { printf("B::bf called\n"); } +}; + +struct C : public B { }; + +// conversion of B::* to C::* is better than conversion of A::* to C::* +typedef void (A::*pmfa)(); +typedef void (B::*pmfb)(); +typedef void (C::*pmfc)(); + +struct X { + operator pmfa(); + operator pmfb() { + return &B::bf; + } +}; + + +void g(pmfc pm) { + C c; + (c.*pm)(); +} + +void test2(X x) +{ + g(x); +} + +int main() +{ + X x; + test2(x); +} + +// CHECK-LP64: call __ZN1XcvM1BFvvEEv +// CHECK-LP64: call __Z1gM1CFvvE + +// CHECK-LP32: call L__ZN1XcvM1BFvvEEv +// CHECK-LP32: call __Z1gM1CFvvE diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp index d622193..e9ed0f7 100644 --- a/test/CodeGenCXX/temporaries.cpp +++ b/test/CodeGenCXX/temporaries.cpp @@ -53,9 +53,9 @@ struct D { }; void f4() { - // CHECK call void @_ZN1DC1Ev - // CHECK call void @_ZN1DD1Ev - // CHECK call void @_ZN1DD1Ev + // CHECK: call void @_ZN1DC1Ev + // CHECK: call void @_ZN1DD1Ev + // CHECK: call void @_ZN1DD1Ev D()(); } diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index 21fecac..7911940 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -91,6 +91,50 @@ int main() { // CHECK-LP64: movl $1, 12(%rax) // CHECK-LP64: movl $2, 8(%rax) +// FIXME: This is the wrong thunk, but until these issues are fixed, better +// than nothing. +// CHECK-LP64: __ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev: +// CHECK-LP64-NEXT:Leh_func_begin43: +// CHECK-LP64-NEXT: subq $24, %rsp +// CHECK-LP64-NEXT:Llabel43: +// CHECK-LP64-NEXT: movq %rdi, %rax +// CHECK-LP64-NEXT: movq %rax, 8(%rsp) +// CHECK-LP64-NEXT: movq 8(%rsp), %rax +// CHECK-LP64-NEXT: movq %rax, %rcx +// CHECK-LP64-NEXT: movabsq $-16, %rdx +// CHECK-LP64-NEXT: addq %rdx, %rcx +// CHECK-LP64-NEXT: movq -16(%rax), %rax +// CHECK-LP64-NEXT: movq -72(%rax), %rax +// CHECK-LP64-NEXT: addq %rax, %rcx +// CHECK-LP64-NEXT: movq %rcx, %rax +// CHECK-LP64-NEXT: movq %rax, %rdi +// CHECK-LP64-NEXT: call __ZTch0_v16_n32_N8test16_D4foo1Ev +// CHECK-LP64-NEXT: movq %rax, 16(%rsp) +// CHECK-LP64-NEXT: movq 16(%rsp), %rax +// CHECK-LP64-NEXT: addq $24, %rsp +// CHECK-LP64-NEXT: ret + +// CHECK-LP64: __ZTch0_v16_n32_N8test16_D4foo1Ev: +// CHECK-LP64-NEXT:Leh_func_begin44: +// CHECK-LP64-NEXT: subq $24, %rsp +// CHECK-LP64-NEXT:Llabel44: +// CHECK-LP64-NEXT: movq %rdi, %rax +// CHECK-LP64-NEXT: movq %rax, 8(%rsp) +// CHECK-LP64-NEXT: movq 8(%rsp), %rax +// CHECK-LP64-NEXT: movq %rax, %rdi +// CHECK-LP64-NEXT: call __ZN8test16_D4foo1Ev +// CHECK-LP64-NEXT: movq %rax, %rcx +// CHECK-LP64-NEXT: movabsq $16, %rdx +// CHECK-LP64-NEXT: addq %rdx, %rcx +// CHECK-LP64-NEXT: movq 16(%rax), %rax +// CHECK-LP64-NEXT: movq -32(%rax), %rax +// CHECK-LP64-NEXT: addq %rax, %rcx +// CHECK-LP64-NEXT: movq %rcx, %rax +// CHECK-LP64-NEXT: movq %rax, 16(%rsp) +// CHECK-LP64-NEXT: movq 16(%rsp), %rax +// CHECK-LP64-NEXT: addq $24, %rsp +// CHECK-LP64-NEXT: ret + struct test12_A { virtual void foo0() { } virtual void foo(); @@ -306,10 +350,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP32-NEXT: .long __ZN9test5_B227funcB22Ev // CHECK-LP32-NEXT: .long __ZN9test5_B217funcB21Ev // CHECK-LP32-NEXT: .space 4 -// CHECK-LP32: .long 8 -// CHECK-LP32 .space 4 -// CHECK-LP32 .space 4 FIXME -// CHECK-LP32: .long 4 +// CHECK-LP32-NEXT: .long 8 +// CHECK-LP32-NEXT: .space 4 +// CHECK-LP32-NEXT: .space 4 +// CHECK-LP32-NEXT: .long 4 // CHECK-LP32-NEXT: .space 4 // CHECK-LP32-NEXT: .space 4 // CHECK-LP32-NEXT: .long 4294967288 @@ -358,10 +402,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP64-NEXT: .quad __ZN9test5_B227funcB22Ev // CHECK-LP64-NEXT: .quad __ZN9test5_B217funcB21Ev // CHECK-LP64-NEXT: .space 8 -// CHECK-LP64: .quad 16 -// CHECK-LP64 .space 8 -// CHECK-LP64 .space 8 -// CHECK-LP64: .quad 8 +// CHECK-LP64-NEXT: .quad 16 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad 8 // CHECK-LP64-NEXT: .space 8 // CHECK-LP64-NEXT: .space 8 // CHECK-LP64-NEXT: .quad 18446744073709551600 @@ -1049,6 +1093,151 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LP32-NEXT: .long __ZN10test16_NV28foo_NV2bEv +class test17_B1 { + virtual void foo() = 0; + virtual void bar() { } +}; + +class test17_B2 : public test17_B1 { + void foo() { } + virtual void bar() = 0; +}; + +class test17_D : public test17_B2 { + void bar() { } +}; + + +// CHECK-LP64:__ZTV8test17_D: +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad __ZTI8test17_D +// CHECK-LP64-NEXT: .quad __ZN9test17_B23fooEv +// CHECK-LP64-NEXT: .quad __ZN8test17_D3barEv + +// CHECK-LP64:__ZTV9test17_B2: +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad __ZTI9test17_B2 +// CHECK-LP64-NEXT: .quad __ZN9test17_B23fooEv +// CHECK-LP64-NEXT: .quad ___cxa_pure_virtual + +// CHECK-LP64:__ZTV9test17_B1: +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad __ZTI9test17_B1 +// CHECK-LP64-NEXT: .quad ___cxa_pure_virtual +// CHECK-LP64-NEXT: .quad __ZN9test17_B13barEv + + +struct test18_NV1 { + virtual void fooNV1() { } +virtual void foo_NV1() { } + int i; +}; + +struct test18_NV2 { + virtual test18_NV2& foo1() { return *this; } +virtual void foo_NV2() { } +virtual void foo_NV2b() { } + int i; +}; + +struct test18_B : public test18_NV1, test18_NV2 { + virtual test18_B& foo1() { return *this; } + virtual test18_B *foo2() { return 0; } + virtual test18_B *foo3() { return 0; } +virtual void foo_B() { } + int i; +}; + +struct test18_B2 : test18_NV1, virtual test18_B { + virtual test18_B2& foo1() { return *this; } + virtual test18_B2 *foo2() { return 0; } +virtual void foo_B2() { } + int i; +}; + +struct test18_D : test18_NV1, virtual test18_B2 { + virtual test18_D& foo1() { return *this; } +}; + + +struct test19_VB1 { }; +struct test19_B1 : public virtual test19_VB1 { + virtual void fB1() { } + virtual void foB1B2() { } + virtual void foB1B3() { } + virtual void foB1B4() { } +}; + +struct test19_VB2 { }; +struct test19_B2: public test19_B1, public virtual test19_VB2 { + virtual void foB1B2() { } + virtual void foB1B3() { } + virtual void foB1B4() { } + + virtual void fB2() { } + virtual void foB2B3() { } + virtual void foB2B4() { } +}; + +struct test19_VB3 { }; +struct test19_B3: virtual public test19_B2, public virtual test19_VB3 { + virtual void foB1B3() { } + virtual void foB1B4() { } + + virtual void foB2B3() { } + virtual void foB2B4() { } + + virtual void fB3() { } + virtual void foB3B4() { } +}; + +struct test19_VB4 { }; +struct test19_B4: public test19_B3, public virtual test19_VB4 { + virtual void foB1B4() { } + + virtual void foB2B4() { } + + virtual void foB3B4() { } + + virtual void fB4() { } +}; + +struct test19_D : virtual test19_B4 { +}; + + +// CHECK-LP64: __ZTV8test19_D: +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad __ZTI8test19_D +// CHECK-LP64-NEXT .quad __ZN9test19_B13fB1Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B26foB1B2Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B36foB1B3Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B46foB1B4Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B23fB2Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B36foB2B3Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B46foB2B4Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B33fB3Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B46foB3B4Ev +// CHECK-LP64-NEXT .quad __ZN9test19_B43fB4Ev + + + // CHECK-LP64: __ZTV1B: // CHECK-LP64-NEXT: .space 8 // CHECK-LP64-NEXT: .quad __ZTI1B @@ -1127,6 +1316,9 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev // CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev +test19_D d19; +test18_D d18; +test17_D d17; test16_D d16; test15_D d15; test13_D d13; diff --git a/test/CodeGenObjC/PR4894-recursive-debug-crash.m b/test/CodeGenObjC/PR4894-recursive-debug-crash.m index c5f901c..d737911 100644 --- a/test/CodeGenObjC/PR4894-recursive-debug-crash.m +++ b/test/CodeGenObjC/PR4894-recursive-debug-crash.m @@ -3,7 +3,7 @@ // // This test is actually just making sure we can generate the debug info for the // return type from im0 without crashing. -// XFAIL +// XFAIL: * @interface I0 { I0 *_iv0; diff --git a/test/CodeGenObjC/encode-test-2.m b/test/CodeGenObjC/encode-test-2.m index 6901168..07a5336 100644 --- a/test/CodeGenObjC/encode-test-2.m +++ b/test/CodeGenObjC/encode-test-2.m @@ -3,7 +3,7 @@ // RUN: grep -e "@\\\22<X><Y>\\\22" %t && // RUN: grep -e "@\\\22<X><Y><Z>\\\22" %t && // RUN: grep -e "@\\\22Foo<X><Y><Z>\\\22" %t && -// RUN: grep -e "{Intf=@@@@}" %t +// RUN: grep -e "{Intf=@@@@#}" %t @protocol X, Y, Z; @class Foo; @@ -17,6 +17,7 @@ id <X> IVAR_x; id <X, Y> IVAR_xy; id <X, Y, Z> IVAR_xyz; Foo <X, Y, Z> *IVAR_Fooxyz; +Class <X> IVAR_Classx; } @end diff --git a/test/CodeGenObjC/synthesize_ivar.m b/test/CodeGenObjC/synthesize_ivar.m index 7646f70..e1746f1 100644 --- a/test/CodeGenObjC/synthesize_ivar.m +++ b/test/CodeGenObjC/synthesize_ivar.m @@ -1,8 +1,6 @@ // RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s @interface I -{ -} @property int IP; @end @@ -25,3 +23,16 @@ @implementation OrganizerViolatorView @synthesize bindingInfo; @end + +// <rdar://problem/7336352> [irgen] crash in synthesized property construction + +@interface I0 @end +@protocol P0 @end +@interface I1 { + I0<P0> *iv0; +} +@property (assign, readwrite) id p0; +@end +@implementation I1 +@synthesize p0 = iv0; +@end diff --git a/test/Coverage/objc-language-features.inc b/test/Coverage/objc-language-features.inc index dd57dfb..dbbf205 100644 --- a/test/Coverage/objc-language-features.inc +++ b/test/Coverage/objc-language-features.inc @@ -14,6 +14,7 @@ @interface A : Root <P1> { int iv0; B *iv1; + B<P1> *iv2; } @property(readonly) int p0; @@ -21,11 +22,16 @@ @property(copy) id p2; @property(retain) id p3; @property(assign, getter=getme, setter=setme:) id p4; +@property(assign, readwrite) id p5; @end @implementation A @dynamic p0; @synthesize p1 = iv0; + +// Property type can differ from ivar type. +@synthesize p5 = iv2; + +(void) fm0 { [super fm0]; } diff --git a/test/Coverage/targets.c b/test/Coverage/targets.c index 5a87b4d..c4f030f 100644 --- a/test/Coverage/targets.c +++ b/test/Coverage/targets.c @@ -16,4 +16,8 @@ // RUN: clang-cc -g -triple x86_64-apple-darwin9 -emit-llvm -o %t %s && // RUN: clang-cc -g -triple x86_64-pc-linux-gnu -emit-llvm -o %t %s && // RUN: clang-cc -g -triple x86_64-unknown-unknown -emit-llvm -o %t %s && + +// <rdar://problem/7181838> clang 1.0 fails to compile Python 2.6 +// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -mmacosx-version-min=10.4 && + // RUN: true diff --git a/test/Driver/analyze.c b/test/Driver/analyze.c index 5ca890f..0381068 100644 --- a/test/Driver/analyze.c +++ b/test/Driver/analyze.c @@ -2,8 +2,8 @@ // (at least for a few key ones). // RUN: env MACOSX_DEPLOYMENT_TARGET=10.5 clang -ccc-host-triple i386-apple-darwin9 -### --analyze -o /dev/null %s -msse 2> %t.log && -// RUN: grep '"-analyze"' %t.log && -// RUN: grep '"--fmath-errno=0"' %t.log && -// RUN: grep '"-target-feature" "+sse"' %t.log && -// RUN: grep '"-mmacosx-version-min=10.5"' %t.log +// RUN: FileCheck --input-file=%t.log %s +// CHECK: "-analyze" +// CHECK: "-target-feature" "+sse" +// CHECK: "--fmath-errno=0" diff --git a/test/Driver/ccc-add-args.c b/test/Driver/ccc-add-args.c index b504b0b4..21e4471 100644 --- a/test/Driver/ccc-add-args.c +++ b/test/Driver/ccc-add-args.c @@ -1,3 +1,3 @@ -// RUN: env CCC_ADD_ARGS="-ccc-echo,-ccc-print-options,,-v" clang -### 2> %t && -// RUN: grep -F 'Option 0 - Name: "-v", Values: {}' %t && -// RUN: grep -F 'Option 1 - Name: "-###", Values: {}' %t +// RUN: env CCC_ADD_ARGS="-ccc-echo,-ccc-print-options,,-v" clang -### 2>&1 | FileCheck %s +// CHECK: Option 0 - Name: "-v", Values: {} +// CHECK: Option 1 - Name: "-###", Values: {} diff --git a/test/Driver/hello.c b/test/Driver/hello.c index 7dbe9c7..ead0d07 100644 --- a/test/Driver/hello.c +++ b/test/Driver/hello.c @@ -6,6 +6,10 @@ // RUN: %t > %t.out && // RUN: grep "I'm a little driver, short and stout." %t.out +// FIXME: We don't have a usable assembler on Windows, so we can't build real +// apps yet. +// XFAIL: win32 + #include <stdio.h> int main() { diff --git a/test/Driver/phases.c b/test/Driver/phases.c index 0967d33..61f68c4 100644 --- a/test/Driver/phases.c +++ b/test/Driver/phases.c @@ -1,79 +1,79 @@ // Basic compilation for various types of files. -// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2> %t && -// RUN: grep '0: input, ".*phases.c", c' %t && -// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t && -// RUN: grep -F '2: compiler, {1}, assembler' %t && -// RUN: grep -F '3: assembler, {2}, object' %t && -// RUN: grep '4: input, ".*phases.c", objective-c' %t && -// RUN: grep -F '5: preprocessor, {4}, objective-c-cpp-output' %t && -// RUN: grep -F '6: compiler, {5}, assembler' %t && -// RUN: grep -F '7: assembler, {6}, object' %t && -// RUN: grep '8: input, ".*phases.c", c++' %t && -// RUN: grep -F '9: preprocessor, {8}, c++-cpp-output' %t && -// RUN: grep -F '10: compiler, {9}, assembler' %t && -// RUN: grep -F '11: assembler, {10}, object' %t && -// RUN: grep '12: input, ".*phases.c", assembler' %t && -// RUN: grep -F '13: assembler, {12}, object' %t && -// RUN: grep '14: input, ".*phases.c", assembler-with-cpp' %t && -// RUN: grep -F '15: preprocessor, {14}, assembler' %t && -// RUN: grep -F '16: assembler, {15}, object' %t && -// RUN: grep '17: input, ".*phases.c", c' %t && -// RUN: grep -F '18: preprocessor, {17}, cpp-output' %t && -// RUN: grep -F '19: compiler, {18}, assembler' %t && -// RUN: grep -F '20: assembler, {19}, object' %t && -// RUN: grep -F '21: linker, {3, 7, 11, 13, 16, 20}, image' %t && +// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2>&1 | FileCheck -check-prefix=BASIC %s && +// BASIC: 0: input, "{{.*}}phases.c", c +// BASIC: 1: preprocessor, {0}, cpp-output +// BASIC: 2: compiler, {1}, assembler +// BASIC: 3: assembler, {2}, object +// BASIC: 4: input, "{{.*}}phases.c", objective-c +// BASIC: 5: preprocessor, {4}, objective-c-cpp-output +// BASIC: 6: compiler, {5}, assembler +// BASIC: 7: assembler, {6}, object +// BASIC: 8: input, "{{.*}}phases.c", c++ +// BASIC: 9: preprocessor, {8}, c++-cpp-output +// BASIC: 10: compiler, {9}, assembler +// BASIC: 11: assembler, {10}, object +// BASIC: 12: input, "{{.*}}phases.c", assembler +// BASIC: 13: assembler, {12}, object +// BASIC: 14: input, "{{.*}}phases.c", assembler-with-cpp +// BASIC: 15: preprocessor, {14}, assembler +// BASIC: 16: assembler, {15}, object +// BASIC: 17: input, "{{.*}}phases.c", c +// BASIC: 18: preprocessor, {17}, cpp-output +// BASIC: 19: compiler, {18}, assembler +// BASIC: 20: assembler, {19}, object +// BASIC: 21: linker, {3, 7, 11, 13, 16, 20}, image // Universal linked image. -// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2> %t && -// RUN: grep '0: input, ".*phases.c", c' %t && -// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t && -// RUN: grep -F '2: compiler, {1}, assembler' %t && -// RUN: grep -F '3: assembler, {2}, object' %t && -// RUN: grep -F '4: linker, {3}, image' %t && -// RUN: grep -F '5: bind-arch, "ppc", {4}, image' %t && -// RUN: grep -F '6: bind-arch, "i386", {4}, image' %t && -// RUN: grep -F '7: lipo, {5, 6}, image' %t && +// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=ULI %s && +// ULI: 0: input, "{{.*}}phases.c", c +// ULI: 1: preprocessor, {0}, cpp-output +// ULI: 2: compiler, {1}, assembler +// ULI: 3: assembler, {2}, object +// ULI: 4: linker, {3}, image +// ULI: 5: bind-arch, "ppc", {4}, image +// ULI: 6: bind-arch, "i386", {4}, image +// ULI: 7: lipo, {5, 6}, image // Universal object file. -// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2> %t && -// RUN: grep '0: input, ".*phases.c", c' %t && -// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t && -// RUN: grep -F '2: compiler, {1}, assembler' %t && -// RUN: grep -F '3: assembler, {2}, object' %t && -// RUN: grep -F '4: bind-arch, "ppc", {3}, object' %t && -// RUN: grep -F '5: bind-arch, "i386", {3}, object' %t && -// RUN: grep -F '6: lipo, {4, 5}, object' %t && +// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=UOF %s && +// UOF: 0: input, "{{.*}}phases.c", c +// UOF: 1: preprocessor, {0}, cpp-output +// UOF: 2: compiler, {1}, assembler +// UOF: 3: assembler, {2}, object +// UOF: 4: bind-arch, "ppc", {3}, object +// UOF: 5: bind-arch, "i386", {3}, object +// UOF: 6: lipo, {4, 5}, object // Arch defaulting -// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2> %t && -// RUN: grep -F '2: bind-arch, "i386", {1}, object' %t && -// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s -m32 -m64 2> %t && -// RUN: grep -F '2: bind-arch, "x86_64", {1}, object' %t && -// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s 2> %t && -// RUN: grep -F '2: bind-arch, "x86_64", {1}, object' %t && -// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s -m64 -m32 2> %t && -// RUN: grep -F '2: bind-arch, "i386", {1}, object' %t && +// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH1 %s && +// ARCH1: 2: bind-arch, "i386", {1}, object +// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s -m32 -m64 2>&1 | FileCheck -check-prefix=ARCH2 %s && +// ARCH2: 2: bind-arch, "x86_64", {1}, object +// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH3 %s && +// ARCH3: 2: bind-arch, "x86_64", {1}, object +// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s -m64 -m32 2>&1 | FileCheck -check-prefix=ARCH4 %s && +// ARCH4: 2: bind-arch, "i386", {1}, object // Analyzer -// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases --analyze %s 2> %t && -// RUN: grep '0: input, ".*phases.c", c' %t && -// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t && -// RUN: grep -F '2: analyzer, {1}, plist' %t && +// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases --analyze %s 2>&1 | FileCheck -check-prefix=ANALYZE %s && +// ANALYZE: 0: input, "{{.*}}phases.c", c +// ANALYZE: 1: preprocessor, {0}, cpp-output +// ANALYZE: 2: analyzer, {1}, plist // Precompiler -// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c-header %s 2> %t && -// RUN: grep '0: input, ".*phases.c", c-header' %t && -// RUN: grep -F '1: preprocessor, {0}, c-header-cpp-output' %t && -// RUN: grep -F '2: precompiler, {1}, precompiled-header' %t && +// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c-header %s 2>&1 | FileCheck -check-prefix=PCH %s && +// PCH: 0: input, "{{.*}}phases.c", c-header +// PCH: 1: preprocessor, {0}, c-header-cpp-output +// PCH: 2: precompiler, {1}, precompiled-header // Darwin overrides the handling for .s // RUN: touch %t.s && -// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.s 2> %t && -// RUN: grep '0: input, ".*\.s", assembler' %t && -// RUN: grep -F '1: assembler, {0}, object' %t && -// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c %t.s 2> %t && -// RUN: grep '0: input, ".*\.s", assembler-with-cpp' %t && -// RUN: grep -F '1: preprocessor, {0}, assembler' %t && -// RUN: grep -F '2: assembler, {1}, object' %t && +// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN1 %s && +// DARWIN1: 0: input, "{{.*}}.s", assembler +// DARWIN1: 1: assembler, {0}, object +// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN2 %s && +// DARWIN2: 0: input, "{{.*}}.s", assembler-with-cpp +// DARWIN2: 1: preprocessor, {0}, assembler +// DARWIN2: 2: assembler, {1}, object // RUN: true diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c index 46e150c..6f72078 100644 --- a/test/Driver/qa_override.c +++ b/test/Driver/qa_override.c @@ -1,7 +1,5 @@ -// RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " clang x -O2 b -O3 2> %t && -// RUN: grep '### ' %t | count 0 && -// RUN: grep -F 'Option 0 - Name: "<input>", Values: {"x"}' %t && -// RUN: grep -F 'Option 1 - Name: "-O", Values: {"ignore"}' %t && -// RUN: grep -F 'Option 2 - Name: "-O", Values: {"magic"}' %t && -// RUN: true - +// RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " clang x -O2 b -O3 2>&1 | FileCheck %s +// CHECK-NOT: ### +// CHECK: Option 0 - Name: "<input>", Values: {"x"} +// CHECK-NEXT: Option 1 - Name: "-O", Values: {"ignore"} +// CHECK-NEXT: Option 2 - Name: "-O", Values: {"magic"} diff --git a/test/Driver/std.c b/test/Driver/std.c index ef6d8f1..04113d5 100644 --- a/test/Driver/std.c +++ b/test/Driver/std.c @@ -1,8 +1,8 @@ -// RUN: clang -std=c99 -trigraphs -std=gnu99 %s -E -o %t && -// RUN: grep '??(??)' %t && -// RUN: clang -ansi %s -E -o %t && -// RUN: grep -F '[]' %t && -// RUN: clang -std=gnu99 -trigraphs %s -E -o %t && -// RUN: grep -F '[]' %t +// RUN: clang -std=c99 -trigraphs -std=gnu99 %s -E -o - | FileCheck -check-prefix=OVERRIDE %s && +// OVERRIDE: ??(??) +// RUN: clang -ansi %s -E -o - | FileCheck -check-prefix=ANSI %s && +// ANSI: [] +// RUN: clang -std=gnu99 -trigraphs %s -E -o - | FileCheck -check-prefix=EXPLICIT %s +// EXPLICIT: [] ??(??) diff --git a/test/FixIt/fixit-pmem.cpp b/test/FixIt/fixit-pmem.cpp new file mode 100644 index 0000000..bb36f7f --- /dev/null +++ b/test/FixIt/fixit-pmem.cpp @@ -0,0 +1,23 @@ +// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -fsyntax-only -pedantic -Werror -x c++ - + +/* This is a test of the various code modification hints that are + provided as part of warning or extension diagnostics. All of the + warnings will be fixed by -fixit, and the resulting file should + compile cleanly with -Werror -pedantic. */ + +struct S { + int i; +}; + +int foo(int S::* ps, S s, S* p) +{ + p.*ps = 1; + return s->*ps; +} + +void foo1(int (S::*ps)(), S s, S* p) +{ + (p.*ps)(); + (s->*ps)(); +} + diff --git a/test/Frontend/darwin-version.c b/test/Frontend/darwin-version.c index 513ea19..3217b9a 100644 --- a/test/Frontend/darwin-version.c +++ b/test/Frontend/darwin-version.c @@ -1,23 +1,23 @@ -// RUN: clang-cc -triple armv6-apple-darwin9 -dM -E -o %t - < /dev/null && -// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '10000' | count 1 && +// RUN: clang -ccc-host-triple armv6-apple-darwin9 -dM -E -o %t %s && +// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '30000' | count 1 && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0 && -// RUN: clang-cc -triple armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20000' | count 1 && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0 && -// RUN: clang-cc -triple armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20200' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin8 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin8 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0 && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin9 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin9 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin10 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin10 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0 && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1 && -// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.6 -dM -E -o %t - < /dev/null && +// RUN: clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.6 -dM -E -o %t %s && // RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1 && // RUN: true diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c index 4a1611a..9538699 100644 --- a/test/Frontend/dependency-gen.c +++ b/test/Frontend/dependency-gen.c @@ -1,7 +1,8 @@ // rdar://6533411 -// RUN: clang -MD -MF %t.d -c -x c -o %t.o /dev/null && +// RUN: clang -MD -MF %t.d -c -x c -o %t.o %s && // RUN: grep '.*dependency-gen.*:' %t.d && -// RUN: grep '/dev/null' %t.d && +// RUN: grep 'dependency-gen.c' %t.d && -// RUN: clang -M -x c /dev/null -o %t.deps && -// RUN: grep 'null.o: /dev/null' %t.deps +// RUN: clang -M -x c %s -o %t.d && +// RUN: grep '.*dependency-gen.*:' %t.d && +// RUN: grep 'dependency-gen.c' %t.d diff --git a/test/Lexer/block_cmt_end.c b/test/Lexer/block_cmt_end.c index d85cf81..83d6cf1 100644 --- a/test/Lexer/block_cmt_end.c +++ b/test/Lexer/block_cmt_end.c @@ -17,7 +17,7 @@ next comment ends with normal escaped newline: /* expected-warning {{escaped newline}} expected-warning {{backslash and newline}} *\ / -int bar +int bar /* expected-error {{invalid token after top level declarator}} */ /* xyz @@ -26,7 +26,7 @@ next comment ends with a trigraph escaped newline: */ /* expected-warning {{escaped newline between}} expected-warning {{backslash and newline separated by space}} expected-warning {{trigraph ends block comment}} *??/ / -foo /* expected-error {{invalid token after top level declarator}} */ +foo // rdar://6060752 - We should not get warnings about trigraphs in comments: diff --git a/test/Makefile b/test/Makefile index 8543d43..fdb9d8f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -40,9 +40,10 @@ lit.site.cfg: FORCE -e "s#@LLVM_LIBS_DIR@#$(LibDir)#g" \ -e "s#@CLANG_SOURCE_DIR@#$(PROJ_SRC_DIR)/..#g" \ -e "s#@CLANG_BINARY_DIR@#$(PROJ_OBJ_DIR)/..#g" \ + -e "s#@TARGET_TRIPLE@#$(TARGET_TRIPLE)#g" \ $(PROJ_SRC_DIR)/lit.site.cfg.in > $@ clean:: - @ rm -rf Output/ + @ find . -name Output | xargs rm -fr .PHONY: all report clean diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c index 9f4d66f..4502951 100644 --- a/test/Misc/message-length.c +++ b/test/Misc/message-length.c @@ -29,4 +29,4 @@ void a_very_long_line(int *ip, float *FloatPointer) { // CHECK: FILE:23:78 -// CHECK: {{^ ...// some long comment text and a brace, eh {} $}} +// CHECK: {{^ ...// some long comment text and a brace, eh {} }} diff --git a/test/PCH/pr4489.c b/test/PCH/pr4489.c index 7730819..d05d5cd 100644 --- a/test/PCH/pr4489.c +++ b/test/PCH/pr4489.c @@ -1,5 +1,6 @@ // RUN: clang -x c-header -o %t.pch %s && -// RUN: clang -include %t -x c /dev/null -emit-llvm -S -o - +// RUN: echo > %t.empty.c && +// RUN: clang -include %t -x c %t.empty.c -emit-llvm -S -o - // PR 4489: Crash with PCH // PR 4492: Crash with PCH (round two) // PR 4509: Crash with PCH (round three) @@ -37,4 +38,4 @@ void y1(void) { extern char e; fprintf (0, "asdf"); -}
\ No newline at end of file +} diff --git a/test/Parser/cxx-parse-member-pointer-op.cpp b/test/Parser/cxx-parse-member-pointer-op.cpp new file mode 100644 index 0000000..cc2e8b1 --- /dev/null +++ b/test/Parser/cxx-parse-member-pointer-op.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -fsyntax-only -pedantic -verify %s + +struct C {}; + +typedef void (C::*pmfc)(); + +void g(pmfc) { + C *c; + c->*pmfc(); // expected-error {{invalid use of pointer to member type after '->*'}} + C c1; + c1.*pmfc(); // expected-error {{invalid use of pointer to member type after '.*'}} +} + diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index 9309b72..2b2d3de 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s // Errors export class foo { }; // expected-error {{expected template}} @@ -92,3 +92,7 @@ void f2() { int x; A< typeof(x>1) > a; } + + +// PR3844 +template <> struct S<int> { }; // expected-error{{explicit specialization of non-template struct 'S'}} diff --git a/test/Preprocessor/assembler-with-cpp.c b/test/Preprocessor/assembler-with-cpp.c index f7706ca..4f1c443 100644 --- a/test/Preprocessor/assembler-with-cpp.c +++ b/test/Preprocessor/assembler-with-cpp.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=0 -E %s > %t && +// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=0 -E %s -o - | FileCheck -strict-whitespace -check-prefix=CHECK-Identifiers-False %s && #ifndef __ASSEMBLER__ #error "__ASSEMBLER__ not defined" @@ -6,72 +6,70 @@ // Invalid token pasting is ok. -// RUN: grep '1: X .' %t && #define A X ## . 1: A +// CHECK-Identifiers-False: 1: X . // Line markers are not linemarkers in .S files, they are passed through. -// RUN: grep '# 321' %t && # 321 +// CHECK-Identifiers-False: # 321 // Unknown directives are passed through. -// RUN: grep '# B C' %t && # B C +// CHECK-Identifiers-False: # B C // Unknown directives are expanded. -// RUN: grep '# BAR42' %t && #define D(x) BAR ## x # D(42) +// CHECK-Identifiers-False: # BAR42 // Unmatched quotes are permitted. -// RUN: grep "2: '" %t && -// RUN: grep '3: "' %t && 2: ' 3: " +// CHECK-Identifiers-False: 2: ' +// CHECK-Identifiers-False: 3: " // (balance quotes to keep editors happy): "' // Empty char literals are ok. -// RUN: grep "4: ''" %t && 4: '' +// CHECK-Identifiers-False: 4: '' // Portions of invalid pasting should still expand as macros. // rdar://6709206 -// RUN: grep "5: expanded (" %t && #define M4 expanded #define M5() M4 ## ( 5: M5() +// CHECK-Identifiers-False: 5: expanded ( // rdar://6804322 -// RUN: grep -F "6: blarg $foo" %t && #define FOO(name) name ## $foo 6: FOO(blarg) +// CHECK-Identifiers-False: 6: blarg $foo -// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=1 -E %s > %t && -// RUN: grep -F "7: blarg$foo" %t && +// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=1 -E %s -o - | FileCheck -check-prefix=CHECK-Identifiers-True -strict-whitespace %s && #define FOO(name) name ## $foo 7: FOO(blarg) - +// CHECK-Identifiers-True: 7: blarg$foo // #define T6() T6 #nostring #define T7(x) T7 #x 8: T6() 9: T7(foo) -// RUN: grep '8: T6 #nostring' %t && -// RUN: grep '9: T7 "foo"' %t && +// CHECK-Identifiers-True: 8: T6 #nostring +// CHECK-Identifiers-True: 9: T7 "foo" // Concatenation with period doesn't leave a space -// RUN: grep -F '10: .T8' %t && #define T8(A,B) A ## B 10: T8(.,T8) - +// CHECK-Identifiers-True: 10: .T8 // This should not crash. -// RUN: grep '11: #0' %t && #define T11(a) #0 11: T11(b) +// CHECK-Identifiers-True: 11: #0 // RUN: true diff --git a/test/Preprocessor/c99-6_10_3_3_p4.c b/test/Preprocessor/c99-6_10_3_3_p4.c index 8966054..99ad6e8 100644 --- a/test/Preprocessor/c99-6_10_3_3_p4.c +++ b/test/Preprocessor/c99-6_10_3_3_p4.c @@ -1,6 +1,10 @@ -// RUN: clang-cc -E %s | grep -F 'char p[] = "x ## y";' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s + #define hash_hash # ## # #define mkstr(a) # a #define in_between(a) mkstr(a) #define join(c, d) in_between(c hash_hash d) char p[] = join(x, y); + +// CHECK: char p[] = "x ## y"; + diff --git a/test/Preprocessor/c99-6_10_3_4_p5.c b/test/Preprocessor/c99-6_10_3_4_p5.c index 22bdf82..08b2c42 100644 --- a/test/Preprocessor/c99-6_10_3_4_p5.c +++ b/test/Preprocessor/c99-6_10_3_4_p5.c @@ -1,10 +1,5 @@ // Example from C99 6.10.3.4p5 - -// RUN: clang-cc -E %s | grep -F 'f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);' && -// RUN: clang-cc -E %s | grep -F 'f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);' && -// RUN: clang-cc -E %s | grep -F 'int i[] = { 1, 23, 4, 5, };' && -// RUN: clang-cc -E %s | grep -F 'char c[2][6] = { "hello", "" };' - +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define x 3 #define f(a) f(x * (a)) @@ -26,4 +21,8 @@ p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; char c[2][6] = { str(hello), str() }; +// CHECK: f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +// CHECK: f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); +// CHECK: int i[] = { 1, 23, 4, 5, }; +// CHECK: char c[2][6] = { "hello", "" }; diff --git a/test/Preprocessor/c99-6_10_3_4_p6.c b/test/Preprocessor/c99-6_10_3_4_p6.c index c48d2ef..8072d7b 100644 --- a/test/Preprocessor/c99-6_10_3_4_p6.c +++ b/test/Preprocessor/c99-6_10_3_4_p6.c @@ -1,10 +1,6 @@ // Example from C99 6.10.3.4p6 -// RUN: clang-cc -E %s | grep -F 'printf("x" "1" "= %d, x" "2" "= s" x1, x2);' && -// RUN: clang-cc -E %s | grep 'fputs("strncmp(\\"abc\\\\0d\\" \\"abc\\", .\\\\4.) == 0" ": @\\n", s);' && -// RUN: clang-cc -E %s | grep -F 'include "vers2.h"' && -// RUN: clang-cc -E %s | grep -F '"hello";' && -// RUN: clang-cc -E %s | grep -F '"hello" ", world"' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define str(s) # s #define xstr(s) str(s) @@ -22,3 +18,10 @@ include xstr(INCFILE(2).h) glue(HIGH, LOW); xglue(HIGH, LOW) + +// CHECK: printf("x" "1" "= %d, x" "2" "= s" x1, x2); +// CHECK: fputs("strncmp(\"abc\\0d\" \"abc\", '\\4') == 0" ": @\n", s); +// CHECK: include "vers2.h" +// CHECK: "hello"; +// CHECK: "hello" ", world" + diff --git a/test/Preprocessor/c99-6_10_3_4_p7.c b/test/Preprocessor/c99-6_10_3_4_p7.c index a53df82..6a7eb48 100644 --- a/test/Preprocessor/c99-6_10_3_4_p7.c +++ b/test/Preprocessor/c99-6_10_3_4_p7.c @@ -1,9 +1,10 @@ // Example from C99 6.10.3.4p7 -// RUN: clang-cc -E %s | grep -F 'int j[] = { 123, 45, 67, 89,' && -// RUN: clang-cc -E %s | grep -F '10, 11, 12, };' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define t(x,y,z) x ## y ## z int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) }; +// CHECK: int j[] = { 123, 45, 67, 89, +// CHECK: 10, 11, 12, }; diff --git a/test/Preprocessor/c99-6_10_3_4_p9.c b/test/Preprocessor/c99-6_10_3_4_p9.c index 39c3454..704241e 100644 --- a/test/Preprocessor/c99-6_10_3_4_p9.c +++ b/test/Preprocessor/c99-6_10_3_4_p9.c @@ -1,16 +1,20 @@ // Example from C99 6.10.3.4p9 -// RUN: clang-cc -E %s | grep -F 'fprintf(stderr, "Flag");' && -// RUN: clang-cc -E %s | grep -F 'fprintf(stderr, "X = %d\n", x);' && -// RUN: clang-cc -E %s | grep -F 'puts("The first, second, and third items.");' && -// RUN: clang-cc -E %s | grep -F '((x>y)?puts("x>y"): printf("x is %d but y is %d", x, y));' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define debug(...) fprintf(stderr, __VA_ARGS__) #define showlist(...) puts(#__VA_ARGS__) #define report(test, ...) ((test)?puts(#test):\ printf(__VA_ARGS__)) -debug("Flag"); -debug("X = %d\n", x); -showlist(The first, second, and third items.); -report(x>y, "x is %d but y is %d", x, y); +debug("Flag"); +// CHECK: fprintf(stderr, "Flag"); + +debug("X = %d\n", x); +// CHECK: fprintf(stderr, "X = %d\n", x); + +showlist(The first, second, and third items.); +// CHECK: puts("The first, second, and third items."); + +report(x>y, "x is %d but y is %d", x, y); +// CHECK: ((x>y)?puts("x>y"): printf("x is %d but y is %d", x, y)); diff --git a/test/Preprocessor/comment_save.c b/test/Preprocessor/comment_save.c index 30b0434..ae609b1 100644 --- a/test/Preprocessor/comment_save.c +++ b/test/Preprocessor/comment_save.c @@ -1,7 +1,8 @@ -// RUN: clang-cc -E -C %s | grep '^// foo$' && -// RUN: clang-cc -E -C %s | grep -F '^/* bar */$' +// RUN: clang-cc -E -C %s | FileCheck -strict-whitespace %s // foo -/* bar */ +// CHECK: // foo +/* bar */ +// CHECK: /* bar */ diff --git a/test/Preprocessor/comment_save_macro.c b/test/Preprocessor/comment_save_macro.c index 66b59d1..b9a25ed 100644 --- a/test/Preprocessor/comment_save_macro.c +++ b/test/Preprocessor/comment_save_macro.c @@ -1,6 +1,11 @@ -// RUN: clang-cc -E -C %s | grep '^boo bork bar // zot$' && -// RUN: clang-cc -E -CC %s | grep -F '^boo bork /* blah*/ bar // zot$' && -// RUN: clang-cc -E %s | grep '^boo bork bar$' +// RUN: clang-cc -E -C %s | FileCheck -check-prefix=CHECK-C -strict-whitespace %s && +// CHECK-C: boo bork bar // zot + +// RUN: clang-cc -E -CC %s | FileCheck -check-prefix=CHECK-CC -strict-whitespace %s && +// CHECK-CC: boo bork /* blah*/ bar // zot + +// RUN: clang-cc -E %s | FileCheck -check-prefix=CHECK -strict-whitespace %s +// CHECK: boo bork bar #define FOO bork // blah diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c new file mode 100644 index 0000000..40697c0 --- /dev/null +++ b/test/Preprocessor/has_include.c @@ -0,0 +1,83 @@ +// RUN: clang-cc -Eonly -verify %s + +// Try different path permutations of __has_include with existing file. +#if __has_include("stdio.h") +#else + #error "__has_include failed (1)." +#endif + +#if __has_include(<stdio.h>) +#else + #error "__has_include failed (2)." +#endif + +// Try unary expression. +#if !__has_include("stdio.h") + #error "__has_include failed (5)." +#endif + +// Try binary expression. +#if __has_include("stdio.h") && __has_include("stddef.h") +#else + #error "__has_include failed (6)." +#endif + +// Try non-existing file. +#if __has_include("blahblah.h") + #error "__has_include failed (7)." +#endif + +// Try defined. +#if !defined(__has_include) + #error "defined(__has_include) failed (8)." +#endif + +// Try different path permutations of __has_include_next with existing file. +#if __has_include_next("stddef.h") // expected-warning {{#include_next in primary source file}} +#else + #error "__has_include failed (1)." +#endif + +#if __has_include_next(<stddef.h>) // expected-warning {{#include_next in primary source file}} +#else + #error "__has_include failed (2)." +#endif + +// Try unary expression. +#if !__has_include_next("stdio.h") // expected-warning {{#include_next in primary source file}} + #error "__has_include_next failed (5)." +#endif + +// Try binary expression. +#if __has_include_next("stdio.h") && __has_include("stddef.h") // expected-warning {{#include_next in primary source file}} +#else + #error "__has_include_next failed (6)." +#endif + +// Try non-existing file. +#if __has_include_next("blahblah.h") // expected-warning {{#include_next in primary source file}} + #error "__has_include_next failed (7)." +#endif + +// Try defined. +#if !defined(__has_include_next) + #error "defined(__has_include_next) failed (8)." +#endif + +// Try badly formed expressions. +// FIXME: I don't quite know how to avoid preprocessor side effects. +// Use FileCheck? +// It also assert due to unterminated #if's. +//#if __has_include("stdio.h" +//#if __has_include "stdio.h") +//#if __has_include(stdio.h) +//#if __has_include() +//#if __has_include( +//#if __has_include) +//#if __has_include +//#if __has_include(<stdio.h> +//#if __has_include<stdio.h>) +//#if __has_include("stdio.h) +//#if __has_include(stdio.h") +//#if __has_include(<stdio.h) +//#if __has_include(stdio.h>) diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c new file mode 100644 index 0000000..800b750 --- /dev/null +++ b/test/Preprocessor/init.c @@ -0,0 +1,945 @@ +// RUN: clang-cc -E -dM -x=assembler-with-cpp < /dev/null | FileCheck -check-prefix ASM %s && +// +// ASM:#define __ASSEMBLER__ 1 +// +// +// RUN: clang-cc -fblocks -E -dM < /dev/null | FileCheck -check-prefix BLOCKS %s && +// +// BLOCKS:#define __BLOCKS__ 1 +// BLOCKS:#define __block __attribute__((__blocks__(byref))) +// +// +// RUN: clang-cc -x=c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s && +// +// CXX0X:#define _GNU_SOURCE 1 +// CXX0X:#define __DEPRECATED 1 +// CXX0X:#define __GNUG__ +// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1 +// CXX0X:#define __GXX_WEAK__ 1 +// CXX0X:#define __cplusplus 199711L +// CXX0X:#define __private_extern__ extern +// +// +// RUN: clang-cc -x=c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s && +// +// CXX98:#define _GNU_SOURCE 1 +// CXX98:#define __DEPRECATED 1 +// CXX98:#define __GNUG__ +// CXX98:#define __GXX_WEAK__ 1 +// CXX98:#define __cplusplus 199711L +// CXX98:#define __private_extern__ extern +// +// +// RUN: clang-cc -std=c99 -E -dM < /dev/null | FileCheck -check-prefix C99 %s && +// +// C99:#define __STDC_VERSION__ 199901L +// C99:#define __STRICT_ANSI__ 1 +// +// +// RUN: clang-cc -E -dM -fms-extensions=0 < /dev/null | FileCheck -check-prefix COMMON %s && +// +// COMMON:#define __CONSTANT_CFSTRINGS__ 1 +// COMMON:#define __FINITE_MATH_ONLY__ 0 +// COMMON:#define __GNUC_MINOR__ +// COMMON:#define __GNUC_PATCHLEVEL__ +// COMMON:#define __GNUC_STDC_INLINE__ 1 +// COMMON:#define __GNUC__ +// COMMON:#define __GXX_ABI_VERSION +// COMMON:#define __STDC_HOSTED__ 1 +// COMMON:#define __STDC_VERSION__ +// COMMON:#define __STDC__ 1 +// COMMON:#define __VERSION__ +// COMMON:#define __clang__ 1 +// COMMON:#define __llvm__ 1 +// +// +// RUN: clang-cc -ffreestanding -E -dM < /dev/null | FileCheck -check-prefix FREESTANDING %s && +// FREESTANDING:#define __STDC_HOSTED__ 0 +// +// RUN: clang-cc -x=c++ -std=gnu++98 -E -dM < /dev/null | FileCheck -check-prefix GXX98 %s && +// +// GXX98:#define _GNU_SOURCE 1 +// GXX98:#define __DEPRECATED 1 +// GXX98:#define __GNUG__ +// GXX98:#define __GXX_WEAK__ 1 +// GXX98:#define __cplusplus 1 +// GXX98:#define __private_extern__ extern +// +// +// RUN: clang-cc -std=iso9899:199409 -E -dM < /dev/null | FileCheck -check-prefix C94 %s && +// +// C94:#define __STDC_VERSION__ 199409L +// +// +// RUN: clang-cc -fms-extensions -E -dM < /dev/null | FileCheck -check-prefix MSEXT %s && +// +// MSEXT-NOT:#define __STDC__ +// MSEXT:#define __int16 __INT16_TYPE__ +// MSEXT:#define __int32 __INT32_TYPE__ +// MSEXT:#define __int64 __INT64_TYPE__ +// MSEXT:#define __int8 __INT8_TYPE__ +// +// +// RUN: clang-cc -x=objective-c -E -dM < /dev/null | FileCheck -check-prefix OBJC %s && +// +// OBJC:#define OBJC_NEW_PROPERTIES 1 +// OBJC:#define __OBJC__ 1 +// +// +// RUN: clang-cc -x=objective-c -fobjc-gc -E -dM < /dev/null | FileCheck -check-prefix OBJCGC %s && +// +// OBJCGC:#define __OBJC_GC__ 1 +// +// +// RUN: clang-cc -x=objective-c -fnext-runtime -E -dM < /dev/null | FileCheck -check-prefix NEXTRT %s && +// +// NEXTRT:#define __NEXT_RUNTIME__ 1 +// +// +// RUN: clang-cc -x=objective-c -fobjc-nonfragile-abi -E -dM < /dev/null | FileCheck -check-prefix NONFRAGILE %s && +// +// NONFRAGILE:#define OBJC_ZEROCOST_EXCEPTIONS 1 +// NONFRAGILE:#define __OBJC2__ 1 +// +// +// RUN: clang-cc -O1 -E -dM < /dev/null | FileCheck -check-prefix O1 %s && +// +// O1:#define __OPTIMIZE__ 1 +// +// +// RUN: clang-cc -fpascal-strings -E -dM < /dev/null | FileCheck -check-prefix PASCAL %s && +// +// PASCAL:#define __PASCAL_STRINGS__ 1 +// +// +// RUN: clang-cc -fsigned-char -E -dM -fms-extensions=0 < /dev/null | FileCheck -check-prefix SCHAR %s && +// +// SCHAR:#define __STDC__ 1 +// SCHAR-NOT:#define __UNSIGNED_CHAR__ +// SCHAR:#define __clang__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=arm-none-none < /dev/null | FileCheck -check-prefix ARM %s && +// +// ARM:#define __APCS_32__ 1 +// ARM:#define __ARMEL__ 1 +// ARM:#define __ARM_ARCH_6K__ 1 +// ARM:#define __CHAR_BIT__ 8 +// ARM:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// ARM:#define __DBL_DIG__ 15 +// ARM:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// ARM:#define __DBL_HAS_DENORM__ 1 +// ARM:#define __DBL_HAS_INFINITY__ 1 +// ARM:#define __DBL_HAS_QUIET_NAN__ 1 +// ARM:#define __DBL_MANT_DIG__ 53 +// ARM:#define __DBL_MAX_10_EXP__ 308 +// ARM:#define __DBL_MAX_EXP__ 1024 +// ARM:#define __DBL_MAX__ 1.7976931348623157e+308 +// ARM:#define __DBL_MIN_10_EXP__ (-307) +// ARM:#define __DBL_MIN_EXP__ (-1021) +// ARM:#define __DBL_MIN__ 2.2250738585072014e-308 +// ARM:#define __DECIMAL_DIG__ 17 +// ARM:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// ARM:#define __FLT_DIG__ 6 +// ARM:#define __FLT_EPSILON__ 1.19209290e-7F +// ARM:#define __FLT_EVAL_METHOD__ 0 +// ARM:#define __FLT_HAS_DENORM__ 1 +// ARM:#define __FLT_HAS_INFINITY__ 1 +// ARM:#define __FLT_HAS_QUIET_NAN__ 1 +// ARM:#define __FLT_MANT_DIG__ 24 +// ARM:#define __FLT_MAX_10_EXP__ 38 +// ARM:#define __FLT_MAX_EXP__ 128 +// ARM:#define __FLT_MAX__ 3.40282347e+38F +// ARM:#define __FLT_MIN_10_EXP__ (-37) +// ARM:#define __FLT_MIN_EXP__ (-125) +// ARM:#define __FLT_MIN__ 1.17549435e-38F +// ARM:#define __FLT_RADIX__ 2 +// ARM:#define __INT16_TYPE__ short +// ARM:#define __INT32_TYPE__ int +// ARM:#define __INT64_TYPE__ long long int +// ARM:#define __INT8_TYPE__ char +// ARM:#define __INTMAX_MAX__ 9223372036854775807LL +// ARM:#define __INTMAX_TYPE__ long long int +// ARM:#define __INTPTR_TYPE__ long int +// ARM:#define __INT_MAX__ 2147483647 +// ARM:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// ARM:#define __LDBL_DIG__ 15 +// ARM:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// ARM:#define __LDBL_HAS_DENORM__ 1 +// ARM:#define __LDBL_HAS_INFINITY__ 1 +// ARM:#define __LDBL_HAS_QUIET_NAN__ 1 +// ARM:#define __LDBL_MANT_DIG__ 53 +// ARM:#define __LDBL_MAX_10_EXP__ 308 +// ARM:#define __LDBL_MAX_EXP__ 1024 +// ARM:#define __LDBL_MAX__ 1.7976931348623157e+308 +// ARM:#define __LDBL_MIN_10_EXP__ (-307) +// ARM:#define __LDBL_MIN_EXP__ (-1021) +// ARM:#define __LDBL_MIN__ 2.2250738585072014e-308 +// ARM:#define __LITTLE_ENDIAN__ 1 +// ARM:#define __LONG_LONG_MAX__ 9223372036854775807LL +// ARM:#define __LONG_MAX__ 2147483647L +// ARM:#define __NO_INLINE__ 1 +// ARM:#define __POINTER_WIDTH__ 32 +// ARM:#define __PTRDIFF_TYPE__ int +// ARM:#define __SCHAR_MAX__ 127 +// ARM:#define __SHRT_MAX__ 32767 +// ARM:#define __SIZE_TYPE__ unsigned int +// ARM:#define __THUMB_INTERWORK__ 1 +// ARM:#define __UINTMAX_TYPE__ long long unsigned int +// ARM:#define __USER_LABEL_PREFIX__ _ +// ARM:#define __VFP_FP__ 1 +// ARM:#define __WCHAR_MAX__ 2147483647 +// ARM:#define __WCHAR_TYPE__ int +// ARM:#define __WINT_TYPE__ int +// ARM:#define __arm 1 +// ARM:#define __arm__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=bfin-none-none < /dev/null | FileCheck -check-prefix BFIN %s && +// +// BFIN:#define BFIN 1 +// BFIN:#define __ADSPBLACKFIN__ 1 +// BFIN:#define __ADSPLPBLACKFIN__ 1 +// BFIN:#define __BFIN 1 +// BFIN:#define __BFIN__ 1 +// BFIN:#define __CHAR_BIT__ 8 +// BFIN:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// BFIN:#define __DBL_DIG__ 15 +// BFIN:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// BFIN:#define __DBL_HAS_DENORM__ 1 +// BFIN:#define __DBL_HAS_INFINITY__ 1 +// BFIN:#define __DBL_HAS_QUIET_NAN__ 1 +// BFIN:#define __DBL_MANT_DIG__ 53 +// BFIN:#define __DBL_MAX_10_EXP__ 308 +// BFIN:#define __DBL_MAX_EXP__ 1024 +// BFIN:#define __DBL_MAX__ 1.7976931348623157e+308 +// BFIN:#define __DBL_MIN_10_EXP__ (-307) +// BFIN:#define __DBL_MIN_EXP__ (-1021) +// BFIN:#define __DBL_MIN__ 2.2250738585072014e-308 +// BFIN:#define __DECIMAL_DIG__ 17 +// BFIN:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// BFIN:#define __FLT_DIG__ 6 +// BFIN:#define __FLT_EPSILON__ 1.19209290e-7F +// BFIN:#define __FLT_EVAL_METHOD__ 0 +// BFIN:#define __FLT_HAS_DENORM__ 1 +// BFIN:#define __FLT_HAS_INFINITY__ 1 +// BFIN:#define __FLT_HAS_QUIET_NAN__ 1 +// BFIN:#define __FLT_MANT_DIG__ 24 +// BFIN:#define __FLT_MAX_10_EXP__ 38 +// BFIN:#define __FLT_MAX_EXP__ 128 +// BFIN:#define __FLT_MAX__ 3.40282347e+38F +// BFIN:#define __FLT_MIN_10_EXP__ (-37) +// BFIN:#define __FLT_MIN_EXP__ (-125) +// BFIN:#define __FLT_MIN__ 1.17549435e-38F +// BFIN:#define __FLT_RADIX__ 2 +// BFIN:#define __INT16_TYPE__ short +// BFIN:#define __INT32_TYPE__ int +// BFIN:#define __INT64_TYPE__ long long int +// BFIN:#define __INT8_TYPE__ char +// BFIN:#define __INTMAX_MAX__ 9223372036854775807LL +// BFIN:#define __INTMAX_TYPE__ long long int +// BFIN:#define __INTPTR_TYPE__ long int +// BFIN:#define __INT_MAX__ 2147483647 +// BFIN:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// BFIN:#define __LDBL_DIG__ 15 +// BFIN:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// BFIN:#define __LDBL_HAS_DENORM__ 1 +// BFIN:#define __LDBL_HAS_INFINITY__ 1 +// BFIN:#define __LDBL_HAS_QUIET_NAN__ 1 +// BFIN:#define __LDBL_MANT_DIG__ 53 +// BFIN:#define __LDBL_MAX_10_EXP__ 308 +// BFIN:#define __LDBL_MAX_EXP__ 1024 +// BFIN:#define __LDBL_MAX__ 1.7976931348623157e+308 +// BFIN:#define __LDBL_MIN_10_EXP__ (-307) +// BFIN:#define __LDBL_MIN_EXP__ (-1021) +// BFIN:#define __LDBL_MIN__ 2.2250738585072014e-308 +// BFIN:#define __LONG_LONG_MAX__ 9223372036854775807LL +// BFIN:#define __LONG_MAX__ 2147483647L +// BFIN:#define __NO_INLINE__ 1 +// BFIN:#define __POINTER_WIDTH__ 32 +// BFIN:#define __PTRDIFF_TYPE__ long int +// BFIN:#define __SCHAR_MAX__ 127 +// BFIN:#define __SHRT_MAX__ 32767 +// BFIN:#define __SIZE_TYPE__ long unsigned int +// BFIN:#define __UINTMAX_TYPE__ long long unsigned int +// BFIN:#define __USER_LABEL_PREFIX__ _ +// BFIN:#define __WCHAR_MAX__ 2147483647 +// BFIN:#define __WCHAR_TYPE__ int +// BFIN:#define __WINT_TYPE__ int +// BFIN:#define __bfin 1 +// BFIN:#define __bfin__ 1 +// BFIN:#define bfin 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=i386-none-none < /dev/null | FileCheck -check-prefix I386 %s && +// +// I386:#define __CHAR_BIT__ 8 +// I386:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// I386:#define __DBL_DIG__ 15 +// I386:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// I386:#define __DBL_HAS_DENORM__ 1 +// I386:#define __DBL_HAS_INFINITY__ 1 +// I386:#define __DBL_HAS_QUIET_NAN__ 1 +// I386:#define __DBL_MANT_DIG__ 53 +// I386:#define __DBL_MAX_10_EXP__ 308 +// I386:#define __DBL_MAX_EXP__ 1024 +// I386:#define __DBL_MAX__ 1.7976931348623157e+308 +// I386:#define __DBL_MIN_10_EXP__ (-307) +// I386:#define __DBL_MIN_EXP__ (-1021) +// I386:#define __DBL_MIN__ 2.2250738585072014e-308 +// I386:#define __DECIMAL_DIG__ 21 +// I386:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// I386:#define __FLT_DIG__ 6 +// I386:#define __FLT_EPSILON__ 1.19209290e-7F +// I386:#define __FLT_EVAL_METHOD__ 0 +// I386:#define __FLT_HAS_DENORM__ 1 +// I386:#define __FLT_HAS_INFINITY__ 1 +// I386:#define __FLT_HAS_QUIET_NAN__ 1 +// I386:#define __FLT_MANT_DIG__ 24 +// I386:#define __FLT_MAX_10_EXP__ 38 +// I386:#define __FLT_MAX_EXP__ 128 +// I386:#define __FLT_MAX__ 3.40282347e+38F +// I386:#define __FLT_MIN_10_EXP__ (-37) +// I386:#define __FLT_MIN_EXP__ (-125) +// I386:#define __FLT_MIN__ 1.17549435e-38F +// I386:#define __FLT_RADIX__ 2 +// I386:#define __INT16_TYPE__ short +// I386:#define __INT32_TYPE__ int +// I386:#define __INT64_TYPE__ long long int +// I386:#define __INT8_TYPE__ char +// I386:#define __INTMAX_MAX__ 9223372036854775807LL +// I386:#define __INTMAX_TYPE__ long long int +// I386:#define __INTPTR_TYPE__ int +// I386:#define __INT_MAX__ 2147483647 +// I386:#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +// I386:#define __LDBL_DIG__ 18 +// I386:#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +// I386:#define __LDBL_HAS_DENORM__ 1 +// I386:#define __LDBL_HAS_INFINITY__ 1 +// I386:#define __LDBL_HAS_QUIET_NAN__ 1 +// I386:#define __LDBL_MANT_DIG__ 64 +// I386:#define __LDBL_MAX_10_EXP__ 4932 +// I386:#define __LDBL_MAX_EXP__ 16384 +// I386:#define __LDBL_MAX__ 1.18973149535723176502e+4932L +// I386:#define __LDBL_MIN_10_EXP__ (-4931) +// I386:#define __LDBL_MIN_EXP__ (-16381) +// I386:#define __LDBL_MIN__ 3.36210314311209350626e-4932L +// I386:#define __LITTLE_ENDIAN__ 1 +// I386:#define __LONG_LONG_MAX__ 9223372036854775807LL +// I386:#define __LONG_MAX__ 2147483647L +// I386:#define __NO_INLINE__ 1 +// I386:#define __NO_MATH_INLINES 1 +// I386:#define __POINTER_WIDTH__ 32 +// I386:#define __PTRDIFF_TYPE__ int +// I386:#define __REGISTER_PREFIX__ +// I386:#define __SCHAR_MAX__ 127 +// I386:#define __SHRT_MAX__ 32767 +// I386:#define __SIZE_TYPE__ unsigned int +// I386:#define __UINTMAX_TYPE__ long long unsigned int +// I386:#define __USER_LABEL_PREFIX__ _ +// I386:#define __WCHAR_MAX__ 2147483647 +// I386:#define __WCHAR_TYPE__ int +// I386:#define __WINT_TYPE__ int +// I386:#define __i386 1 +// I386:#define __i386__ 1 +// I386:#define __nocona 1 +// I386:#define __nocona__ 1 +// I386:#define __tune_nocona__ 1 +// I386:#define i386 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -check-prefix MSP430 %s && +// +// MSP430:#define MSP430 1 +// MSP430:#define __CHAR_BIT__ 8 +// MSP430:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// MSP430:#define __DBL_DIG__ 15 +// MSP430:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// MSP430:#define __DBL_HAS_DENORM__ 1 +// MSP430:#define __DBL_HAS_INFINITY__ 1 +// MSP430:#define __DBL_HAS_QUIET_NAN__ 1 +// MSP430:#define __DBL_MANT_DIG__ 53 +// MSP430:#define __DBL_MAX_10_EXP__ 308 +// MSP430:#define __DBL_MAX_EXP__ 1024 +// MSP430:#define __DBL_MAX__ 1.7976931348623157e+308 +// MSP430:#define __DBL_MIN_10_EXP__ (-307) +// MSP430:#define __DBL_MIN_EXP__ (-1021) +// MSP430:#define __DBL_MIN__ 2.2250738585072014e-308 +// MSP430:#define __DECIMAL_DIG__ 17 +// MSP430:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// MSP430:#define __FLT_DIG__ 6 +// MSP430:#define __FLT_EPSILON__ 1.19209290e-7F +// MSP430:#define __FLT_EVAL_METHOD__ 0 +// MSP430:#define __FLT_HAS_DENORM__ 1 +// MSP430:#define __FLT_HAS_INFINITY__ 1 +// MSP430:#define __FLT_HAS_QUIET_NAN__ 1 +// MSP430:#define __FLT_MANT_DIG__ 24 +// MSP430:#define __FLT_MAX_10_EXP__ 38 +// MSP430:#define __FLT_MAX_EXP__ 128 +// MSP430:#define __FLT_MAX__ 3.40282347e+38F +// MSP430:#define __FLT_MIN_10_EXP__ (-37) +// MSP430:#define __FLT_MIN_EXP__ (-125) +// MSP430:#define __FLT_MIN__ 1.17549435e-38F +// MSP430:#define __FLT_RADIX__ 2 +// MSP430:#define __INT16_TYPE__ short +// MSP430:#define __INT32_TYPE__ long long +// MSP430:#define __INT8_TYPE__ char +// MSP430:#define __INTMAX_MAX__ 2147483647L +// MSP430:#define __INTMAX_TYPE__ long int +// MSP430:#define __INTPTR_TYPE__ short +// MSP430:#define __INT_MAX__ 32767 +// MSP430:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// MSP430:#define __LDBL_DIG__ 15 +// MSP430:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// MSP430:#define __LDBL_HAS_DENORM__ 1 +// MSP430:#define __LDBL_HAS_INFINITY__ 1 +// MSP430:#define __LDBL_HAS_QUIET_NAN__ 1 +// MSP430:#define __LDBL_MANT_DIG__ 53 +// MSP430:#define __LDBL_MAX_10_EXP__ 308 +// MSP430:#define __LDBL_MAX_EXP__ 1024 +// MSP430:#define __LDBL_MAX__ 1.7976931348623157e+308 +// MSP430:#define __LDBL_MIN_10_EXP__ (-307) +// MSP430:#define __LDBL_MIN_EXP__ (-1021) +// MSP430:#define __LDBL_MIN__ 2.2250738585072014e-308 +// MSP430:#define __LONG_LONG_MAX__ 2147483647LL +// MSP430:#define __LONG_MAX__ 2147483647L +// MSP430:#define __MSP430__ 1 +// MSP430:#define __NO_INLINE__ 1 +// MSP430:#define __POINTER_WIDTH__ 16 +// MSP430:#define __PTRDIFF_TYPE__ int +// MSP430:#define __SCHAR_MAX__ 127 +// MSP430:#define __SHRT_MAX__ 32767 +// MSP430:#define __SIZE_TYPE__ unsigned int +// MSP430:#define __UINTMAX_TYPE__ long unsigned int +// MSP430:#define __USER_LABEL_PREFIX__ _ +// MSP430:#define __WCHAR_MAX__ 2147483647 +// MSP430:#define __WCHAR_TYPE__ int +// MSP430:#define __WINT_TYPE__ int +// MSP430:#define __clang__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=pic16-none-none < /dev/null | FileCheck -check-prefix PIC16 %s && +// +// PIC16:#define _CONFIG(conf) asm("CONFIG "#conf) +// PIC16:#define __CHAR_BIT__ 8 +// PIC16:#define __DBL_DENORM_MIN__ 1.40129846e-45F +// PIC16:#define __DBL_DIG__ 6 +// PIC16:#define __DBL_EPSILON__ 1.19209290e-7F +// PIC16:#define __DBL_HAS_DENORM__ 1 +// PIC16:#define __DBL_HAS_INFINITY__ 1 +// PIC16:#define __DBL_HAS_QUIET_NAN__ 1 +// PIC16:#define __DBL_MANT_DIG__ 24 +// PIC16:#define __DBL_MAX_10_EXP__ 38 +// PIC16:#define __DBL_MAX_EXP__ 128 +// PIC16:#define __DBL_MAX__ 3.40282347e+38F +// PIC16:#define __DBL_MIN_10_EXP__ (-37) +// PIC16:#define __DBL_MIN_EXP__ (-125) +// PIC16:#define __DBL_MIN__ 1.17549435e-38F +// PIC16:#define __DECIMAL_DIG__ -1 +// PIC16:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// PIC16:#define __FLT_DIG__ 6 +// PIC16:#define __FLT_EPSILON__ 1.19209290e-7F +// PIC16:#define __FLT_EVAL_METHOD__ 0 +// PIC16:#define __FLT_HAS_DENORM__ 1 +// PIC16:#define __FLT_HAS_INFINITY__ 1 +// PIC16:#define __FLT_HAS_QUIET_NAN__ 1 +// PIC16:#define __FLT_MANT_DIG__ 24 +// PIC16:#define __FLT_MAX_10_EXP__ 38 +// PIC16:#define __FLT_MAX_EXP__ 128 +// PIC16:#define __FLT_MAX__ 3.40282347e+38F +// PIC16:#define __FLT_MIN_10_EXP__ (-37) +// PIC16:#define __FLT_MIN_EXP__ (-125) +// PIC16:#define __FLT_MIN__ 1.17549435e-38F +// PIC16:#define __FLT_RADIX__ 2 +// PIC16:#define __INT16_TYPE__ short +// PIC16:#define __INT32_TYPE__ long long +// PIC16:#define __INT8_TYPE__ char +// PIC16:#define __INTMAX_MAX__ 2147483647L +// PIC16:#define __INTMAX_TYPE__ long int +// PIC16:#define __INTPTR_TYPE__ short +// PIC16:#define __INT_MAX__ 32767 +// PIC16:#define __LDBL_DENORM_MIN__ 1.40129846e-45F +// PIC16:#define __LDBL_DIG__ 6 +// PIC16:#define __LDBL_EPSILON__ 1.19209290e-7F +// PIC16:#define __LDBL_HAS_DENORM__ 1 +// PIC16:#define __LDBL_HAS_INFINITY__ 1 +// PIC16:#define __LDBL_HAS_QUIET_NAN__ 1 +// PIC16:#define __LDBL_MANT_DIG__ 24 +// PIC16:#define __LDBL_MAX_10_EXP__ 38 +// PIC16:#define __LDBL_MAX_EXP__ 128 +// PIC16:#define __LDBL_MAX__ 3.40282347e+38F +// PIC16:#define __LDBL_MIN_10_EXP__ (-37) +// PIC16:#define __LDBL_MIN_EXP__ (-125) +// PIC16:#define __LDBL_MIN__ 1.17549435e-38F +// PIC16:#define __LONG_LONG_MAX__ 2147483647LL +// PIC16:#define __LONG_MAX__ 2147483647L +// PIC16:#define __NO_INLINE__ 1 +// PIC16:#define __POINTER_WIDTH__ 16 +// PIC16:#define __PTRDIFF_TYPE__ int +// PIC16:#define __SCHAR_MAX__ 127 +// PIC16:#define __SHRT_MAX__ 32767 +// PIC16:#define __SIZE_TYPE__ unsigned int +// PIC16:#define __UINTMAX_TYPE__ long unsigned int +// PIC16:#define __USER_LABEL_PREFIX__ _ +// PIC16:#define __WCHAR_MAX__ 2147483647 +// PIC16:#define __WCHAR_TYPE__ int +// PIC16:#define __WINT_TYPE__ int +// PIC16:#define __clang__ 1 +// PIC16:#define __llvm__ 1 +// PIC16:#define __pic16 1 +// PIC16:#define _address(Addr) __attribute__((section("Address="#Addr))) +// PIC16:#define _interrupt __attribute__((section("interrupt=0x4"))) __attribute__((used)) +// PIC16:#define _section(SectName) __attribute__((section(SectName))) +// PIC16:#define ram __attribute__((address_space(0))) +// PIC16:#define rom __attribute__((address_space(1))) +// +// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc64-none-none < /dev/null | FileCheck -check-prefix PPC64 %s && +// +// PPC64:#define _ARCH_PPC 1 +// PPC64:#define _ARCH_PPC64 1 +// PPC64:#define _BIG_ENDIAN 1 +// PPC64:#define _LP64 1 +// PPC64:#define __BIG_ENDIAN__ 1 +// PPC64:#define __CHAR_BIT__ 8 +// PPC64:#define __CHAR_UNSIGNED__ 1 +// PPC64:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// PPC64:#define __DBL_DIG__ 15 +// PPC64:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// PPC64:#define __DBL_HAS_DENORM__ 1 +// PPC64:#define __DBL_HAS_INFINITY__ 1 +// PPC64:#define __DBL_HAS_QUIET_NAN__ 1 +// PPC64:#define __DBL_MANT_DIG__ 53 +// PPC64:#define __DBL_MAX_10_EXP__ 308 +// PPC64:#define __DBL_MAX_EXP__ 1024 +// PPC64:#define __DBL_MAX__ 1.7976931348623157e+308 +// PPC64:#define __DBL_MIN_10_EXP__ (-307) +// PPC64:#define __DBL_MIN_EXP__ (-1021) +// PPC64:#define __DBL_MIN__ 2.2250738585072014e-308 +// PPC64:#define __DECIMAL_DIG__ 17 +// PPC64:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// PPC64:#define __FLT_DIG__ 6 +// PPC64:#define __FLT_EPSILON__ 1.19209290e-7F +// PPC64:#define __FLT_EVAL_METHOD__ 0 +// PPC64:#define __FLT_HAS_DENORM__ 1 +// PPC64:#define __FLT_HAS_INFINITY__ 1 +// PPC64:#define __FLT_HAS_QUIET_NAN__ 1 +// PPC64:#define __FLT_MANT_DIG__ 24 +// PPC64:#define __FLT_MAX_10_EXP__ 38 +// PPC64:#define __FLT_MAX_EXP__ 128 +// PPC64:#define __FLT_MAX__ 3.40282347e+38F +// PPC64:#define __FLT_MIN_10_EXP__ (-37) +// PPC64:#define __FLT_MIN_EXP__ (-125) +// PPC64:#define __FLT_MIN__ 1.17549435e-38F +// PPC64:#define __FLT_RADIX__ 2 +// PPC64:#define __INT16_TYPE__ short +// PPC64:#define __INT32_TYPE__ int +// PPC64:#define __INT64_TYPE__ long int +// PPC64:#define __INT8_TYPE__ char +// PPC64:#define __INTMAX_MAX__ 9223372036854775807L +// PPC64:#define __INTMAX_TYPE__ long int +// PPC64:#define __INTPTR_TYPE__ long int +// PPC64:#define __INT_MAX__ 2147483647 +// PPC64:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// PPC64:#define __LDBL_DIG__ 15 +// PPC64:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// PPC64:#define __LDBL_HAS_DENORM__ 1 +// PPC64:#define __LDBL_HAS_INFINITY__ 1 +// PPC64:#define __LDBL_HAS_QUIET_NAN__ 1 +// PPC64:#define __LDBL_MANT_DIG__ 53 +// PPC64:#define __LDBL_MAX_10_EXP__ 308 +// PPC64:#define __LDBL_MAX_EXP__ 1024 +// PPC64:#define __LDBL_MAX__ 1.7976931348623157e+308 +// PPC64:#define __LDBL_MIN_10_EXP__ (-307) +// PPC64:#define __LDBL_MIN_EXP__ (-1021) +// PPC64:#define __LDBL_MIN__ 2.2250738585072014e-308 +// PPC64:#define __LONG_DOUBLE_128__ 1 +// PPC64:#define __LONG_LONG_MAX__ 9223372036854775807LL +// PPC64:#define __LONG_MAX__ 9223372036854775807L +// PPC64:#define __LP64__ 1 +// PPC64:#define __NATURAL_ALIGNMENT__ 1 +// PPC64:#define __NO_INLINE__ 1 +// PPC64:#define __POINTER_WIDTH__ 64 +// PPC64:#define __POWERPC__ 1 +// PPC64:#define __PTRDIFF_TYPE__ long int +// PPC64:#define __REGISTER_PREFIX__ +// PPC64:#define __SCHAR_MAX__ 127 +// PPC64:#define __SHRT_MAX__ 32767 +// PPC64:#define __SIZE_TYPE__ long unsigned int +// PPC64:#define __UINTMAX_TYPE__ long unsigned int +// PPC64:#define __USER_LABEL_PREFIX__ _ +// PPC64:#define __WCHAR_MAX__ 2147483647 +// PPC64:#define __WCHAR_TYPE__ int +// PPC64:#define __WINT_TYPE__ int +// PPC64:#define __ppc64__ 1 +// PPC64:#define __ppc__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc-none-none < /dev/null | FileCheck -check-prefix PPC %s && +// +// PPC:#define _ARCH_PPC 1 +// PPC:#define _BIG_ENDIAN 1 +// PPC:#define __BIG_ENDIAN__ 1 +// PPC:#define __CHAR_BIT__ 8 +// PPC:#define __CHAR_UNSIGNED__ 1 +// PPC:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// PPC:#define __DBL_DIG__ 15 +// PPC:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// PPC:#define __DBL_HAS_DENORM__ 1 +// PPC:#define __DBL_HAS_INFINITY__ 1 +// PPC:#define __DBL_HAS_QUIET_NAN__ 1 +// PPC:#define __DBL_MANT_DIG__ 53 +// PPC:#define __DBL_MAX_10_EXP__ 308 +// PPC:#define __DBL_MAX_EXP__ 1024 +// PPC:#define __DBL_MAX__ 1.7976931348623157e+308 +// PPC:#define __DBL_MIN_10_EXP__ (-307) +// PPC:#define __DBL_MIN_EXP__ (-1021) +// PPC:#define __DBL_MIN__ 2.2250738585072014e-308 +// PPC:#define __DECIMAL_DIG__ 17 +// PPC:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// PPC:#define __FLT_DIG__ 6 +// PPC:#define __FLT_EPSILON__ 1.19209290e-7F +// PPC:#define __FLT_EVAL_METHOD__ 0 +// PPC:#define __FLT_HAS_DENORM__ 1 +// PPC:#define __FLT_HAS_INFINITY__ 1 +// PPC:#define __FLT_HAS_QUIET_NAN__ 1 +// PPC:#define __FLT_MANT_DIG__ 24 +// PPC:#define __FLT_MAX_10_EXP__ 38 +// PPC:#define __FLT_MAX_EXP__ 128 +// PPC:#define __FLT_MAX__ 3.40282347e+38F +// PPC:#define __FLT_MIN_10_EXP__ (-37) +// PPC:#define __FLT_MIN_EXP__ (-125) +// PPC:#define __FLT_MIN__ 1.17549435e-38F +// PPC:#define __FLT_RADIX__ 2 +// PPC:#define __INT16_TYPE__ short +// PPC:#define __INT32_TYPE__ int +// PPC:#define __INT64_TYPE__ long long int +// PPC:#define __INT8_TYPE__ char +// PPC:#define __INTMAX_MAX__ 9223372036854775807LL +// PPC:#define __INTMAX_TYPE__ long long int +// PPC:#define __INTPTR_TYPE__ long int +// PPC:#define __INT_MAX__ 2147483647 +// PPC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// PPC:#define __LDBL_DIG__ 15 +// PPC:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// PPC:#define __LDBL_HAS_DENORM__ 1 +// PPC:#define __LDBL_HAS_INFINITY__ 1 +// PPC:#define __LDBL_HAS_QUIET_NAN__ 1 +// PPC:#define __LDBL_MANT_DIG__ 53 +// PPC:#define __LDBL_MAX_10_EXP__ 308 +// PPC:#define __LDBL_MAX_EXP__ 1024 +// PPC:#define __LDBL_MAX__ 1.7976931348623157e+308 +// PPC:#define __LDBL_MIN_10_EXP__ (-307) +// PPC:#define __LDBL_MIN_EXP__ (-1021) +// PPC:#define __LDBL_MIN__ 2.2250738585072014e-308 +// PPC:#define __LONG_DOUBLE_128__ 1 +// PPC:#define __LONG_LONG_MAX__ 9223372036854775807LL +// PPC:#define __LONG_MAX__ 2147483647L +// PPC:#define __NATURAL_ALIGNMENT__ 1 +// PPC:#define __NO_INLINE__ 1 +// PPC:#define __POINTER_WIDTH__ 32 +// PPC:#define __POWERPC__ 1 +// PPC:#define __PTRDIFF_TYPE__ long int +// PPC:#define __REGISTER_PREFIX__ +// PPC:#define __SCHAR_MAX__ 127 +// PPC:#define __SHRT_MAX__ 32767 +// PPC:#define __SIZE_TYPE__ long unsigned int +// PPC:#define __UINTMAX_TYPE__ long long unsigned int +// PPC:#define __USER_LABEL_PREFIX__ _ +// PPC:#define __WCHAR_MAX__ 2147483647 +// PPC:#define __WCHAR_TYPE__ int +// PPC:#define __WINT_TYPE__ int +// PPC:#define __ppc__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=s390x-none-none < /dev/null | FileCheck -check-prefix S390X %s && +// +// S390X:#define __CHAR_BIT__ 8 +// S390X:#define __CHAR_UNSIGNED__ 1 +// S390X:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// S390X:#define __DBL_DIG__ 15 +// S390X:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// S390X:#define __DBL_HAS_DENORM__ 1 +// S390X:#define __DBL_HAS_INFINITY__ 1 +// S390X:#define __DBL_HAS_QUIET_NAN__ 1 +// S390X:#define __DBL_MANT_DIG__ 53 +// S390X:#define __DBL_MAX_10_EXP__ 308 +// S390X:#define __DBL_MAX_EXP__ 1024 +// S390X:#define __DBL_MAX__ 1.7976931348623157e+308 +// S390X:#define __DBL_MIN_10_EXP__ (-307) +// S390X:#define __DBL_MIN_EXP__ (-1021) +// S390X:#define __DBL_MIN__ 2.2250738585072014e-308 +// S390X:#define __DECIMAL_DIG__ 17 +// S390X:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// S390X:#define __FLT_DIG__ 6 +// S390X:#define __FLT_EPSILON__ 1.19209290e-7F +// S390X:#define __FLT_EVAL_METHOD__ 0 +// S390X:#define __FLT_HAS_DENORM__ 1 +// S390X:#define __FLT_HAS_INFINITY__ 1 +// S390X:#define __FLT_HAS_QUIET_NAN__ 1 +// S390X:#define __FLT_MANT_DIG__ 24 +// S390X:#define __FLT_MAX_10_EXP__ 38 +// S390X:#define __FLT_MAX_EXP__ 128 +// S390X:#define __FLT_MAX__ 3.40282347e+38F +// S390X:#define __FLT_MIN_10_EXP__ (-37) +// S390X:#define __FLT_MIN_EXP__ (-125) +// S390X:#define __FLT_MIN__ 1.17549435e-38F +// S390X:#define __FLT_RADIX__ 2 +// S390X:#define __INT16_TYPE__ short +// S390X:#define __INT32_TYPE__ int +// S390X:#define __INT64_TYPE__ long long int +// S390X:#define __INT8_TYPE__ char +// S390X:#define __INTMAX_MAX__ 9223372036854775807LL +// S390X:#define __INTMAX_TYPE__ long long int +// S390X:#define __INTPTR_TYPE__ long int +// S390X:#define __INT_MAX__ 2147483647 +// S390X:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// S390X:#define __LDBL_DIG__ 15 +// S390X:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// S390X:#define __LDBL_HAS_DENORM__ 1 +// S390X:#define __LDBL_HAS_INFINITY__ 1 +// S390X:#define __LDBL_HAS_QUIET_NAN__ 1 +// S390X:#define __LDBL_MANT_DIG__ 53 +// S390X:#define __LDBL_MAX_10_EXP__ 308 +// S390X:#define __LDBL_MAX_EXP__ 1024 +// S390X:#define __LDBL_MAX__ 1.7976931348623157e+308 +// S390X:#define __LDBL_MIN_10_EXP__ (-307) +// S390X:#define __LDBL_MIN_EXP__ (-1021) +// S390X:#define __LDBL_MIN__ 2.2250738585072014e-308 +// S390X:#define __LONG_LONG_MAX__ 9223372036854775807LL +// S390X:#define __LONG_MAX__ 9223372036854775807L +// S390X:#define __NO_INLINE__ 1 +// S390X:#define __POINTER_WIDTH__ 64 +// S390X:#define __PTRDIFF_TYPE__ long int +// S390X:#define __SCHAR_MAX__ 127 +// S390X:#define __SHRT_MAX__ 32767 +// S390X:#define __SIZE_TYPE__ long unsigned int +// S390X:#define __UINTMAX_TYPE__ long long unsigned int +// S390X:#define __USER_LABEL_PREFIX__ _ +// S390X:#define __WCHAR_MAX__ 2147483647 +// S390X:#define __WCHAR_TYPE__ int +// S390X:#define __WINT_TYPE__ int +// S390X:#define __s390__ 1 +// S390X:#define __s390x__ 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=sparc-none-none < /dev/null | FileCheck -check-prefix SPARC %s && +// +// SPARC:#define __CHAR_BIT__ 8 +// SPARC:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// SPARC:#define __DBL_DIG__ 15 +// SPARC:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// SPARC:#define __DBL_HAS_DENORM__ 1 +// SPARC:#define __DBL_HAS_INFINITY__ 1 +// SPARC:#define __DBL_HAS_QUIET_NAN__ 1 +// SPARC:#define __DBL_MANT_DIG__ 53 +// SPARC:#define __DBL_MAX_10_EXP__ 308 +// SPARC:#define __DBL_MAX_EXP__ 1024 +// SPARC:#define __DBL_MAX__ 1.7976931348623157e+308 +// SPARC:#define __DBL_MIN_10_EXP__ (-307) +// SPARC:#define __DBL_MIN_EXP__ (-1021) +// SPARC:#define __DBL_MIN__ 2.2250738585072014e-308 +// SPARC:#define __DECIMAL_DIG__ 17 +// SPARC:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// SPARC:#define __FLT_DIG__ 6 +// SPARC:#define __FLT_EPSILON__ 1.19209290e-7F +// SPARC:#define __FLT_EVAL_METHOD__ 0 +// SPARC:#define __FLT_HAS_DENORM__ 1 +// SPARC:#define __FLT_HAS_INFINITY__ 1 +// SPARC:#define __FLT_HAS_QUIET_NAN__ 1 +// SPARC:#define __FLT_MANT_DIG__ 24 +// SPARC:#define __FLT_MAX_10_EXP__ 38 +// SPARC:#define __FLT_MAX_EXP__ 128 +// SPARC:#define __FLT_MAX__ 3.40282347e+38F +// SPARC:#define __FLT_MIN_10_EXP__ (-37) +// SPARC:#define __FLT_MIN_EXP__ (-125) +// SPARC:#define __FLT_MIN__ 1.17549435e-38F +// SPARC:#define __FLT_RADIX__ 2 +// SPARC:#define __INT16_TYPE__ short +// SPARC:#define __INT32_TYPE__ int +// SPARC:#define __INT64_TYPE__ long long int +// SPARC:#define __INT8_TYPE__ char +// SPARC:#define __INTMAX_MAX__ 9223372036854775807LL +// SPARC:#define __INTMAX_TYPE__ long long int +// SPARC:#define __INTPTR_TYPE__ long int +// SPARC:#define __INT_MAX__ 2147483647 +// SPARC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324 +// SPARC:#define __LDBL_DIG__ 15 +// SPARC:#define __LDBL_EPSILON__ 2.2204460492503131e-16 +// SPARC:#define __LDBL_HAS_DENORM__ 1 +// SPARC:#define __LDBL_HAS_INFINITY__ 1 +// SPARC:#define __LDBL_HAS_QUIET_NAN__ 1 +// SPARC:#define __LDBL_MANT_DIG__ 53 +// SPARC:#define __LDBL_MAX_10_EXP__ 308 +// SPARC:#define __LDBL_MAX_EXP__ 1024 +// SPARC:#define __LDBL_MAX__ 1.7976931348623157e+308 +// SPARC:#define __LDBL_MIN_10_EXP__ (-307) +// SPARC:#define __LDBL_MIN_EXP__ (-1021) +// SPARC:#define __LDBL_MIN__ 2.2250738585072014e-308 +// SPARC:#define __LONG_LONG_MAX__ 9223372036854775807LL +// SPARC:#define __LONG_MAX__ 2147483647L +// SPARC:#define __NO_INLINE__ 1 +// SPARC:#define __POINTER_WIDTH__ 32 +// SPARC:#define __PTRDIFF_TYPE__ long int +// SPARC:#define __REGISTER_PREFIX__ +// SPARC:#define __SCHAR_MAX__ 127 +// SPARC:#define __SHRT_MAX__ 32767 +// SPARC:#define __SIZE_TYPE__ long unsigned int +// SPARC:#define __UINTMAX_TYPE__ long long unsigned int +// SPARC:#define __USER_LABEL_PREFIX__ _ +// SPARC:#define __VERSION__ "4.2.1 Compatible Clang Compiler" +// SPARC:#define __WCHAR_MAX__ 2147483647 +// SPARC:#define __WCHAR_TYPE__ int +// SPARC:#define __WINT_TYPE__ int +// SPARC:#define __sparc 1 +// SPARC:#define __sparc__ 1 +// SPARC:#define __sparcv8 1 +// SPARC:#define sparc 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=tce-none-none < /dev/null | FileCheck -check-prefix TCE %s && +// +// TCE:#define __CHAR_BIT__ 8 +// TCE:#define __DBL_DENORM_MIN__ 1.40129846e-45F +// TCE:#define __DBL_DIG__ 6 +// TCE:#define __DBL_EPSILON__ 1.19209290e-7F +// TCE:#define __DBL_HAS_DENORM__ 1 +// TCE:#define __DBL_HAS_INFINITY__ 1 +// TCE:#define __DBL_HAS_QUIET_NAN__ 1 +// TCE:#define __DBL_MANT_DIG__ 24 +// TCE:#define __DBL_MAX_10_EXP__ 38 +// TCE:#define __DBL_MAX_EXP__ 128 +// TCE:#define __DBL_MAX__ 3.40282347e+38F +// TCE:#define __DBL_MIN_10_EXP__ (-37) +// TCE:#define __DBL_MIN_EXP__ (-125) +// TCE:#define __DBL_MIN__ 1.17549435e-38F +// TCE:#define __DECIMAL_DIG__ -1 +// TCE:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// TCE:#define __FLT_DIG__ 6 +// TCE:#define __FLT_EPSILON__ 1.19209290e-7F +// TCE:#define __FLT_EVAL_METHOD__ 0 +// TCE:#define __FLT_HAS_DENORM__ 1 +// TCE:#define __FLT_HAS_INFINITY__ 1 +// TCE:#define __FLT_HAS_QUIET_NAN__ 1 +// TCE:#define __FLT_MANT_DIG__ 24 +// TCE:#define __FLT_MAX_10_EXP__ 38 +// TCE:#define __FLT_MAX_EXP__ 128 +// TCE:#define __FLT_MAX__ 3.40282347e+38F +// TCE:#define __FLT_MIN_10_EXP__ (-37) +// TCE:#define __FLT_MIN_EXP__ (-125) +// TCE:#define __FLT_MIN__ 1.17549435e-38F +// TCE:#define __FLT_RADIX__ 2 +// TCE:#define __INT16_TYPE__ short +// TCE:#define __INT32_TYPE__ int +// TCE:#define __INT8_TYPE__ char +// TCE:#define __INTMAX_MAX__ 2147483647L +// TCE:#define __INTMAX_TYPE__ long int +// TCE:#define __INTPTR_TYPE__ int +// TCE:#define __INT_MAX__ 2147483647 +// TCE:#define __LDBL_DENORM_MIN__ 1.40129846e-45F +// TCE:#define __LDBL_DIG__ 6 +// TCE:#define __LDBL_EPSILON__ 1.19209290e-7F +// TCE:#define __LDBL_HAS_DENORM__ 1 +// TCE:#define __LDBL_HAS_INFINITY__ 1 +// TCE:#define __LDBL_HAS_QUIET_NAN__ 1 +// TCE:#define __LDBL_MANT_DIG__ 24 +// TCE:#define __LDBL_MAX_10_EXP__ 38 +// TCE:#define __LDBL_MAX_EXP__ 128 +// TCE:#define __LDBL_MAX__ 3.40282347e+38F +// TCE:#define __LDBL_MIN_10_EXP__ (-37) +// TCE:#define __LDBL_MIN_EXP__ (-125) +// TCE:#define __LDBL_MIN__ 1.17549435e-38F +// TCE:#define __LONG_LONG_MAX__ 2147483647LL +// TCE:#define __LONG_MAX__ 2147483647L +// TCE:#define __NO_INLINE__ 1 +// TCE:#define __POINTER_WIDTH__ 32 +// TCE:#define __PTRDIFF_TYPE__ int +// TCE:#define __SCHAR_MAX__ 127 +// TCE:#define __SHRT_MAX__ 32767 +// TCE:#define __SIZE_TYPE__ unsigned int +// TCE:#define __TCE_V1__ 1 +// TCE:#define __TCE__ 1 +// TCE:#define __UINTMAX_TYPE__ long unsigned int +// TCE:#define __USER_LABEL_PREFIX__ _ +// TCE:#define __WCHAR_MAX__ 2147483647 +// TCE:#define __WCHAR_TYPE__ int +// TCE:#define __WINT_TYPE__ int +// TCE:#define __tce 1 +// TCE:#define __tce__ 1 +// TCE:#define tce 1 +// +// RUN: clang-cc -E -dM -ffreestanding -triple=x86_64-none-none < /dev/null | FileCheck -check-prefix X86_64 %s && +// +// X86_64:#define _LP64 1 +// X86_64:#define __CHAR_BIT__ 8 +// X86_64:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +// X86_64:#define __DBL_DIG__ 15 +// X86_64:#define __DBL_EPSILON__ 2.2204460492503131e-16 +// X86_64:#define __DBL_HAS_DENORM__ 1 +// X86_64:#define __DBL_HAS_INFINITY__ 1 +// X86_64:#define __DBL_HAS_QUIET_NAN__ 1 +// X86_64:#define __DBL_MANT_DIG__ 53 +// X86_64:#define __DBL_MAX_10_EXP__ 308 +// X86_64:#define __DBL_MAX_EXP__ 1024 +// X86_64:#define __DBL_MAX__ 1.7976931348623157e+308 +// X86_64:#define __DBL_MIN_10_EXP__ (-307) +// X86_64:#define __DBL_MIN_EXP__ (-1021) +// X86_64:#define __DBL_MIN__ 2.2250738585072014e-308 +// X86_64:#define __DECIMAL_DIG__ 21 +// X86_64:#define __FLT_DENORM_MIN__ 1.40129846e-45F +// X86_64:#define __FLT_DIG__ 6 +// X86_64:#define __FLT_EPSILON__ 1.19209290e-7F +// X86_64:#define __FLT_EVAL_METHOD__ 0 +// X86_64:#define __FLT_HAS_DENORM__ 1 +// X86_64:#define __FLT_HAS_INFINITY__ 1 +// X86_64:#define __FLT_HAS_QUIET_NAN__ 1 +// X86_64:#define __FLT_MANT_DIG__ 24 +// X86_64:#define __FLT_MAX_10_EXP__ 38 +// X86_64:#define __FLT_MAX_EXP__ 128 +// X86_64:#define __FLT_MAX__ 3.40282347e+38F +// X86_64:#define __FLT_MIN_10_EXP__ (-37) +// X86_64:#define __FLT_MIN_EXP__ (-125) +// X86_64:#define __FLT_MIN__ 1.17549435e-38F +// X86_64:#define __FLT_RADIX__ 2 +// X86_64:#define __INT16_TYPE__ short +// X86_64:#define __INT32_TYPE__ int +// X86_64:#define __INT64_TYPE__ long int +// X86_64:#define __INT8_TYPE__ char +// X86_64:#define __INTMAX_MAX__ 9223372036854775807L +// X86_64:#define __INTMAX_TYPE__ long int +// X86_64:#define __INTPTR_TYPE__ long int +// X86_64:#define __INT_MAX__ 2147483647 +// X86_64:#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +// X86_64:#define __LDBL_DIG__ 18 +// X86_64:#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +// X86_64:#define __LDBL_HAS_DENORM__ 1 +// X86_64:#define __LDBL_HAS_INFINITY__ 1 +// X86_64:#define __LDBL_HAS_QUIET_NAN__ 1 +// X86_64:#define __LDBL_MANT_DIG__ 64 +// X86_64:#define __LDBL_MAX_10_EXP__ 4932 +// X86_64:#define __LDBL_MAX_EXP__ 16384 +// X86_64:#define __LDBL_MAX__ 1.18973149535723176502e+4932L +// X86_64:#define __LDBL_MIN_10_EXP__ (-4931) +// X86_64:#define __LDBL_MIN_EXP__ (-16381) +// X86_64:#define __LDBL_MIN__ 3.36210314311209350626e-4932L +// X86_64:#define __LITTLE_ENDIAN__ 1 +// X86_64:#define __LONG_LONG_MAX__ 9223372036854775807LL +// X86_64:#define __LONG_MAX__ 9223372036854775807L +// X86_64:#define __LP64__ 1 +// X86_64:#define __MMX__ 1 +// X86_64:#define __NO_INLINE__ 1 +// X86_64:#define __NO_MATH_INLINES 1 +// X86_64:#define __POINTER_WIDTH__ 64 +// X86_64:#define __PTRDIFF_TYPE__ long int +// X86_64:#define __REGISTER_PREFIX__ +// X86_64:#define __SCHAR_MAX__ 127 +// X86_64:#define __SHRT_MAX__ 32767 +// X86_64:#define __SIZE_TYPE__ long unsigned int +// X86_64:#define __SSE2_MATH__ 1 +// X86_64:#define __SSE2__ 1 +// X86_64:#define __SSE_MATH__ 1 +// X86_64:#define __SSE__ 1 +// X86_64:#define __UINTMAX_TYPE__ long unsigned int +// X86_64:#define __USER_LABEL_PREFIX__ _ +// X86_64:#define __WCHAR_MAX__ 2147483647 +// X86_64:#define __WCHAR_TYPE__ int +// X86_64:#define __WINT_TYPE__ int +// X86_64:#define __amd64 1 +// X86_64:#define __amd64__ 1 +// X86_64:#define __nocona 1 +// X86_64:#define __nocona__ 1 +// X86_64:#define __tune_nocona__ 1 +// X86_64:#define __x86_64 1 +// X86_64:#define __x86_64__ 1 +// +// RUN: true diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c index ed9a6c4..4ebf95b 100644 --- a/test/Preprocessor/line-directive.c +++ b/test/Preprocessor/line-directive.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s && +// RUN: clang-cc -fsyntax-only -verify -pedantic -fms-extensions=0 %s && // RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:92:2: error: #error ABC' && // RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:93:2: error: #error DEF' diff --git a/test/Preprocessor/macro_disable3.c b/test/Preprocessor/macro_disable3.c index 011de3b..d4a5664 100644 --- a/test/Preprocessor/macro_disable3.c +++ b/test/Preprocessor/macro_disable3.c @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -E | grep -F 'f(2 * (f(2 * (z[0]))));' +// RUN: clang-cc %s -E | FileCheck -strict-whitespace %s // Check for C99 6.10.3.4p2. #define f(a) f(x * (a)) @@ -6,3 +6,5 @@ #define z z[0] f(f(z)); +// CHECK: f(2 * (f(2 * (z[0])))); + diff --git a/test/Preprocessor/macro_paste_mscomment.c b/test/Preprocessor/macro_paste_mscomment.c index d6ead91..ecd0b9d 100644 --- a/test/Preprocessor/macro_paste_mscomment.c +++ b/test/Preprocessor/macro_paste_mscomment.c @@ -1,5 +1,4 @@ -// RUN: clang-cc -P -E -fms-extensions %s | sed '/^#.\+/d' | tr -d '\n' > %t && -// RUN: grep '^int foo;int bar;int baz;$' %t | count 1 +// RUN: clang-cc -P -E -fms-extensions %s | FileCheck -strict-whitespace %s // This horrible stuff should preprocess into (other than whitespace): // int foo; // int bar; @@ -7,14 +6,21 @@ int foo; +// CHECK: int foo; + #define comment /##/ dead tokens live here comment This is stupidity int bar; +// CHECK: int bar; + #define nested(x) int x comment cute little dead tokens... nested(baz) rise of the dead tokens ; +// CHECK: int baz +// CHECK: ; + diff --git a/test/Preprocessor/macro_rescan_varargs.c b/test/Preprocessor/macro_rescan_varargs.c index ed1056a..8a3ad15 100644 --- a/test/Preprocessor/macro_rescan_varargs.c +++ b/test/Preprocessor/macro_rescan_varargs.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -E %s | grep -F "1: F, (, 'a', 'b', );" && -// RUN: clang-cc -E %s | grep -F "2: 'a' + 'b';" +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s + #define LPAREN ( #define RPAREN ) #define F(x, y) x + y @@ -8,3 +8,6 @@ 1: ELLIP_FUNC(F, LPAREN, 'a', 'b', RPAREN); /* 1st invocation */ 2: ELLIP_FUNC(F LPAREN 'a', 'b' RPAREN); /* 2nd invocation */ +// CHECK: 1: F, (, 'a', 'b', ); +// CHECK: 2: 'a' + 'b'; + diff --git a/test/Preprocessor/macro_rparen_scan2.c b/test/Preprocessor/macro_rparen_scan2.c index 41748ac..c7fb9e3 100644 --- a/test/Preprocessor/macro_rparen_scan2.c +++ b/test/Preprocessor/macro_rparen_scan2.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -E %s | grep -F 'static int glob = (1 + 1 );' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define R_PAREN ) @@ -6,3 +6,5 @@ static int glob = (1 + FUNC(1 R_PAREN ); +// CHECK: static int glob = (1 + 1 ); + diff --git a/test/Preprocessor/macro_undef.c b/test/Preprocessor/macro_undef.c new file mode 100644 index 0000000..4507cdd --- /dev/null +++ b/test/Preprocessor/macro_undef.c @@ -0,0 +1,4 @@ +// RUN: clang-cc -dM -undef -Dfoo=1 -E %s | FileCheck %s + +// CHECK-NOT: #define __clang__ +// CHECK: #define foo 1 diff --git a/test/Preprocessor/output_paste_avoid.c b/test/Preprocessor/output_paste_avoid.c index ff8afc3..200ced9 100644 --- a/test/Preprocessor/output_paste_avoid.c +++ b/test/Preprocessor/output_paste_avoid.c @@ -1,23 +1,26 @@ -// RUN: clang-cc -E %s -o %t && -// This should print as ".. ." to avoid turning into ... -// RUN: grep -F 'A: . . .' %t && +// RUN: clang-cc -E %s -o - | FileCheck -strict-whitespace %s + + #define y(a) ..a A: y(.) +// This should print as ".. ." to avoid turning into ... +// CHECK: A: . . . + -// RUN: grep -F 'C: .. .' %t && #define DOT . C: ..DOT +// CHECK: C: .. . -// RUN: grep -F 'D: + + - - + + = = =' %t && #define PLUS + #define EMPTY #define f(x) =x= D: +PLUS -EMPTY- PLUS+ f(=) +// CHECK: D: + + - - + + = = = -// RUN: grep -F 'E: L "str"' %t -// Should expand to L "str" not L"str" #define test(x) L#x E: test(str) +// Should expand to L "str" not L"str" +// CHECK: E: L "str" diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c new file mode 100644 index 0000000..e292bd3 --- /dev/null +++ b/test/Preprocessor/stdint.c @@ -0,0 +1,1244 @@ +// RUN: clang-cc -E -ffreestanding -triple=arm-none-none %s | FileCheck -check-prefix ARM %s && +// +// ARM:typedef signed char int8_t; +// ARM:typedef short int16_t; +// ARM:typedef int int32_t; +// ARM:typedef long long int int64_t; +// +// ARM:typedef unsigned char uint8_t; +// ARM:typedef int8_t int_least8_t; +// ARM:typedef uint8_t uint_least8_t; +// ARM:typedef int8_t int_fast8_t; +// ARM:typedef uint8_t uint_fast8_t; +// +// ARM:typedef unsigned short uint16_t; +// ARM:typedef int16_t int_least16_t; +// ARM:typedef uint16_t uint_least16_t; +// ARM:typedef int16_t int_fast16_t; +// ARM:typedef uint16_t uint_fast16_t; +// +// ARM:typedef unsigned int uint32_t; +// ARM:typedef int32_t int_least32_t; +// ARM:typedef uint32_t uint_least32_t; +// ARM:typedef int32_t int_fast32_t; +// ARM:typedef uint32_t uint_fast32_t; +// +// ARM:typedef unsigned long long int uint64_t; +// ARM:typedef int64_t int_least64_t; +// ARM:typedef uint64_t uint_least64_t; +// ARM:typedef int64_t int_fast64_t; +// ARM:typedef uint64_t uint_fast64_t; +// +// ARM:typedef long int intptr_t; +// ARM:typedef unsigned long int uintptr_t; +// +// ARM:typedef long long int intmax_t; +// ARM:typedef long long unsigned int uintmax_t; +// +// ARM:INT8_MAX_ 127 +// ARM:INT8_MIN_ (-128) +// ARM:UINT8_MAX_ 255 +// ARM:INT_LEAST8_MIN_ (-128) +// ARM:INT_LEAST8_MAX_ 127 +// ARM:UINT_LEAST8_MAX_ 255 +// ARM:INT_FAST8_MIN_ (-128) +// ARM:INT_FAST8_MAX_ 127 +// ARM:UINT_FAST8_MAX_ 255 +// +// ARM:INT16_MAX_ 32767 +// ARM:INT16_MIN_ (-32768) +// ARM:UINT16_MAX_ 65535 +// ARM:INT_LEAST16_MIN_ (-32768) +// ARM:INT_LEAST16_MAX_ 32767 +// ARM:UINT_LEAST16_MAX_ 65535 +// ARM:INT_FAST16_MIN_ (-32768) +// ARM:INT_FAST16_MAX_ 32767 +// ARM:UINT_FAST16_MAX_ 65535 +// +// ARM:INT32_MAX_ 2147483647 +// ARM:INT32_MIN_ (-2147483647 -1) +// ARM:UINT32_MAX_ 4294967295U +// ARM:INT_LEAST32_MIN_ (-2147483647 -1) +// ARM:INT_LEAST32_MAX_ 2147483647 +// ARM:UINT_LEAST32_MAX_ 4294967295U +// ARM:INT_FAST32_MIN_ (-2147483647 -1) +// ARM:INT_FAST32_MAX_ 2147483647 +// ARM:UINT_FAST32_MAX_ 4294967295U +// +// ARM:INT64_MAX_ 9223372036854775807LL +// ARM:INT64_MIN_ (-9223372036854775807LL -1) +// ARM:UINT64_MAX_ 18446744073709551615ULL +// ARM:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// ARM:INT_LEAST64_MAX_ 9223372036854775807LL +// ARM:UINT_LEAST64_MAX_ 18446744073709551615ULL +// ARM:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// ARM:INT_FAST64_MAX_ 9223372036854775807LL +// ARM:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// ARM:INTPTR_MIN_ (-2147483647 -1) +// ARM:INTPTR_MAX_ 2147483647 +// ARM:UINTPTR_MAX_ 4294967295U +// ARM:PTRDIFF_MIN_ (-2147483647 -1) +// ARM:PTRDIFF_MAX_ 2147483647 +// ARM:SIZE_MAX_ 4294967295U +// +// ARM:INTMAX_MIN_ (-9223372036854775807LL -1) +// ARM:INTMAX_MAX_ 9223372036854775807LL +// ARM:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// ARM:SIG_ATOMIC_MIN_ (-2147483647 -1) +// ARM:SIG_ATOMIC_MAX_ 2147483647 +// ARM:WINT_MIN_ (-2147483647 -1) +// ARM:WINT_MAX_ 2147483647 +// +// ARM:WCHAR_MAX_ 2147483647 +// ARM:WCHAR_MIN_ (-2147483647 -1) +// +// ARM:INT8_C_(0) (0) +// ARM:UINT8_C_(0) (0U) +// ARM:INT16_C_(0) (0) +// ARM:UINT16_C_(0) (0U) +// ARM:INT32_C_(0) (0) +// ARM:UINT32_C_(0) (0U) +// ARM:INT64_C_(0) (0LL) +// ARM:UINT64_C_(0) (0ULL) +// +// ARM:INTMAX_C_(0) (0LL) +// ARM:UINTMAX_C_(0) (0ULL) +// +// +// RUN: clang-cc -E -ffreestanding -triple=bfin-none-none %s | FileCheck -check-prefix BFIN %s && +// +// BFIN:typedef signed char int8_t; +// BFIN:typedef short int16_t; +// BFIN:typedef int int32_t; +// +// BFIN:typedef long long int int64_t; +// +// BFIN:typedef unsigned char uint8_t; +// BFIN:typedef int8_t int_least8_t; +// BFIN:typedef uint8_t uint_least8_t; +// BFIN:typedef int8_t int_fast8_t; +// BFIN:typedef uint8_t uint_fast8_t; +// +// BFIN:typedef unsigned short uint16_t; +// BFIN:typedef int16_t int_least16_t; +// BFIN:typedef uint16_t uint_least16_t; +// BFIN:typedef int16_t int_fast16_t; +// BFIN:typedef uint16_t uint_fast16_t; +// +// BFIN:typedef unsigned int uint32_t; +// BFIN:typedef int32_t int_least32_t; +// BFIN:typedef uint32_t uint_least32_t; +// BFIN:typedef int32_t int_fast32_t; +// BFIN:typedef uint32_t uint_fast32_t; +// +// BFIN:typedef unsigned long long int uint64_t; +// BFIN:typedef int64_t int_least64_t; +// BFIN:typedef uint64_t uint_least64_t; +// BFIN:typedef int64_t int_fast64_t; +// BFIN:typedef uint64_t uint_fast64_t; +// +// BFIN:typedef long int intptr_t; +// BFIN:typedef unsigned long int uintptr_t; +// +// BFIN:typedef long long int intmax_t; +// BFIN:typedef long long unsigned int uintmax_t; +// +// BFIN:INT8_MAX_ 127 +// BFIN:INT8_MIN_ (-128) +// BFIN:UINT8_MAX_ 255 +// BFIN:INT_LEAST8_MIN_ (-128) +// BFIN:INT_LEAST8_MAX_ 127 +// BFIN:UINT_LEAST8_MAX_ 255 +// BFIN:INT_FAST8_MIN_ (-128) +// BFIN:INT_FAST8_MAX_ 127 +// BFIN:UINT_FAST8_MAX_ 255 +// +// BFIN:INT16_MAX_ 32767 +// BFIN:INT16_MIN_ (-32768) +// BFIN:UINT16_MAX_ 65535 +// BFIN:INT_LEAST16_MIN_ (-32768) +// BFIN:INT_LEAST16_MAX_ 32767 +// BFIN:UINT_LEAST16_MAX_ 65535 +// BFIN:INT_FAST16_MIN_ (-32768) +// BFIN:INT_FAST16_MAX_ 32767 +// BFIN:UINT_FAST16_MAX_ 65535 +// +// BFIN:INT32_MAX_ 2147483647 +// BFIN:INT32_MIN_ (-2147483647 -1) +// BFIN:UINT32_MAX_ 4294967295U +// BFIN:INT_LEAST32_MIN_ (-2147483647 -1) +// BFIN:INT_LEAST32_MAX_ 2147483647 +// BFIN:UINT_LEAST32_MAX_ 4294967295U +// BFIN:INT_FAST32_MIN_ (-2147483647 -1) +// BFIN:INT_FAST32_MAX_ 2147483647 +// BFIN:UINT_FAST32_MAX_ 4294967295U +// +// BFIN:INT64_MAX_ 9223372036854775807LL +// BFIN:INT64_MIN_ (-9223372036854775807LL -1) +// BFIN:UINT64_MAX_ 18446744073709551615ULL +// BFIN:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// BFIN:INT_LEAST64_MAX_ 9223372036854775807LL +// BFIN:UINT_LEAST64_MAX_ 18446744073709551615ULL +// BFIN:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// BFIN:INT_FAST64_MAX_ 9223372036854775807LL +// BFIN:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// BFIN:INTPTR_MIN_ (-2147483647 -1) +// BFIN:INTPTR_MAX_ 2147483647 +// BFIN:UINTPTR_MAX_ 4294967295U +// BFIN:PTRDIFF_MIN_ (-2147483647 -1) +// BFIN:PTRDIFF_MAX_ 2147483647 +// BFIN:SIZE_MAX_ 4294967295U +// +// BFIN:INTMAX_MIN_ (-9223372036854775807LL -1) +// BFIN:INTMAX_MAX_ 9223372036854775807LL +// BFIN:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// BFIN:SIG_ATOMIC_MIN_ (-2147483647 -1) +// BFIN:SIG_ATOMIC_MAX_ 2147483647 +// BFIN:WINT_MIN_ (-2147483647 -1) +// BFIN:WINT_MAX_ 2147483647 +// +// BFIN:WCHAR_MAX_ 2147483647 +// BFIN:WCHAR_MIN_ (-2147483647 -1) +// +// BFIN:INT8_C_(0) (0) +// BFIN:UINT8_C_(0) (0U) +// BFIN:INT16_C_(0) (0) +// BFIN:UINT16_C_(0) (0U) +// BFIN:INT32_C_(0) (0) +// BFIN:UINT32_C_(0) (0U) +// BFIN:INT64_C_(0) (0LL) +// BFIN:UINT64_C_(0) (0ULL) +// +// BFIN:INTMAX_C_(0) (0LL) +// BFIN:UINTMAX_C_(0) (0ULL) +// +// +// RUN: clang-cc -E -ffreestanding -triple=i386-none-none %s | FileCheck -check-prefix I386 %s && +// +// I386:typedef signed char int8_t; +// I386:typedef short int16_t; +// I386:typedef int int32_t; +// I386:typedef long long int int64_t; +// +// I386:typedef unsigned char uint8_t; +// I386:typedef int8_t int_least8_t; +// I386:typedef uint8_t uint_least8_t; +// I386:typedef int8_t int_fast8_t; +// I386:typedef uint8_t uint_fast8_t; +// +// I386:typedef unsigned short uint16_t; +// I386:typedef int16_t int_least16_t; +// I386:typedef uint16_t uint_least16_t; +// I386:typedef int16_t int_fast16_t; +// I386:typedef uint16_t uint_fast16_t; +// +// I386:typedef unsigned int uint32_t; +// I386:typedef int32_t int_least32_t; +// I386:typedef uint32_t uint_least32_t; +// I386:typedef int32_t int_fast32_t; +// I386:typedef uint32_t uint_fast32_t; +// +// I386:typedef unsigned long long int uint64_t; +// I386:typedef int64_t int_least64_t; +// I386:typedef uint64_t uint_least64_t; +// I386:typedef int64_t int_fast64_t; +// I386:typedef uint64_t uint_fast64_t; +// +// I386:typedef int intptr_t; +// I386:typedef unsigned int uintptr_t; +// +// I386:typedef long long int intmax_t; +// I386:typedef long long unsigned int uintmax_t; +// +// I386:INT8_MAX_ 127 +// I386:INT8_MIN_ (-128) +// I386:UINT8_MAX_ 255 +// I386:INT_LEAST8_MIN_ (-128) +// I386:INT_LEAST8_MAX_ 127 +// I386:UINT_LEAST8_MAX_ 255 +// I386:INT_FAST8_MIN_ (-128) +// I386:INT_FAST8_MAX_ 127 +// I386:UINT_FAST8_MAX_ 255 +// +// I386:INT16_MAX_ 32767 +// I386:INT16_MIN_ (-32768) +// I386:UINT16_MAX_ 65535 +// I386:INT_LEAST16_MIN_ (-32768) +// I386:INT_LEAST16_MAX_ 32767 +// I386:UINT_LEAST16_MAX_ 65535 +// I386:INT_FAST16_MIN_ (-32768) +// I386:INT_FAST16_MAX_ 32767 +// I386:UINT_FAST16_MAX_ 65535 +// +// I386:INT32_MAX_ 2147483647 +// I386:INT32_MIN_ (-2147483647 -1) +// I386:UINT32_MAX_ 4294967295U +// I386:INT_LEAST32_MIN_ (-2147483647 -1) +// I386:INT_LEAST32_MAX_ 2147483647 +// I386:UINT_LEAST32_MAX_ 4294967295U +// I386:INT_FAST32_MIN_ (-2147483647 -1) +// I386:INT_FAST32_MAX_ 2147483647 +// I386:UINT_FAST32_MAX_ 4294967295U +// +// I386:INT64_MAX_ 9223372036854775807LL +// I386:INT64_MIN_ (-9223372036854775807LL -1) +// I386:UINT64_MAX_ 18446744073709551615ULL +// I386:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// I386:INT_LEAST64_MAX_ 9223372036854775807LL +// I386:UINT_LEAST64_MAX_ 18446744073709551615ULL +// I386:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// I386:INT_FAST64_MAX_ 9223372036854775807LL +// I386:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// I386:INTPTR_MIN_ (-2147483647 -1) +// I386:INTPTR_MAX_ 2147483647 +// I386:UINTPTR_MAX_ 4294967295U +// I386:PTRDIFF_MIN_ (-2147483647 -1) +// I386:PTRDIFF_MAX_ 2147483647 +// I386:SIZE_MAX_ 4294967295U +// +// I386:INTMAX_MIN_ (-9223372036854775807LL -1) +// I386:INTMAX_MAX_ 9223372036854775807LL +// I386:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// I386:SIG_ATOMIC_MIN_ (-2147483647 -1) +// I386:SIG_ATOMIC_MAX_ 2147483647 +// I386:WINT_MIN_ (-2147483647 -1) +// I386:WINT_MAX_ 2147483647 +// +// I386:WCHAR_MAX_ 2147483647 +// I386:WCHAR_MIN_ (-2147483647 -1) +// +// I386:INT8_C_(0) (0) +// I386:UINT8_C_(0) (0U) +// I386:INT16_C_(0) (0) +// I386:UINT16_C_(0) (0U) +// I386:INT32_C_(0) (0) +// I386:UINT32_C_(0) (0U) +// I386:INT64_C_(0) (0LL) +// I386:UINT64_C_(0) (0ULL) +// +// I386:INTMAX_C_(0) (0LL) +// I386:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=msp430-none-none %s | FileCheck -check-prefix MSP430 %s && +// +// MSP430:typedef signed char int8_t; +// MSP430:typedef short int16_t; +// MSP430:typedef long long int32_t; +// +// MSP430:typedef unsigned char uint8_t; +// MSP430:typedef int8_t int_least8_t; +// MSP430:typedef uint8_t uint_least8_t; +// MSP430:typedef int8_t int_fast8_t; +// MSP430:typedef uint8_t uint_fast8_t; +// +// MSP430:typedef unsigned short uint16_t; +// MSP430:typedef int16_t int_least16_t; +// MSP430:typedef uint16_t uint_least16_t; +// MSP430:typedef int16_t int_fast16_t; +// MSP430:typedef uint16_t uint_fast16_t; +// +// MSP430:typedef unsigned long long uint32_t; +// MSP430:typedef int32_t int_least32_t; +// MSP430:typedef uint32_t uint_least32_t; +// MSP430:typedef int32_t int_fast32_t; +// MSP430:typedef uint32_t uint_fast32_t; +// +// MSP430:typedef short intptr_t; +// MSP430:typedef unsigned short uintptr_t; +// +// MSP430:typedef long int intmax_t; +// MSP430:typedef long unsigned int uintmax_t; +// +// MSP430:INT8_MAX_ 127 +// MSP430:INT8_MIN_ (-128) +// MSP430:UINT8_MAX_ 255 +// MSP430:INT_LEAST8_MIN_ (-128) +// MSP430:INT_LEAST8_MAX_ 127 +// MSP430:UINT_LEAST8_MAX_ 255 +// MSP430:INT_FAST8_MIN_ (-128) +// MSP430:INT_FAST8_MAX_ 127 +// MSP430:UINT_FAST8_MAX_ 255 +// +// MSP430:INT16_MAX_ 32767 +// MSP430:INT16_MIN_ (-32768) +// MSP430:UINT16_MAX_ 65535 +// MSP430:INT_LEAST16_MIN_ (-32768) +// MSP430:INT_LEAST16_MAX_ 32767 +// MSP430:UINT_LEAST16_MAX_ 65535 +// MSP430:INT_FAST16_MIN_ (-32768) +// MSP430:INT_FAST16_MAX_ 32767 +// MSP430:UINT_FAST16_MAX_ 65535 +// +// MSP430:INT32_MAX_ 2147483647 +// MSP430:INT32_MIN_ (-2147483647 -1) +// MSP430:UINT32_MAX_ 4294967295U +// MSP430:INT_LEAST32_MIN_ (-2147483647 -1) +// MSP430:INT_LEAST32_MAX_ 2147483647 +// MSP430:UINT_LEAST32_MAX_ 4294967295U +// MSP430:INT_FAST32_MIN_ (-2147483647 -1) +// MSP430:INT_FAST32_MAX_ 2147483647 +// MSP430:UINT_FAST32_MAX_ 4294967295U +// +// MSP430:INT64_MAX_ INT64_MAX +// MSP430:INT64_MIN_ INT64_MIN +// MSP430:UINT64_MAX_ UINT64_MAX +// MSP430:INT_LEAST64_MIN_ INT_LEAST64_MIN +// MSP430:INT_LEAST64_MAX_ INT_LEAST64_MAX +// MSP430:UINT_LEAST64_MAX_ UINT_LEAST64_MAX +// MSP430:INT_FAST64_MIN_ INT_FAST64_MIN +// MSP430:INT_FAST64_MAX_ INT_FAST64_MAX +// MSP430:UINT_FAST64_MAX_ UINT_FAST64_MAX +// +// MSP430:INTPTR_MIN_ (-32768) +// MSP430:INTPTR_MAX_ 32767 +// MSP430:UINTPTR_MAX_ 65535 +// MSP430:PTRDIFF_MIN_ (-32768) +// MSP430:PTRDIFF_MAX_ 32767 +// MSP430:SIZE_MAX_ 65535 +// +// MSP430:INTMAX_MIN_ (-2147483647L -1) +// MSP430:INTMAX_MAX_ 2147483647L +// MSP430:UINTMAX_MAX_ (2147483647L*2ULL +1ULL) +// +// MSP430:SIG_ATOMIC_MIN_ (-2147483647 -1) +// MSP430:SIG_ATOMIC_MAX_ 2147483647 +// MSP430:WINT_MIN_ (-2147483647 -1) +// MSP430:WINT_MAX_ 2147483647 +// +// MSP430:WCHAR_MAX_ 2147483647 +// MSP430:WCHAR_MIN_ (-2147483647 -1) +// +// MSP430:INT8_C_(0) (0) +// MSP430:UINT8_C_(0) (0U) +// MSP430:INT16_C_(0) (0) +// MSP430:UINT16_C_(0) (0U) +// MSP430:INT32_C_(0) (0) +// MSP430:UINT32_C_(0) (0U) +// MSP430:INT64_C_(0) INT64_C(0) +// MSP430:UINT64_C_(0) UINT64_C(0) +// +// MSP430:INTMAX_C_(0) (0LL) +// MSP430:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=pic16-none-none %s | FileCheck -check-prefix PIC16 %s && +// +// PIC16:typedef signed char int8_t; +// PIC16:typedef short int16_t; +// PIC16:typedef long long int32_t; +// +// PIC16:typedef unsigned char uint8_t; +// PIC16:typedef int8_t int_least8_t; +// PIC16:typedef uint8_t uint_least8_t; +// PIC16:typedef int8_t int_fast8_t; +// PIC16:typedef uint8_t uint_fast8_t; +// +// PIC16:typedef unsigned short uint16_t; +// PIC16:typedef int16_t int_least16_t; +// PIC16:typedef uint16_t uint_least16_t; +// PIC16:typedef int16_t int_fast16_t; +// PIC16:typedef uint16_t uint_fast16_t; +// +// PIC16:typedef unsigned long long uint32_t; +// PIC16:typedef int32_t int_least32_t; +// PIC16:typedef uint32_t uint_least32_t; +// PIC16:typedef int32_t int_fast32_t; +// PIC16:typedef uint32_t uint_fast32_t; +// +// PIC16:typedef short intptr_t; +// PIC16:typedef unsigned short uintptr_t; +// +// PIC16:typedef long int intmax_t; +// PIC16:typedef long unsigned int uintmax_t; +// +// PIC16:INT8_MAX_ 127 +// PIC16:INT8_MIN_ (-128) +// PIC16:UINT8_MAX_ 255 +// PIC16:INT_LEAST8_MIN_ (-128) +// PIC16:INT_LEAST8_MAX_ 127 +// PIC16:UINT_LEAST8_MAX_ 255 +// PIC16:INT_FAST8_MIN_ (-128) +// PIC16:INT_FAST8_MAX_ 127 +// PIC16:UINT_FAST8_MAX_ 255 +// +// PIC16:INT16_MAX_ 32767 +// PIC16:INT16_MIN_ (-32768) +// PIC16:UINT16_MAX_ 65535 +// PIC16:INT_LEAST16_MIN_ (-32768) +// PIC16:INT_LEAST16_MAX_ 32767 +// PIC16:UINT_LEAST16_MAX_ 65535 +// PIC16:INT_FAST16_MIN_ (-32768) +// PIC16:INT_FAST16_MAX_ 32767 +// PIC16:UINT_FAST16_MAX_ 65535 +// +// PIC16:INT32_MAX_ 2147483647 +// PIC16:INT32_MIN_ (-2147483647 -1) +// PIC16:UINT32_MAX_ 4294967295U +// PIC16:INT_LEAST32_MIN_ (-2147483647 -1) +// PIC16:INT_LEAST32_MAX_ 2147483647 +// PIC16:UINT_LEAST32_MAX_ 4294967295U +// PIC16:INT_FAST32_MIN_ (-2147483647 -1) +// PIC16:INT_FAST32_MAX_ 2147483647 +// PIC16:UINT_FAST32_MAX_ 4294967295U +// +// PIC16:INT64_MAX_ INT64_MAX +// PIC16:INT64_MIN_ INT64_MIN +// PIC16:UINT64_MAX_ UINT64_MAX +// PIC16:INT_LEAST64_MIN_ INT_LEAST64_MIN +// PIC16:INT_LEAST64_MAX_ INT_LEAST64_MAX +// PIC16:UINT_LEAST64_MAX_ UINT_LEAST64_MAX +// PIC16:INT_FAST64_MIN_ INT_FAST64_MIN +// PIC16:INT_FAST64_MAX_ INT_FAST64_MAX +// PIC16:UINT_FAST64_MAX_ UINT_FAST64_MAX +// +// PIC16:INTPTR_MIN_ (-32768) +// PIC16:INTPTR_MAX_ 32767 +// PIC16:UINTPTR_MAX_ 65535 +// PIC16:PTRDIFF_MIN_ (-32768) +// PIC16:PTRDIFF_MAX_ 32767 +// PIC16:SIZE_MAX_ 65535 +// +// PIC16:INTMAX_MIN_ (-2147483647L -1) +// PIC16:INTMAX_MAX_ 2147483647L +// PIC16:UINTMAX_MAX_ (2147483647L*2ULL +1ULL) +// +// PIC16:SIG_ATOMIC_MIN_ (-2147483647 -1) +// PIC16:SIG_ATOMIC_MAX_ 2147483647 +// PIC16:WINT_MIN_ (-2147483647 -1) +// PIC16:WINT_MAX_ 2147483647 +// +// PIC16:WCHAR_MAX_ 2147483647 +// PIC16:WCHAR_MIN_ (-2147483647 -1) +// +// PIC16:INT8_C_(0) (0) +// PIC16:UINT8_C_(0) (0U) +// PIC16:INT16_C_(0) (0) +// PIC16:UINT16_C_(0) (0U) +// PIC16:INT32_C_(0) (0) +// PIC16:UINT32_C_(0) (0U) +// PIC16:INT64_C_(0) INT64_C(0) +// PIC16:UINT64_C_(0) UINT64_C(0) +// +// PIC16:INTMAX_C_(0) (0LL) +// PIC16:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=powerpc64-none-none %s | FileCheck -check-prefix PPC64 %s && +// +// PPC64:typedef signed char int8_t; +// PPC64:typedef short int16_t; +// PPC64:typedef int int32_t; +// PPC64:typedef long int int64_t; +// +// PPC64:typedef unsigned char uint8_t; +// PPC64:typedef int8_t int_least8_t; +// PPC64:typedef uint8_t uint_least8_t; +// PPC64:typedef int8_t int_fast8_t; +// PPC64:typedef uint8_t uint_fast8_t; +// +// PPC64:typedef unsigned short uint16_t; +// PPC64:typedef int16_t int_least16_t; +// PPC64:typedef uint16_t uint_least16_t; +// PPC64:typedef int16_t int_fast16_t; +// PPC64:typedef uint16_t uint_fast16_t; +// +// PPC64:typedef unsigned int uint32_t; +// PPC64:typedef int32_t int_least32_t; +// PPC64:typedef uint32_t uint_least32_t; +// PPC64:typedef int32_t int_fast32_t; +// PPC64:typedef uint32_t uint_fast32_t; +// +// PPC64:typedef unsigned long int uint64_t; +// PPC64:typedef int64_t int_least64_t; +// PPC64:typedef uint64_t uint_least64_t; +// PPC64:typedef int64_t int_fast64_t; +// PPC64:typedef uint64_t uint_fast64_t; +// +// PPC64:typedef long int intptr_t; +// PPC64:typedef unsigned long int uintptr_t; +// +// PPC64:typedef long int intmax_t; +// PPC64:typedef long unsigned int uintmax_t; +// +// PPC64:INT8_MAX_ 127 +// PPC64:INT8_MIN_ (-128) +// PPC64:UINT8_MAX_ 255 +// PPC64:INT_LEAST8_MIN_ (-128) +// PPC64:INT_LEAST8_MAX_ 127 +// PPC64:UINT_LEAST8_MAX_ 255 +// PPC64:INT_FAST8_MIN_ (-128) +// PPC64:INT_FAST8_MAX_ 127 +// PPC64:UINT_FAST8_MAX_ 255 +// +// PPC64:INT16_MAX_ 32767 +// PPC64:INT16_MIN_ (-32768) +// PPC64:UINT16_MAX_ 65535 +// PPC64:INT_LEAST16_MIN_ (-32768) +// PPC64:INT_LEAST16_MAX_ 32767 +// PPC64:UINT_LEAST16_MAX_ 65535 +// PPC64:INT_FAST16_MIN_ (-32768) +// PPC64:INT_FAST16_MAX_ 32767 +// PPC64:UINT_FAST16_MAX_ 65535 +// +// PPC64:INT32_MAX_ 2147483647 +// PPC64:INT32_MIN_ (-2147483647 -1) +// PPC64:UINT32_MAX_ 4294967295U +// PPC64:INT_LEAST32_MIN_ (-2147483647 -1) +// PPC64:INT_LEAST32_MAX_ 2147483647 +// PPC64:UINT_LEAST32_MAX_ 4294967295U +// PPC64:INT_FAST32_MIN_ (-2147483647 -1) +// PPC64:INT_FAST32_MAX_ 2147483647 +// PPC64:UINT_FAST32_MAX_ 4294967295U +// +// PPC64:INT64_MAX_ 9223372036854775807LL +// PPC64:INT64_MIN_ (-9223372036854775807LL -1) +// PPC64:UINT64_MAX_ 18446744073709551615ULL +// PPC64:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// PPC64:INT_LEAST64_MAX_ 9223372036854775807LL +// PPC64:UINT_LEAST64_MAX_ 18446744073709551615ULL +// PPC64:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// PPC64:INT_FAST64_MAX_ 9223372036854775807LL +// PPC64:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// PPC64:INTPTR_MIN_ (-9223372036854775807LL -1) +// PPC64:INTPTR_MAX_ 9223372036854775807LL +// PPC64:UINTPTR_MAX_ 18446744073709551615ULL +// PPC64:PTRDIFF_MIN_ (-9223372036854775807LL -1) +// PPC64:PTRDIFF_MAX_ 9223372036854775807LL +// PPC64:SIZE_MAX_ 18446744073709551615ULL +// +// PPC64:INTMAX_MIN_ (-9223372036854775807L -1) +// PPC64:INTMAX_MAX_ 9223372036854775807L +// PPC64:UINTMAX_MAX_ (9223372036854775807L*2ULL +1ULL) +// +// PPC64:SIG_ATOMIC_MIN_ (-2147483647 -1) +// PPC64:SIG_ATOMIC_MAX_ 2147483647 +// PPC64:WINT_MIN_ (-2147483647 -1) +// PPC64:WINT_MAX_ 2147483647 +// +// PPC64:WCHAR_MAX_ 2147483647 +// PPC64:WCHAR_MIN_ (-2147483647 -1) +// +// PPC64:INT8_C_(0) (0) +// PPC64:UINT8_C_(0) (0U) +// PPC64:INT16_C_(0) (0) +// PPC64:UINT16_C_(0) (0U) +// PPC64:INT32_C_(0) (0) +// PPC64:UINT32_C_(0) (0U) +// PPC64:INT64_C_(0) (0LL) +// PPC64:UINT64_C_(0) (0ULL) +// +// PPC64:INTMAX_C_(0) (0LL) +// PPC64:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=powerpc-none-none %s | FileCheck -check-prefix PPC %s && +// +// PPC:typedef signed char int8_t; +// PPC:typedef short int16_t; +// PPC:typedef int int32_t; +// PPC:typedef long long int int64_t; +// +// PPC:typedef unsigned char uint8_t; +// PPC:typedef int8_t int_least8_t; +// PPC:typedef uint8_t uint_least8_t; +// PPC:typedef int8_t int_fast8_t; +// PPC:typedef uint8_t uint_fast8_t; +// +// PPC:typedef unsigned short uint16_t; +// PPC:typedef int16_t int_least16_t; +// PPC:typedef uint16_t uint_least16_t; +// PPC:typedef int16_t int_fast16_t; +// PPC:typedef uint16_t uint_fast16_t; +// +// PPC:typedef unsigned int uint32_t; +// PPC:typedef int32_t int_least32_t; +// PPC:typedef uint32_t uint_least32_t; +// PPC:typedef int32_t int_fast32_t; +// PPC:typedef uint32_t uint_fast32_t; +// +// PPC:typedef unsigned long long int uint64_t; +// PPC:typedef int64_t int_least64_t; +// PPC:typedef uint64_t uint_least64_t; +// PPC:typedef int64_t int_fast64_t; +// PPC:typedef uint64_t uint_fast64_t; +// +// PPC:typedef long int intptr_t; +// PPC:typedef unsigned long int uintptr_t; +// +// PPC:typedef long long int intmax_t; +// PPC:typedef long long unsigned int uintmax_t; +// +// PPC:INT8_MAX_ 127 +// PPC:INT8_MIN_ (-128) +// PPC:UINT8_MAX_ 255 +// PPC:INT_LEAST8_MIN_ (-128) +// PPC:INT_LEAST8_MAX_ 127 +// PPC:UINT_LEAST8_MAX_ 255 +// PPC:INT_FAST8_MIN_ (-128) +// PPC:INT_FAST8_MAX_ 127 +// PPC:UINT_FAST8_MAX_ 255 +// +// PPC:INT16_MAX_ 32767 +// PPC:INT16_MIN_ (-32768) +// PPC:UINT16_MAX_ 65535 +// PPC:INT_LEAST16_MIN_ (-32768) +// PPC:INT_LEAST16_MAX_ 32767 +// PPC:UINT_LEAST16_MAX_ 65535 +// PPC:INT_FAST16_MIN_ (-32768) +// PPC:INT_FAST16_MAX_ 32767 +// PPC:UINT_FAST16_MAX_ 65535 +// +// PPC:INT32_MAX_ 2147483647 +// PPC:INT32_MIN_ (-2147483647 -1) +// PPC:UINT32_MAX_ 4294967295U +// PPC:INT_LEAST32_MIN_ (-2147483647 -1) +// PPC:INT_LEAST32_MAX_ 2147483647 +// PPC:UINT_LEAST32_MAX_ 4294967295U +// PPC:INT_FAST32_MIN_ (-2147483647 -1) +// PPC:INT_FAST32_MAX_ 2147483647 +// PPC:UINT_FAST32_MAX_ 4294967295U +// +// PPC:INT64_MAX_ 9223372036854775807LL +// PPC:INT64_MIN_ (-9223372036854775807LL -1) +// PPC:UINT64_MAX_ 18446744073709551615ULL +// PPC:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// PPC:INT_LEAST64_MAX_ 9223372036854775807LL +// PPC:UINT_LEAST64_MAX_ 18446744073709551615ULL +// PPC:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// PPC:INT_FAST64_MAX_ 9223372036854775807LL +// PPC:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// PPC:INTPTR_MIN_ (-2147483647 -1) +// PPC:INTPTR_MAX_ 2147483647 +// PPC:UINTPTR_MAX_ 4294967295U +// PPC:PTRDIFF_MIN_ (-2147483647 -1) +// PPC:PTRDIFF_MAX_ 2147483647 +// PPC:SIZE_MAX_ 4294967295U +// +// PPC:INTMAX_MIN_ (-9223372036854775807LL -1) +// PPC:INTMAX_MAX_ 9223372036854775807LL +// PPC:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// PPC:SIG_ATOMIC_MIN_ (-2147483647 -1) +// PPC:SIG_ATOMIC_MAX_ 2147483647 +// PPC:WINT_MIN_ (-2147483647 -1) +// PPC:WINT_MAX_ 2147483647 +// +// PPC:WCHAR_MAX_ 2147483647 +// PPC:WCHAR_MIN_ (-2147483647 -1) +// +// PPC:INT8_C_(0) (0) +// PPC:UINT8_C_(0) (0U) +// PPC:INT16_C_(0) (0) +// PPC:UINT16_C_(0) (0U) +// PPC:INT32_C_(0) (0) +// PPC:UINT32_C_(0) (0U) +// PPC:INT64_C_(0) (0LL) +// PPC:UINT64_C_(0) (0ULL) +// +// PPC:INTMAX_C_(0) (0LL) +// PPC:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=s390x-none-none %s | FileCheck -check-prefix S390X %s && +// +// S390X:typedef signed char int8_t; +// S390X:typedef short int16_t; +// S390X:typedef int int32_t; +// S390X:typedef long long int int64_t; +// +// S390X:typedef unsigned char uint8_t; +// S390X:typedef int8_t int_least8_t; +// S390X:typedef uint8_t uint_least8_t; +// S390X:typedef int8_t int_fast8_t; +// S390X:typedef uint8_t uint_fast8_t; +// +// S390X:typedef unsigned short uint16_t; +// S390X:typedef int16_t int_least16_t; +// S390X:typedef uint16_t uint_least16_t; +// S390X:typedef int16_t int_fast16_t; +// S390X:typedef uint16_t uint_fast16_t; +// +// S390X:typedef unsigned int uint32_t; +// S390X:typedef int32_t int_least32_t; +// S390X:typedef uint32_t uint_least32_t; +// S390X:typedef int32_t int_fast32_t; +// S390X:typedef uint32_t uint_fast32_t; +// +// S390X:typedef unsigned long long int uint64_t; +// S390X:typedef int64_t int_least64_t; +// S390X:typedef uint64_t uint_least64_t; +// S390X:typedef int64_t int_fast64_t; +// S390X:typedef uint64_t uint_fast64_t; +// +// S390X:typedef long int intptr_t; +// S390X:typedef unsigned long int uintptr_t; +// +// S390X:typedef long long int intmax_t; +// S390X:typedef long long unsigned int uintmax_t; +// +// S390X:INT8_MAX_ 127 +// S390X:INT8_MIN_ (-128) +// S390X:UINT8_MAX_ 255 +// S390X:INT_LEAST8_MIN_ (-128) +// S390X:INT_LEAST8_MAX_ 127 +// S390X:UINT_LEAST8_MAX_ 255 +// S390X:INT_FAST8_MIN_ (-128) +// S390X:INT_FAST8_MAX_ 127 +// S390X:UINT_FAST8_MAX_ 255 +// +// S390X:INT16_MAX_ 32767 +// S390X:INT16_MIN_ (-32768) +// S390X:UINT16_MAX_ 65535 +// S390X:INT_LEAST16_MIN_ (-32768) +// S390X:INT_LEAST16_MAX_ 32767 +// S390X:UINT_LEAST16_MAX_ 65535 +// S390X:INT_FAST16_MIN_ (-32768) +// S390X:INT_FAST16_MAX_ 32767 +// S390X:UINT_FAST16_MAX_ 65535 +// +// S390X:INT32_MAX_ 2147483647 +// S390X:INT32_MIN_ (-2147483647 -1) +// S390X:UINT32_MAX_ 4294967295U +// S390X:INT_LEAST32_MIN_ (-2147483647 -1) +// S390X:INT_LEAST32_MAX_ 2147483647 +// S390X:UINT_LEAST32_MAX_ 4294967295U +// S390X:INT_FAST32_MIN_ (-2147483647 -1) +// S390X:INT_FAST32_MAX_ 2147483647 +// S390X:UINT_FAST32_MAX_ 4294967295U +// +// S390X:INT64_MAX_ 9223372036854775807LL +// S390X:INT64_MIN_ (-9223372036854775807LL -1) +// S390X:UINT64_MAX_ 18446744073709551615ULL +// S390X:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// S390X:INT_LEAST64_MAX_ 9223372036854775807LL +// S390X:UINT_LEAST64_MAX_ 18446744073709551615ULL +// S390X:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// S390X:INT_FAST64_MAX_ 9223372036854775807LL +// S390X:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// S390X:INTPTR_MIN_ (-9223372036854775807LL -1) +// S390X:INTPTR_MAX_ 9223372036854775807LL +// S390X:UINTPTR_MAX_ 18446744073709551615ULL +// S390X:PTRDIFF_MIN_ (-9223372036854775807LL -1) +// S390X:PTRDIFF_MAX_ 9223372036854775807LL +// S390X:SIZE_MAX_ 18446744073709551615ULL +// +// S390X:INTMAX_MIN_ (-9223372036854775807LL -1) +// S390X:INTMAX_MAX_ 9223372036854775807LL +// S390X:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// S390X:SIG_ATOMIC_MIN_ (-2147483647 -1) +// S390X:SIG_ATOMIC_MAX_ 2147483647 +// S390X:WINT_MIN_ (-2147483647 -1) +// S390X:WINT_MAX_ 2147483647 +// +// S390X:WCHAR_MAX_ 2147483647 +// S390X:WCHAR_MIN_ (-2147483647 -1) +// +// S390X:INT8_C_(0) (0) +// S390X:UINT8_C_(0) (0U) +// S390X:INT16_C_(0) (0) +// S390X:UINT16_C_(0) (0U) +// S390X:INT32_C_(0) (0) +// S390X:UINT32_C_(0) (0U) +// S390X:INT64_C_(0) (0LL) +// S390X:UINT64_C_(0) (0ULL) +// +// S390X:INTMAX_C_(0) (0LL) +// S390X:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=sparc-none-none %s | FileCheck -check-prefix SPARC %s && +// +// SPARC:typedef signed char int8_t; +// SPARC:typedef short int16_t; +// SPARC:typedef int int32_t; +// SPARC:typedef long long int int64_t; +// +// SPARC:typedef unsigned char uint8_t; +// SPARC:typedef int8_t int_least8_t; +// SPARC:typedef uint8_t uint_least8_t; +// SPARC:typedef int8_t int_fast8_t; +// SPARC:typedef uint8_t uint_fast8_t; +// +// SPARC:typedef unsigned short uint16_t; +// SPARC:typedef int16_t int_least16_t; +// SPARC:typedef uint16_t uint_least16_t; +// SPARC:typedef int16_t int_fast16_t; +// SPARC:typedef uint16_t uint_fast16_t; +// +// SPARC:typedef unsigned int uint32_t; +// SPARC:typedef int32_t int_least32_t; +// SPARC:typedef uint32_t uint_least32_t; +// SPARC:typedef int32_t int_fast32_t; +// SPARC:typedef uint32_t uint_fast32_t; +// +// SPARC:typedef unsigned long long int uint64_t; +// SPARC:typedef int64_t int_least64_t; +// SPARC:typedef uint64_t uint_least64_t; +// SPARC:typedef int64_t int_fast64_t; +// SPARC:typedef uint64_t uint_fast64_t; +// +// SPARC:typedef long int intptr_t; +// SPARC:typedef unsigned long int uintptr_t; +// +// SPARC:typedef long long int intmax_t; +// SPARC:typedef long long unsigned int uintmax_t; +// +// SPARC:INT8_MAX_ 127 +// SPARC:INT8_MIN_ (-128) +// SPARC:UINT8_MAX_ 255 +// SPARC:INT_LEAST8_MIN_ (-128) +// SPARC:INT_LEAST8_MAX_ 127 +// SPARC:UINT_LEAST8_MAX_ 255 +// SPARC:INT_FAST8_MIN_ (-128) +// SPARC:INT_FAST8_MAX_ 127 +// SPARC:UINT_FAST8_MAX_ 255 +// +// SPARC:INT16_MAX_ 32767 +// SPARC:INT16_MIN_ (-32768) +// SPARC:UINT16_MAX_ 65535 +// SPARC:INT_LEAST16_MIN_ (-32768) +// SPARC:INT_LEAST16_MAX_ 32767 +// SPARC:UINT_LEAST16_MAX_ 65535 +// SPARC:INT_FAST16_MIN_ (-32768) +// SPARC:INT_FAST16_MAX_ 32767 +// SPARC:UINT_FAST16_MAX_ 65535 +// +// SPARC:INT32_MAX_ 2147483647 +// SPARC:INT32_MIN_ (-2147483647 -1) +// SPARC:UINT32_MAX_ 4294967295U +// SPARC:INT_LEAST32_MIN_ (-2147483647 -1) +// SPARC:INT_LEAST32_MAX_ 2147483647 +// SPARC:UINT_LEAST32_MAX_ 4294967295U +// SPARC:INT_FAST32_MIN_ (-2147483647 -1) +// SPARC:INT_FAST32_MAX_ 2147483647 +// SPARC:UINT_FAST32_MAX_ 4294967295U +// +// SPARC:INT64_MAX_ 9223372036854775807LL +// SPARC:INT64_MIN_ (-9223372036854775807LL -1) +// SPARC:UINT64_MAX_ 18446744073709551615ULL +// SPARC:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// SPARC:INT_LEAST64_MAX_ 9223372036854775807LL +// SPARC:UINT_LEAST64_MAX_ 18446744073709551615ULL +// SPARC:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// SPARC:INT_FAST64_MAX_ 9223372036854775807LL +// SPARC:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// SPARC:INTPTR_MIN_ (-2147483647 -1) +// SPARC:INTPTR_MAX_ 2147483647 +// SPARC:UINTPTR_MAX_ 4294967295U +// SPARC:PTRDIFF_MIN_ (-2147483647 -1) +// SPARC:PTRDIFF_MAX_ 2147483647 +// SPARC:SIZE_MAX_ 4294967295U +// +// SPARC:INTMAX_MIN_ (-9223372036854775807LL -1) +// SPARC:INTMAX_MAX_ 9223372036854775807LL +// SPARC:UINTMAX_MAX_ (9223372036854775807LL*2ULL +1ULL) +// +// SPARC:SIG_ATOMIC_MIN_ (-2147483647 -1) +// SPARC:SIG_ATOMIC_MAX_ 2147483647 +// SPARC:WINT_MIN_ (-2147483647 -1) +// SPARC:WINT_MAX_ 2147483647 +// +// SPARC:WCHAR_MAX_ 2147483647 +// SPARC:WCHAR_MIN_ (-2147483647 -1) +// +// SPARC:INT8_C_(0) (0) +// SPARC:UINT8_C_(0) (0U) +// SPARC:INT16_C_(0) (0) +// SPARC:UINT16_C_(0) (0U) +// SPARC:INT32_C_(0) (0) +// SPARC:UINT32_C_(0) (0U) +// SPARC:INT64_C_(0) (0LL) +// SPARC:UINT64_C_(0) (0ULL) +// +// SPARC:INTMAX_C_(0) (0LL) +// SPARC:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=tce-none-none %s | FileCheck -check-prefix TCE %s && +// +// TCE:typedef signed char int8_t; +// TCE:typedef short int16_t; +// TCE:typedef int int32_t; +// +// TCE:typedef unsigned char uint8_t; +// TCE:typedef int8_t int_least8_t; +// TCE:typedef uint8_t uint_least8_t; +// TCE:typedef int8_t int_fast8_t; +// TCE:typedef uint8_t uint_fast8_t; +// +// TCE:typedef unsigned short uint16_t; +// TCE:typedef int16_t int_least16_t; +// TCE:typedef uint16_t uint_least16_t; +// TCE:typedef int16_t int_fast16_t; +// TCE:typedef uint16_t uint_fast16_t; +// +// TCE:typedef unsigned int uint32_t; +// TCE:typedef int32_t int_least32_t; +// TCE:typedef uint32_t uint_least32_t; +// TCE:typedef int32_t int_fast32_t; +// TCE:typedef uint32_t uint_fast32_t; +// +// TCE:typedef int intptr_t; +// TCE:typedef unsigned int uintptr_t; +// +// TCE:typedef long int intmax_t; +// TCE:typedef long unsigned int uintmax_t; +// +// TCE:INT8_MAX_ 127 +// TCE:INT8_MIN_ (-128) +// TCE:UINT8_MAX_ 255 +// TCE:INT_LEAST8_MIN_ (-128) +// TCE:INT_LEAST8_MAX_ 127 +// TCE:UINT_LEAST8_MAX_ 255 +// TCE:INT_FAST8_MIN_ (-128) +// TCE:INT_FAST8_MAX_ 127 +// TCE:UINT_FAST8_MAX_ 255 +// +// TCE:INT16_MAX_ 32767 +// TCE:INT16_MIN_ (-32768) +// TCE:UINT16_MAX_ 65535 +// TCE:INT_LEAST16_MIN_ (-32768) +// TCE:INT_LEAST16_MAX_ 32767 +// TCE:UINT_LEAST16_MAX_ 65535 +// TCE:INT_FAST16_MIN_ (-32768) +// TCE:INT_FAST16_MAX_ 32767 +// TCE:UINT_FAST16_MAX_ 65535 +// +// TCE:INT32_MAX_ 2147483647 +// TCE:INT32_MIN_ (-2147483647 -1) +// TCE:UINT32_MAX_ 4294967295U +// TCE:INT_LEAST32_MIN_ (-2147483647 -1) +// TCE:INT_LEAST32_MAX_ 2147483647 +// TCE:UINT_LEAST32_MAX_ 4294967295U +// TCE:INT_FAST32_MIN_ (-2147483647 -1) +// TCE:INT_FAST32_MAX_ 2147483647 +// TCE:UINT_FAST32_MAX_ 4294967295U +// +// TCE:INT64_MAX_ INT64_MAX +// TCE:INT64_MIN_ INT64_MIN +// TCE:UINT64_MAX_ UINT64_MAX +// TCE:INT_LEAST64_MIN_ INT_LEAST64_MIN +// TCE:INT_LEAST64_MAX_ INT_LEAST64_MAX +// TCE:UINT_LEAST64_MAX_ UINT_LEAST64_MAX +// TCE:INT_FAST64_MIN_ INT_FAST64_MIN +// TCE:INT_FAST64_MAX_ INT_FAST64_MAX +// TCE:UINT_FAST64_MAX_ UINT_FAST64_MAX +// +// TCE:INTPTR_MIN_ (-2147483647 -1) +// TCE:INTPTR_MAX_ 2147483647 +// TCE:UINTPTR_MAX_ 4294967295U +// TCE:PTRDIFF_MIN_ (-2147483647 -1) +// TCE:PTRDIFF_MAX_ 2147483647 +// TCE:SIZE_MAX_ 4294967295U +// +// TCE:INTMAX_MIN_ (-2147483647L -1) +// TCE:INTMAX_MAX_ 2147483647L +// TCE:UINTMAX_MAX_ (2147483647L*2ULL +1ULL) +// +// TCE:SIG_ATOMIC_MIN_ (-2147483647 -1) +// TCE:SIG_ATOMIC_MAX_ 2147483647 +// TCE:WINT_MIN_ (-2147483647 -1) +// TCE:WINT_MAX_ 2147483647 +// +// TCE:WCHAR_MAX_ 2147483647 +// TCE:WCHAR_MIN_ (-2147483647 -1) +// +// TCE:INT8_C_(0) (0) +// TCE:UINT8_C_(0) (0U) +// TCE:INT16_C_(0) (0) +// TCE:UINT16_C_(0) (0U) +// TCE:INT32_C_(0) (0) +// TCE:UINT32_C_(0) (0U) +// TCE:INT64_C_(0) INT64_C(0) +// TCE:UINT64_C_(0) UINT64_C(0) +// +// TCE:INTMAX_C_(0) (0LL) +// TCE:UINTMAX_C_(0) (0ULL) +// +// RUN: clang-cc -E -ffreestanding -triple=x86_64-none-none %s | FileCheck -check-prefix X86_64 %s && +// +// X86_64:typedef signed char int8_t; +// X86_64:typedef short int16_t; +// X86_64:typedef int int32_t; +// X86_64:typedef long int int64_t; +// +// X86_64:typedef unsigned char uint8_t; +// X86_64:typedef int8_t int_least8_t; +// X86_64:typedef uint8_t uint_least8_t; +// X86_64:typedef int8_t int_fast8_t; +// X86_64:typedef uint8_t uint_fast8_t; +// +// X86_64:typedef unsigned short uint16_t; +// X86_64:typedef int16_t int_least16_t; +// X86_64:typedef uint16_t uint_least16_t; +// X86_64:typedef int16_t int_fast16_t; +// X86_64:typedef uint16_t uint_fast16_t; +// +// X86_64:typedef unsigned int uint32_t; +// X86_64:typedef int32_t int_least32_t; +// X86_64:typedef uint32_t uint_least32_t; +// X86_64:typedef int32_t int_fast32_t; +// X86_64:typedef uint32_t uint_fast32_t; +// +// X86_64:typedef unsigned long int uint64_t; +// X86_64:typedef int64_t int_least64_t; +// X86_64:typedef uint64_t uint_least64_t; +// X86_64:typedef int64_t int_fast64_t; +// X86_64:typedef uint64_t uint_fast64_t; +// +// X86_64:typedef long int intptr_t; +// X86_64:typedef unsigned long int uintptr_t; +// +// X86_64:typedef long int intmax_t; +// X86_64:typedef long unsigned int uintmax_t; +// +// X86_64:INT8_MAX_ 127 +// X86_64:INT8_MIN_ (-128) +// X86_64:UINT8_MAX_ 255 +// X86_64:INT_LEAST8_MIN_ (-128) +// X86_64:INT_LEAST8_MAX_ 127 +// X86_64:UINT_LEAST8_MAX_ 255 +// X86_64:INT_FAST8_MIN_ (-128) +// X86_64:INT_FAST8_MAX_ 127 +// X86_64:UINT_FAST8_MAX_ 255 +// +// X86_64:INT16_MAX_ 32767 +// X86_64:INT16_MIN_ (-32768) +// X86_64:UINT16_MAX_ 65535 +// X86_64:INT_LEAST16_MIN_ (-32768) +// X86_64:INT_LEAST16_MAX_ 32767 +// X86_64:UINT_LEAST16_MAX_ 65535 +// X86_64:INT_FAST16_MIN_ (-32768) +// X86_64:INT_FAST16_MAX_ 32767 +// X86_64:UINT_FAST16_MAX_ 65535 +// +// X86_64:INT32_MAX_ 2147483647 +// X86_64:INT32_MIN_ (-2147483647 -1) +// X86_64:UINT32_MAX_ 4294967295U +// X86_64:INT_LEAST32_MIN_ (-2147483647 -1) +// X86_64:INT_LEAST32_MAX_ 2147483647 +// X86_64:UINT_LEAST32_MAX_ 4294967295U +// X86_64:INT_FAST32_MIN_ (-2147483647 -1) +// X86_64:INT_FAST32_MAX_ 2147483647 +// X86_64:UINT_FAST32_MAX_ 4294967295U +// +// X86_64:INT64_MAX_ 9223372036854775807LL +// X86_64:INT64_MIN_ (-9223372036854775807LL -1) +// X86_64:UINT64_MAX_ 18446744073709551615ULL +// X86_64:INT_LEAST64_MIN_ (-9223372036854775807LL -1) +// X86_64:INT_LEAST64_MAX_ 9223372036854775807LL +// X86_64:UINT_LEAST64_MAX_ 18446744073709551615ULL +// X86_64:INT_FAST64_MIN_ (-9223372036854775807LL -1) +// X86_64:INT_FAST64_MAX_ 9223372036854775807LL +// X86_64:UINT_FAST64_MAX_ 18446744073709551615ULL +// +// X86_64:INTPTR_MIN_ (-9223372036854775807LL -1) +// X86_64:INTPTR_MAX_ 9223372036854775807LL +// X86_64:UINTPTR_MAX_ 18446744073709551615ULL +// X86_64:PTRDIFF_MIN_ (-9223372036854775807LL -1) +// X86_64:PTRDIFF_MAX_ 9223372036854775807LL +// X86_64:SIZE_MAX_ 18446744073709551615ULL +// +// X86_64:INTMAX_MIN_ (-9223372036854775807L -1) +// X86_64:INTMAX_MAX_ 9223372036854775807L +// X86_64:UINTMAX_MAX_ (9223372036854775807L*2ULL +1ULL) +// +// X86_64:SIG_ATOMIC_MIN_ (-2147483647 -1) +// X86_64:SIG_ATOMIC_MAX_ 2147483647 +// X86_64:WINT_MIN_ (-2147483647 -1) +// X86_64:WINT_MAX_ 2147483647 +// +// X86_64:WCHAR_MAX_ 2147483647 +// X86_64:WCHAR_MIN_ (-2147483647 -1) +// +// X86_64:INT8_C_(0) (0) +// X86_64:UINT8_C_(0) (0U) +// X86_64:INT16_C_(0) (0) +// X86_64:UINT16_C_(0) (0U) +// X86_64:INT32_C_(0) (0) +// X86_64:UINT32_C_(0) (0U) +// X86_64:INT64_C_(0) (0LL) +// X86_64:UINT64_C_(0) (0ULL) +// +// X86_64:INTMAX_C_(0) (0LL) +// X86_64:UINTMAX_C_(0) (0ULL) +// +// RUN: true + +#include <stdint.h> + +INT8_MAX_ INT8_MAX +INT8_MIN_ INT8_MIN +UINT8_MAX_ UINT8_MAX +INT_LEAST8_MIN_ INT_LEAST8_MIN +INT_LEAST8_MAX_ INT_LEAST8_MAX +UINT_LEAST8_MAX_ UINT_LEAST8_MAX +INT_FAST8_MIN_ INT_FAST8_MIN +INT_FAST8_MAX_ INT_FAST8_MAX +UINT_FAST8_MAX_ UINT_FAST8_MAX + +INT16_MAX_ INT16_MAX +INT16_MIN_ INT16_MIN +UINT16_MAX_ UINT16_MAX +INT_LEAST16_MIN_ INT_LEAST16_MIN +INT_LEAST16_MAX_ INT_LEAST16_MAX +UINT_LEAST16_MAX_ UINT_LEAST16_MAX +INT_FAST16_MIN_ INT_FAST16_MIN +INT_FAST16_MAX_ INT_FAST16_MAX +UINT_FAST16_MAX_ UINT_FAST16_MAX + +INT32_MAX_ INT32_MAX +INT32_MIN_ INT32_MIN +UINT32_MAX_ UINT32_MAX +INT_LEAST32_MIN_ INT_LEAST32_MIN +INT_LEAST32_MAX_ INT_LEAST32_MAX +UINT_LEAST32_MAX_ UINT_LEAST32_MAX +INT_FAST32_MIN_ INT_FAST32_MIN +INT_FAST32_MAX_ INT_FAST32_MAX +UINT_FAST32_MAX_ UINT_FAST32_MAX + +INT64_MAX_ INT64_MAX +INT64_MIN_ INT64_MIN +UINT64_MAX_ UINT64_MAX +INT_LEAST64_MIN_ INT_LEAST64_MIN +INT_LEAST64_MAX_ INT_LEAST64_MAX +UINT_LEAST64_MAX_ UINT_LEAST64_MAX +INT_FAST64_MIN_ INT_FAST64_MIN +INT_FAST64_MAX_ INT_FAST64_MAX +UINT_FAST64_MAX_ UINT_FAST64_MAX + +INTPTR_MIN_ INTPTR_MIN +INTPTR_MAX_ INTPTR_MAX +UINTPTR_MAX_ UINTPTR_MAX +PTRDIFF_MIN_ PTRDIFF_MIN +PTRDIFF_MAX_ PTRDIFF_MAX +SIZE_MAX_ SIZE_MAX + +INTMAX_MIN_ INTMAX_MIN +INTMAX_MAX_ INTMAX_MAX +UINTMAX_MAX_ UINTMAX_MAX + +SIG_ATOMIC_MIN_ SIG_ATOMIC_MIN +SIG_ATOMIC_MAX_ SIG_ATOMIC_MAX +WINT_MIN_ WINT_MIN +WINT_MAX_ WINT_MAX + +WCHAR_MAX_ WCHAR_MAX +WCHAR_MIN_ WCHAR_MIN + +INT8_C_(0) INT8_C(0) +UINT8_C_(0) UINT8_C(0) +INT16_C_(0) INT16_C(0) +UINT16_C_(0) UINT16_C(0) +INT32_C_(0) INT32_C(0) +UINT32_C_(0) UINT32_C(0) +INT64_C_(0) INT64_C(0) +UINT64_C_(0) UINT64_C(0) + +INTMAX_C_(0) INTMAX_C(0) +UINTMAX_C_(0) UINTMAX_C(0) diff --git a/test/Preprocessor/stringize_misc.c b/test/Preprocessor/stringize_misc.c index 251116a..60d66a0 100644 --- a/test/Preprocessor/stringize_misc.c +++ b/test/Preprocessor/stringize_misc.c @@ -1,20 +1,23 @@ -// RUN: clang-cc -E %s | grep -F '"f(1, 2)" "g((x=y++, y))"' && -// RUN: clang-cc -E %s | grep -F '"{a=1" "b=2;}"' && -// RUN: clang-cc -E %s | grep -F '"<" "["' && -// RUN: clang-cc -E %s | grep -F '"(,)" "(...)"' && -// RUN: clang-cc -E %s | grep -F '{a=1 c=3; b=2;}' && -// RUN: clang-cc -E %s | grep -F '"a COMMA b" "(a, b)"' +// RUN: clang-cc -E %s | FileCheck -strict-whitespace %s #define M(x, y) #x #y M( f(1, 2), g((x=y++, y))) +// CHECK: "f(1, 2)" "g((x=y++, y))" + M( {a=1 , b=2;} ) /* A semicolon is not a comma */ +// CHECK: "{a=1" "b=2;}" + M( <, [ ) /* Passes the arguments < and [ */ +// CHECK: "<" "[" + M( (,), (...) ) /* Passes the arguments (,) and (...) */ +// CHECK: "(,)" "(...)" #define START_END(start, end) start c=3; end START_END( {a=1 , b=2;} ) /* braces are not parentheses */ +// CHECK: {a=1 c=3; b=2;} /* * To pass a comma token as an argument it is @@ -23,4 +26,5 @@ START_END( {a=1 , b=2;} ) /* braces are not parentheses */ #define COMMA , M(a COMMA b, (a, b)) +// CHECK: "a COMMA b" "(a, b)" diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c index e15381e..4b889fc 100644 --- a/test/Sema/attr-deprecated.c +++ b/test/Sema/attr-deprecated.c @@ -43,3 +43,60 @@ void test1(struct foo *F) { typedef struct foo foo_dep __attribute__((deprecated)); foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}} + +struct bar_dep __attribute__((deprecated, + invalid_attribute)); // expected-warning {{'invalid_attribute' attribute ignored}} + +struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}} + + +// These should not warn because the actually declaration itself is deprecated. +// rdar://6756623 +foo_dep *test4 __attribute__((deprecated)); +struct bar_dep *test5 __attribute__((deprecated)); + +typedef foo_dep test6(struct bar_dep*); // expected-warning {{'foo_dep' is deprecated}} \ + // expected-warning {{'bar_dep' is deprecated}} +typedef foo_dep test7(struct bar_dep*) __attribute__((deprecated)); + +int test8(char *p) { + p += sizeof(foo_dep); // expected-warning {{'foo_dep' is deprecated}} + + foo_dep *ptr; // expected-warning {{'foo_dep' is deprecated}} + ptr = (foo_dep*) p; // expected-warning {{'foo_dep' is deprecated}} + + int func(foo_dep *foo); // expected-warning {{'foo_dep' is deprecated}} + return func(ptr); +} + +foo_dep *test9(void) __attribute__((deprecated)); +foo_dep *test9(void) { + void* myalloc(unsigned long); + + foo_dep *ptr + = (foo_dep*) + myalloc(sizeof(foo_dep)); + return ptr; +} + +void test10(void) __attribute__((deprecated)); +void test10(void) { + if (sizeof(foo_dep) == sizeof(void*)) { + } + foo_dep *localfunc(void); + foo_dep localvar; +} + +char test11[sizeof(foo_dep)] __attribute__((deprecated)); +char test12[sizeof(foo_dep)]; // expected-warning {{'foo_dep' is deprecated}} + +int test13(foo_dep *foo) __attribute__((deprecated)); +int test14(foo_dep *foo); // expected-warning {{'foo_dep' is deprecated}} + +unsigned long test15 = sizeof(foo_dep); // expected-warning {{'foo_dep' is deprecated}} +unsigned long test16 __attribute__((deprecated)) + = sizeof(foo_dep); + +foo_dep test17, // expected-warning {{'foo_dep' is deprecated}} + test18 __attribute__((deprecated)), + test19; diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c index cb69c59..102115b 100644 --- a/test/Sema/callingconv.c +++ b/test/Sema/callingconv.c @@ -8,3 +8,12 @@ void __attribute__((stdcall)) bar(float *a) { void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute requires 0 argument(s)}} } + +void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use 'fastcall' calling convention}} +} + +void __attribute__((fastcall)) test1(void) { +} + +void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use 'fastcall' calling convention}} +} diff --git a/test/Sema/constant-builtins-2.c b/test/Sema/constant-builtins-2.c index 146d9e9..18dbb1e 100644 --- a/test/Sema/constant-builtins-2.c +++ b/test/Sema/constant-builtins-2.c @@ -48,3 +48,5 @@ extern int f(); int h0 = __builtin_types_compatible_p(int, float); //int h1 = __builtin_choose_expr(1, 10, f()); //int h2 = __builtin_expect(0, 0); +extern long int bi0; +extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c index 051f0f7..823551f 100644 --- a/test/Sema/decl-invalid.c +++ b/test/Sema/decl-invalid.c @@ -10,8 +10,7 @@ int a() { int r[x()]; // expected-error {{size of array has non-integer type 'void'}} static y ?; // expected-error{{unknown type name 'y'}} \ - expected-error{{expected identifier or '('}} \ - expected-error{{expected ';' at end of declaration}} + expected-error{{expected identifier or '('}} } int; // expected-error {{declaration does not declare anything}} diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 1826c74..797e53c 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -8,6 +8,10 @@ char * global_fmt; +#if defined(_WIN32) || defined(_WIN64) +extern int snprintf(char*, size_t, const char*, ...); +#endif + void check_string_literal( FILE* fp, const char* s, char *buf, ... ) { char * b; @@ -83,7 +87,7 @@ void check_wide_string(char* b, ...) va_start(ap,b); printf(L"foo %d",2); // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}} - vasprintf(&b,L"bar %d",ap); // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}} + vsprintf(b,L"bar %d",ap); // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}} } void check_asterisk_precision_width(int x) { diff --git a/test/Sema/init.c b/test/Sema/init.c index 1cbcbb7..840b24f 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -21,7 +21,7 @@ int *h = &x; int test() { int a[10]; int b[10] = a; // expected-error {{initialization with '{...}' expected}} -int +; // expected-error {{expected identifier or '('}} expected-error {{expected ';' at end of declaration}} +int +; // expected-error {{expected identifier or '('}} } diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c index f8b9fed..dfae992 100644 --- a/test/Sema/offsetof.c +++ b/test/Sema/offsetof.c @@ -48,3 +48,9 @@ int a[__builtin_offsetof(struct sockaddr_un, sun_path[len+1])]; // PR4079 union x {struct {int x;};}; int x[__builtin_offsetof(union x, x)]; + +// rdar://problem/7222956 +struct incomplete; // expected-note 2 {{forward declaration of 'struct incomplete'}} +int test1[__builtin_offsetof(struct incomplete, foo)]; // expected-error {{offsetof of incomplete type 'struct incomplete'}} + +int test1[__builtin_offsetof(struct incomplete[10], [4].foo)]; // expected-error {{array has incomplete element type 'struct incomplete'}} diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c new file mode 100644 index 0000000..a8ad260 --- /dev/null +++ b/test/Sema/parentheses.c @@ -0,0 +1,20 @@ +// RUN: clang-cc -Wparentheses -fsyntax-only -verify %s && +// RUN: clang-cc -Wparentheses -fixit %s -o - | clang-cc -Wparentheses -Werror - + +// Test the various warnings under -Wparentheses +void if_assign(void) { + int i; + if (i = 4) {} // expected-warning {{assignment as a condition}} + if ((i = 4)) {} +} + +void bitwise_rel(unsigned i) { + (void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}} + (void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}} + (void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}} + (void)((i & 0x2) == 0); + (void)(i & (0x2 == 0)); + // Eager logical op + (void)(i == 1 | i == 2 | i == 3); + (void)(i != 1 & i != 2 & i != 3); +} diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c index e2452f4..8868c9e 100644 --- a/test/Sema/return-noreturn.c +++ b/test/Sema/return-noreturn.c @@ -27,3 +27,11 @@ __attribute__((__noreturn__)) void* test3(int arg) { __attribute__((__noreturn__)) void* test3_positive(int arg) { while (0) foo_test_3(); } // expected-warning{{function declared 'noreturn' should not return}} + + +// PR5298 - -Wmissing-noreturn shouldn't warn if the function is already +// declared noreturn. +void __attribute__((noreturn)) +test4() { + test2_positive(); +} diff --git a/test/Sema/return.c b/test/Sema/return.c index 64def30..cdd3105 100644 --- a/test/Sema/return.c +++ b/test/Sema/return.c @@ -203,7 +203,11 @@ int test30() { if (j) longjmp(test30_j, 1); else +#if defined(_WIN32) || defined(_WIN64) + longjmp(test30_j, 2); +#else _longjmp(test30_j, 1); +#endif } typedef void test31_t(int status); diff --git a/test/Sema/statements.c b/test/Sema/statements.c index 9a71a40..8eac052 100644 --- a/test/Sema/statements.c +++ b/test/Sema/statements.c @@ -27,3 +27,9 @@ int test8[({10;})]; // expected-error {{statement expression not allowed at file void test9(const void *P) { __builtin_prefetch(P); } + + +void *test10() { +bar: + return &&bar; // expected-warning {{returning address of label, which is local}} +} diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c index 353bbfc..e0db638 100644 --- a/test/Sema/stdcall-fastcall.c +++ b/test/Sema/stdcall-fastcall.c @@ -5,6 +5,6 @@ int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' attribute only int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' attribute only applies to function types}} // Different CC qualifiers are not compatible -void __attribute__((stdcall, fastcall)) foo3(); // expected-error{{stdcall and fastcall attributes are not compatible}} +void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}} void __attribute__((stdcall)) foo4(); -void __attribute__((fastcall)) foo4(); // expected-error{{fastcall and stdcall attributes are not compatible}} +void __attribute__((fastcall)) foo4(void); // expected-error{{fastcall and stdcall attributes are not compatible}} diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c index 18104d8..9dac6c7 100644 --- a/test/Sema/vector-init.c +++ b/test/Sema/vector-init.c @@ -8,7 +8,7 @@ float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 }; float4 foo2 = (float4){ 1.0, 2.0, 3.0, 4.0 , 5.0 }; // expected-warning{{excess elements in vector initializer}} float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; -int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1]; +int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3 ? 1 : -1]; float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; // expected-warning {{excess elements in array initializer}} @@ -26,5 +26,5 @@ float f1(void) { // PR5265 typedef float __attribute__((ext_vector_type (3))) float3; -int test2[(sizeof(float3) == sizeof(float4))*2-1]; +int test2[sizeof(float3) == sizeof(float4) ? 1 : -1]; diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index 5ce595c..58d28b55 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -14,7 +14,7 @@ class Foo { static Foo(short, short); // expected-error{{constructor cannot be declared 'static'}} virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}} Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}} - + int Foo(int, int); // expected-error{{constructor cannot have a return type}} }; diff --git a/test/SemaCXX/implicit-int.cpp b/test/SemaCXX/implicit-int.cpp index 6fa8dd3..7230305 100644 --- a/test/SemaCXX/implicit-int.cpp +++ b/test/SemaCXX/implicit-int.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s x; // expected-error{{C++ requires a type specifier for all declarations}} diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp index 90932ed..730beb3 100644 --- a/test/SemaCXX/invalid-member-expr.cpp +++ b/test/SemaCXX/invalid-member-expr.cpp @@ -5,8 +5,8 @@ class X {}; void test() { X x; - x.int; // expected-error{{expected identifier}} - x.~int(); // expected-error{{expected identifier}} + x.int; // expected-error{{expected unqualified-id}} + x.~int(); // expected-error{{expected the class name}} x.operator; // expected-error{{missing type specifier after 'operator'}} x.operator typedef; // expected-error{{missing type specifier after 'operator'}} } @@ -14,8 +14,8 @@ void test() { void test2() { X *x; - x->int; // expected-error{{expected identifier}} - x->~int(); // expected-error{{expected identifier}} + x->int; // expected-error{{expected unqualified-id}} + x->~int(); // expected-error{{expected the class name}} x->operator; // expected-error{{missing type specifier after 'operator'}} x->operator typedef; // expected-error{{missing type specifier after 'operator'}} } diff --git a/test/SemaCXX/invalid-template-specifier.cpp b/test/SemaCXX/invalid-template-specifier.cpp index a3f081f..034ad73 100644 --- a/test/SemaCXX/invalid-template-specifier.cpp +++ b/test/SemaCXX/invalid-template-specifier.cpp @@ -8,5 +8,5 @@ const template basic_istream<char>; // expected-error {{expected unqualified-id} namespace S {} template <class X> class Y { void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \ - // expected-error {{no member named 'y'}} + // expected-error {{unqualified-id}} }; diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 5178557..721758f 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s +// RUN: clang-cc -fsyntax-only -std=c++98 -verify -fms-extensions=0 %s namespace A { struct C { static int cx; diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index c67a3f6..6f3e9ef 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -58,6 +58,7 @@ void bad_news(int *ip) (void)new int[1.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}} (void)new int[1][i]; // expected-error {{only the first dimension}} (void)new (int[1][i]); // expected-error {{only the first dimension}} + (void)new (int[i]); // expected-error {{when type is in parentheses}} (void)new int(*(S*)0); // expected-error {{incompatible type initializing}} (void)new int(1, 2); // expected-error {{initializer of a builtin type can only take one argument}} (void)new S(1); // expected-error {{no matching constructor}} diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 10b0f5a..0f723ad 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/test/SemaCXX/overloaded-operator.cpp @@ -70,6 +70,34 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) { float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type 'bool'}} } +// PR5244 - Argument-dependent lookup would include the two operators below, +// which would break later assumptions and lead to a crash. +class pr5244_foo +{ + pr5244_foo(int); + pr5244_foo(char); +}; + +bool operator==(const pr5244_foo& s1, const pr5244_foo& s2); +bool operator==(char c, const pr5244_foo& s); + +enum pr5244_bar +{ + pr5244_BAR +}; + +class pr5244_baz +{ + pr5244_bar quux; +}; + +void pr5244_barbaz() +{ + pr5244_baz quuux; + (void)(pr5244_BAR == quuux.quux); +} + + struct PostInc { PostInc operator++(int); diff --git a/test/SemaCXX/ptrtomember-badcall.cpp b/test/SemaCXX/ptrtomember-badcall.cpp new file mode 100644 index 0000000..42b8e3b --- /dev/null +++ b/test/SemaCXX/ptrtomember-badcall.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x + +struct S { + int i; + + int mem(int); +}; + +int foo(int S::* ps, S *s) +{ + return (s->*ps)(1); // expected-error {{called object type 'int' is not a function or function pointer}} +} + diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp index e38f474..85944a6 100644 --- a/test/SemaCXX/typedef-redecl.cpp +++ b/test/SemaCXX/typedef-redecl.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s typedef int INT; typedef INT REALLY_INT; // expected-note {{previous definition is here}} typedef REALLY_INT REALLY_REALLY_INT; diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp new file mode 100644 index 0000000..29d866f --- /dev/null +++ b/test/SemaCXX/value-initialization.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x + +struct A { + const int i; // expected-note {{declared at}} + virtual void f() { } +}; + +int main () { + (void)A(); // expected-error {{cannot define the implicit default constructor for 'struct A', because const member 'i' cannot be default-initialized}} +} diff --git a/test/SemaObjC/conditional-expr-6.m b/test/SemaObjC/conditional-expr-6.m new file mode 100644 index 0000000..bba51bb --- /dev/null +++ b/test/SemaObjC/conditional-expr-6.m @@ -0,0 +1,51 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +@protocol MyProtocol @end + +@interface NSObject @end + +@interface NSInterm : NSObject <MyProtocol> +@end + +@interface NSArray : NSInterm +@end + +@interface NSSet : NSObject <MyProtocol> +@end + + +@interface N1 : NSObject +@end + +@interface N1() <MyProtocol> +@end + +NSObject* test (int argc) { + NSArray *array = ((void*)0); + NSSet *set = ((void*)0); + return (argc) ? set : array ; +} + + +NSObject* test1 (int argc) { + NSArray *array = ((void*)0); + NSSet *set = ((void*)0); + id <MyProtocol> instance = (argc) ? array : set; + id <MyProtocol> instance1 = (argc) ? set : array; + + N1 *n1 = ((void*)0); + id <MyProtocol> instance2 = (argc) ? set : n1; + id <MyProtocol> instance3 = (argc) ? n1 : array; + + NSArray<MyProtocol> *qual_array = ((void*)0); + id <MyProtocol> instance4 = (argc) ? array : qual_array; + id <MyProtocol> instance5 = (argc) ? qual_array : array; + NSSet<MyProtocol> *qual_set = ((void*)0); + id <MyProtocol> instance6 = (argc) ? qual_set : qual_array; + id <MyProtocol> instance7 = (argc) ? qual_set : array; + id <MyProtocol> instance8 = (argc) ? qual_array : set; + id <MyProtocol> instance9 = (argc) ? qual_array : qual_set; + + + return (argc) ? array : set; +} diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m index f516a93..262b786 100644 --- a/test/SemaObjC/continuation-class-err.m +++ b/test/SemaObjC/continuation-class-err.m @@ -5,11 +5,36 @@ id _object; id _object1; } -@property(readonly) id object; -@property(readwrite, assign) id object1; +@property(readonly) id object; // expected-note {{property declared here}} +@property(readwrite, assign) id object1; // expected-note {{property declared here}} @end @interface ReadOnly () -@property(readwrite, copy) id object; -@property(readonly) id object1; // expected-error {{attribute of property in continuation class of 'ReadOnly' can only be 'readwrite'}} +@property(readwrite, copy) id object; // expected-warning {{property attribute in continuation class does not match the primary class}} +@property(readonly) id object1; // expected-error {{property declaration in continuation class of 'ReadOnly' is to change a 'readonly' property to 'readwrite'}} @end + +@protocol Proto + @property (copy) id fee; // expected-note {{property declared here}} +@end + +@protocol Foo<Proto> + @property (copy) id foo; // expected-note {{property declared here}} +@end + +@interface Bar <Foo> { + id _foo; + id _fee; +} +@end + +@interface Bar () +@property (copy) id foo; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}} +@property (copy) id fee; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}} +@end + +@implementation Bar +@synthesize foo = _foo; +@synthesize fee = _fee; +@end + diff --git a/test/SemaObjC/id-isa-ref.m b/test/SemaObjC/id-isa-ref.m index dc42f9a..fa3293c 100644 --- a/test/SemaObjC/id-isa-ref.m +++ b/test/SemaObjC/id-isa-ref.m @@ -1,7 +1,7 @@ // RUN: clang-cc -fsyntax-only -verify %s // Failing currently due to Obj-C type representation changes. 2009-09-17 -// XFAIL +// XFAIL: * typedef struct objc_object { struct objc_class *isa; diff --git a/test/SemaObjC/property-category-4.m b/test/SemaObjC/property-category-4.m new file mode 100644 index 0000000..ee08b09 --- /dev/null +++ b/test/SemaObjC/property-category-4.m @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +@interface IDELogNavigator +{ + id selectedObjects; +} +@end + +@interface IDELogNavigator (CAT) + @property (readwrite, retain) id selectedObjects; // expected-note {{property declared here}} + @property (readwrite, retain) id d_selectedObjects; // expected-note {{property declared here}} +@end + +@implementation IDELogNavigator +@synthesize selectedObjects = _selectedObjects; // expected-error {{property declared in category 'CAT' cannot be implemented in class implementation}} +@dynamic d_selectedObjects; // expected-error {{property declared in category 'CAT' cannot be implemented in class implementation}} +@end + diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m index 9acf470..ff64994 100644 --- a/test/SemaObjC/return.m +++ b/test/SemaObjC/return.m @@ -1,6 +1,22 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang-cc %s -fsyntax-only -verify -Wmissing-noreturn int test1() { id a; @throw a; } + +// PR5286 +void test2(int a) { + while (1) { + if (a) + return; + } +} + +// PR5286 +void test3(int a) { // expected-warning {{function could be attribute 'noreturn'}} + while (1) { + if (a) + @throw (id)0; + } +} diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm index 4714100..56dc510 100644 --- a/test/SemaObjCXX/overload.mm +++ b/test/SemaObjCXX/overload.mm @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * @interface Foo @end diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm index 82797ce..e02f360f 100644 --- a/test/SemaObjCXX/references.mm +++ b/test/SemaObjCXX/references.mm @@ -1,7 +1,7 @@ // FIXME: This crashes, disable it until fixed. // RN: clang-cc -verify -emit-llvm -o - %s // RUN: false -// XFAIL +// XFAIL: * // Test reference binding. diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index e44115c..4cd43b4 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -20,8 +20,7 @@ int test_incomplete_specs(A<double, double> *a1, A<double> *a2) { (void)a1->x; // expected-error{{incomplete definition of type 'A<double, double>'}} - (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} \ - // expected-note{{first required here}} + (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} } typedef float FLOAT; @@ -71,8 +70,7 @@ namespace N { } // Diagnose specialization errors -struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} \ - // expected-error{{after instantiation}} +struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} template<> struct ::A<double>; @@ -100,3 +98,9 @@ template<> struct N::B<char> { int testf(int x) { return f(x); } }; +// PR5264 +template <typename T> class Foo; +Foo<int>* v; +Foo<int>& F() { return *v; } +template <typename T> class Foo {}; +Foo<int> x; diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index acd845b..79bf7c5 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -51,3 +51,4 @@ void test_X1(X1<int> xi) { template<class C> struct A {}; template <> struct A<int>{A(const A<int>&);}; struct B { A<int> x; B(B& a) : x(a.x) {} }; + diff --git a/test/SemaTemplate/copy-ctor-assign.cpp b/test/SemaTemplate/copy-ctor-assign.cpp index 90fb013..69481ea 100644 --- a/test/SemaTemplate/copy-ctor-assign.cpp +++ b/test/SemaTemplate/copy-ctor-assign.cpp @@ -33,4 +33,20 @@ void test3(X<int> &x, X<int> xi, X<long> xl, X<int Y::*> xmptr) { x = xi; x = xl; x = xmptr; // expected-note{{instantiation}} -}
\ No newline at end of file +} + +struct X1 { + X1 &operator=(const X1&); +}; + +template<typename T> +struct X2 : X1 { + template<typename U> X2 &operator=(const U&); +}; + +struct X3 : X2<int> { +}; + +void test_X2(X3 &to, X3 from) { + to = from; +} diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 575283e..9c0f1ec 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -84,3 +84,27 @@ struct X1 { void test_X1() { X1<int> x1; } + +// PR5283 +namespace PR5283 { +template<typename T> struct A { + A(T = 1); // expected-error 3 {{incompatible type initializing 'int', expected 'int *'}} +}; + +struct B : A<int*> { + B(); +}; +B::B() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}} + +struct C : virtual A<int*> { + C(); +}; +C::C() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}} + +struct D { + D(); + + A<int*> a; +}; +D::D() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}} +} diff --git a/test/SemaTemplate/ext-vector-type.cpp b/test/SemaTemplate/ext-vector-type.cpp index b6aebc1..7cc4ae9 100644 --- a/test/SemaTemplate/ext-vector-type.cpp +++ b/test/SemaTemplate/ext-vector-type.cpp @@ -45,3 +45,16 @@ struct make5 { typedef int_ptr __attribute__((ext_vector_type(Length))) type; // expected-error{{invalid vector type}} }; +template<int Length> +struct make6 { + typedef int __attribute__((ext_vector_type(Length))) type; +}; + +int test_make6() { + make6<4>::type x; + x.w = 7; + + make6<2>::type y; + y.x = -1; + y.w = -1; // expected-error{{vector component access exceeds type}} +} diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp index 761c130..84a8e89 100644 --- a/test/SemaTemplate/friend-template.cpp +++ b/test/SemaTemplate/friend-template.cpp @@ -54,6 +54,7 @@ struct X1 { template<typename U> void f2(U); X1<int> x1i; +X0<int*> x0ip; template<> void f2(int); @@ -62,3 +63,31 @@ template<> void f2(int); template<typename U> void f3(U); template<> void f3(int); + +// PR5332 +template <typename T> +class Foo { + template <typename U> + friend class Foo; +}; + +Foo<int> foo; + +template<typename T, T Value> +struct X2a; + +template<typename T, int Size> +struct X2b; + +template<typename T> +class X3 { + template<typename U, U Value> + friend struct X2a; + + template<typename U, T Value> + friend struct X2b; +}; + +X3<int> x3i; // okay + +X3<long> x3l; // FIXME: should cause an instantiation-time failure diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp index 6b3fc6e..c3c318f 100644 --- a/test/SemaTemplate/instantiate-cast.cpp +++ b/test/SemaTemplate/instantiate-cast.cpp @@ -96,7 +96,6 @@ struct FunctionalCast1 { template struct FunctionalCast1<int, float>; template struct FunctionalCast1<A, int>; // expected-note{{instantiation}} -#if 0 // Generates temporaries, which we cannot handle yet. template<int N, long M> struct FunctionalCast2 { @@ -106,4 +105,13 @@ struct FunctionalCast2 { }; template struct FunctionalCast2<1, 3>; -#endif + +// --------------------------------------------------------------------- +// implicit casting +// --------------------------------------------------------------------- +template<typename T> +struct Derived2 : public Base { }; + +void test_derived_to_base(Base *&bp, Derived2<int> *dp) { + bp = dp; +} diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp index 21ee872..ab12b90 100644 --- a/test/SemaTemplate/instantiate-declref-ice.cpp +++ b/test/SemaTemplate/instantiate-declref-ice.cpp @@ -5,3 +5,33 @@ template<int i> struct x { x<j>* y; }; +template<int i> +const int x<i>::j; + +int array0[x<2>::j]; + + +template<typename T> +struct X0 { + static const unsigned value = sizeof(T); +}; + +template<typename T> +const unsigned X0<T>::value; + +int array1[X0<int>::value == sizeof(int)? 1 : -1]; + +const unsigned& testX0() { return X0<int>::value; } + +int array2[X0<int>::value == sizeof(int)? 1 : -1]; + +template<typename T> +struct X1 { + static const unsigned value; +}; + +template<typename T> +const unsigned X1<T>::value = sizeof(T); + +int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length arrays are not permitted in C++}} \ +// expected-error{{variable length array declaration not allowed at file scope}} diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp index 051c605..359e2c7 100644 --- a/test/SemaTemplate/instantiate-declref.cpp +++ b/test/SemaTemplate/instantiate-declref.cpp @@ -69,3 +69,21 @@ namespace N2 { template struct N2::Outer2::Inner<float>; template struct N2::Outer2::Inner<int*, float*>; // expected-note{{instantiation}} + +// Test dependent pointer-to-member expressions. +template<typename T> +struct smart_ptr { + struct safe_bool { + int member; + }; + + operator int safe_bool::*() const { + return ptr? &safe_bool::member : 0; + } + + T* ptr; +}; + +void test_smart_ptr(smart_ptr<int> p) { + if (p) { } +} diff --git a/test/SemaTemplate/instantiate-function-1.mm b/test/SemaTemplate/instantiate-function-1.mm index be995e7..c119ab5 100644 --- a/test/SemaTemplate/instantiate-function-1.mm +++ b/test/SemaTemplate/instantiate-function-1.mm @@ -1,5 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL +// XFAIL: * template<typename T> struct Member0 { void f(T t) { diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index f7c09ef..df1e1d9 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -81,3 +81,20 @@ int *a(A0<int> &x0, A1<int> &x1) { int *y0 = x0; int *y1 = x1; // expected-error{{initializing}} } + +struct X0Base { + int &f(); +}; + +template<typename T> +struct X0 : X0Base { +}; + +template<typename U> +struct X1 : X0<U> { + int &f2() { return X0Base::f(); } +}; + +void test_X1(X1<int> x1i) { + int &ir = x1i.f2(); +} diff --git a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp new file mode 100644 index 0000000..32acbd0 --- /dev/null +++ b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5311 +template<typename T> +class StringSwitch { +public: + template<unsigned N> + void Case(const char (&S)[N], const int & Value) { + } +}; + +int main(int argc, char *argv[]) { + (void)StringSwitch<int>(); +} diff --git a/test/SemaTemplate/instantiate-subscript.cpp b/test/SemaTemplate/instantiate-subscript.cpp index 434d84e..20e2c39 100644 --- a/test/SemaTemplate/instantiate-subscript.cpp +++ b/test/SemaTemplate/instantiate-subscript.cpp @@ -6,7 +6,7 @@ struct Sub0 { }; struct Sub1 { - long &operator[](long); + long &operator[](long); // expected-note{{candidate function}} }; struct ConvertibleToInt { @@ -24,3 +24,18 @@ template struct Subscript0<int*, int, int&>; template struct Subscript0<Sub0, int, int&>; template struct Subscript0<Sub1, ConvertibleToInt, long&>; template struct Subscript0<Sub1, Sub0, long&>; // expected-note{{instantiation}} + +// PR5345 +template <typename T> +struct S { + bool operator[](int n) const { return true; } +}; + +template <typename T> +void Foo(const S<int>& s, T x) { + if (s[0]) {} +} + +void Bar() { + Foo(S<int>(), 0); +} diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index 0f9f21f..0238cd5 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template<typename U, typename T> U f0(T t) { return t.template get<U>(); @@ -50,3 +49,47 @@ B<T>::destroy() void do_destroy_B(B<int> b) { b.destroy(); } + +struct X1 { + int* f1(int); + template<typename T> float* f1(T); + + static int* f2(int); + template<typename T> static float* f2(T); +}; + +void test_X1(X1 x1) { + float *fp1 = x1.f1<>(17); + float *fp2 = x1.f1<int>(3.14); + int *ip1 = x1.f1(17); + float *ip2 = x1.f1(3.14); + + float* (X1::*mf1)(int) = &X1::f1; + float* (X1::*mf2)(int) = &X1::f1<>; + float* (X1::*mf3)(float) = &X1::f1<float>; + + float* (*fp3)(int) = &X1::f2; + float* (*fp4)(int) = &X1::f2<>; + float* (*fp5)(float) = &X1::f2<float>; + float* (*fp6)(int) = X1::f2; + float* (*fp7)(int) = X1::f2<>; + float* (*fp8)(float) = X1::f2<float>; +} + +template<int A> struct X2 { + int m; +}; + +template<typename T> +struct X3 : T { }; + +template<typename T> +struct X4 { + template<typename U> + void f(X2<sizeof(X3<U>().U::m)>); +}; + +void f(X4<X3<int> > x4i) { + X2<sizeof(int)> x2; + x4i.f<X2<sizeof(int)> >(x2); +} diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index a5aa2dc..1bdc7a8 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s namespace N { namespace M { diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp index 5ee2c99..4d94818 100644 --- a/test/SemaTemplate/nested-template.cpp +++ b/test/SemaTemplate/nested-template.cpp @@ -101,3 +101,10 @@ struct X0<T*> { template<typename U> void f(U u = T()) { } }; + +// PR5103 +template<typename> +struct X1 { + template<typename, bool = false> struct B { }; +}; +template struct X1<int>::B<bool>; diff --git a/test/SemaTemplate/operator-function-id-template.cpp b/test/SemaTemplate/operator-function-id-template.cpp new file mode 100644 index 0000000..92a8c84 --- /dev/null +++ b/test/SemaTemplate/operator-function-id-template.cpp @@ -0,0 +1,28 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct A { + template<typename U> A<T> operator+(U); +}; + +template<int Value, typename T> bool operator==(A<T>, A<T>); + +template<> bool operator==<0>(A<int>, A<int>); + +bool test_qualified_id(A<int> ai) { + return ::operator==<0, int>(ai, ai); +} + +void test_op(A<int> a, int i) { + const A<int> &air = a.operator+<int>(i); +} + +template<typename T> +void test_op_template(A<T> at, T x) { + const A<T> &atr = at.template operator+<T>(x); + const A<T> &atr2 = at.A::template operator+<T>(x); + // FIXME: unrelated template-name instantiation issue + // const A<T> &atr3 = at.template A<T>::template operator+<T>(x); +} + +template void test_op_template<float>(A<float>, float); diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp new file mode 100644 index 0000000..a0cbe44 --- /dev/null +++ b/test/SemaTemplate/template-id-expr.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5336 +template<typename FromCl> +struct isa_impl_cl { + template<class ToCl> + static void isa(const FromCl &Val) { } +}; + +template<class X, class Y> +void isa(const Y &Val) { return isa_impl_cl<Y>::template isa<X>(Val); } + +class Value; +void f0(const Value &Val) { isa<Value>(Val); } diff --git a/test/SemaTemplate/template-id-printing.cpp b/test/SemaTemplate/template-id-printing.cpp new file mode 100644 index 0000000..1325094 --- /dev/null +++ b/test/SemaTemplate/template-id-printing.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -fsyntax-only -ast-print %s | FileCheck %s +namespace N { + template<typename T, typename U> void f(U); + template<int> void f(); +} + +void g() { + // CHECK: N::f<int>(3.14 + N::f<int>(3.14); + + // CHECK: N::f<double> + void (*fp)(int) = N::f<double>; +} diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 9dabafc..c88c90b 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -5,6 +5,7 @@ config.llvm_obj_root = "@LLVM_BINARY_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" config.llvm_libs_dir = "@LLVM_LIBS_DIR@" config.clang_obj_root = "@CLANG_BINARY_DIR@" +config.target_triple = "@TARGET_TRIPLE@" # Let the main config do the real work. lit.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg") diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 64dfcfe..4798e28 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -116,6 +116,10 @@ class TUVisitor : public DeclVisitor<TUVisitor> { if (ND->getPCHLevel() > MaxPCHLevel) return; + // Filter any implicit declarations (since the source info will be bogus). + if (ND->isImplicit()) + return; + CXCursor C = { CK, ND, 0 }; Callback(TUnit, C, CData); } @@ -380,10 +384,8 @@ CXTranslationUnit clang_createTranslationUnit( CXXIdx->getOnlyLocalDecls(), /* UseBumpAllocator = */ true); - if (!ErrMsg.empty()) { - (llvm::errs() << "clang_createTranslationUnit: " << ErrMsg - << '\n').flush(); - } + if (!ErrMsg.empty()) + llvm::errs() << "clang_createTranslationUnit: " << ErrMsg << '\n'; return TU; } @@ -436,8 +438,9 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile( // Add the null terminator. argv.push_back(NULL); -#ifndef LLVM_ON_WIN32 - llvm::sys::Path DevNull("/dev/null"); + // Invoke 'clang'. + llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null + // on Unix or NUL (Windows). std::string ErrMsg; const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL }; llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, @@ -448,16 +451,12 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile( llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg << '\n' << "Arguments: \n"; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); - I!=E; ++I) - if (*I) llvm::errs() << ' ' << *I << '\n'; - - (llvm::errs() << '\n').flush(); + I!=E; ++I) { + if (*I) + llvm::errs() << ' ' << *I << '\n'; + } + llvm::errs() << '\n'; } -#else - // FIXME: I don't know what is the equivalent '/dev/null' redirect for - // Windows for this API. - llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0]); -#endif // Finally, we create the translation unit from the ast file. ASTUnit *ATU = static_cast<ASTUnit *>( @@ -550,7 +549,13 @@ const char *clang_getDeclSpelling(CXDecl AnonDecl) if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) { return OMD->getSelector().getAsString().c_str(); - } + } + if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) + // No, this isn't the same as the code below. getIdentifier() is non-virtual + // and returns different names. NamedDecl returns the class name and + // ObjCCategoryImplDecl returns the category name. + return CIMP->getIdentifier()->getNameStart(); + if (ND->getIdentifier()) return ND->getIdentifier()->getNameStart(); else @@ -576,9 +581,40 @@ unsigned clang_getDeclColumn(CXDecl AnonDecl) const char *clang_getDeclSource(CXDecl AnonDecl) { assert(AnonDecl && "Passed null CXDecl"); + FileEntry *FEnt = static_cast<FileEntry *>(clang_getDeclSourceFile(AnonDecl)); + assert (FEnt && "Cannot find FileEntry for Decl"); + return clang_getFileName(FEnt); +} + +static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr, + SourceLocation SLoc) +{ + FileID FID; + if (SLoc.isFileID()) + FID = SMgr.getFileID(SLoc); + else + FID = SMgr.getDecomposedSpellingLoc(SLoc).first; + return SMgr.getFileEntryForID(FID); +} + +CXFile clang_getDeclSourceFile(CXDecl AnonDecl) +{ + assert(AnonDecl && "Passed null CXDecl"); NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return SourceMgr.getBufferName(ND->getLocation()); + return (void *)getFileEntryFromSourceLocation(SourceMgr, ND->getLocation()); +} + +const char *clang_getFileName(CXFile SFile) { + assert(SFile && "Passed null CXFile"); + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return FEnt->getName(); +} + +time_t clang_getFileTime(CXFile SFile) { + assert(SFile && "Passed null CXFile"); + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return FEnt->getModificationTime(); } const char *clang_getCursorSpelling(CXCursor C) @@ -695,26 +731,12 @@ static enum CXCursorKind TranslateKind(Decl *D) { // // CXCursor Operations. // -void clang_initCXLookupHint(CXLookupHint *hint) { - memset(hint, 0, sizeof(*hint)); -} - CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, - unsigned line, unsigned column) { - return clang_getCursorWithHint(CTUnit, source_name, line, column, NULL); -} - -CXCursor clang_getCursorWithHint(CXTranslationUnit CTUnit, - const char *source_name, - unsigned line, unsigned column, - CXLookupHint *hint) + unsigned line, unsigned column) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - // FIXME: Make this better. - CXDecl RelativeToDecl = hint ? hint->decl : NULL; - FileManager &FMgr = CXXUnit->getFileManager(); const FileEntry *File = FMgr.getFile(source_name, source_name+strlen(source_name)); @@ -725,9 +747,13 @@ CXCursor clang_getCursorWithHint(CXTranslationUnit CTUnit, SourceLocation SLoc = CXXUnit->getSourceManager().getLocation(File, line, column); - ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc, - static_cast<NamedDecl *>(RelativeToDecl)); - + ASTLocation LastLoc = CXXUnit->getLastASTLocation(); + + ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc, + &LastLoc); + if (ALoc.isValid()) + CXXUnit->setLastASTLocation(ALoc); + Decl *Dcl = ALoc.getParentDecl(); if (ALoc.isNamedRef()) Dcl = ALoc.AsNamedRef().ND; @@ -935,6 +961,16 @@ const char *clang_getCursorSource(CXCursor C) return Buffer->getBufferIdentifier(); } +CXFile clang_getCursorSourceFile(CXCursor C) +{ + assert(C.decl && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + + return (void *)getFileEntryFromSourceLocation(SourceMgr, + getLocationFromCursor(C,SourceMgr, ND)); +} + void clang_getDefinitionSpellingAndExtent(CXCursor C, const char **startBuf, const char **endBuf, diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index e9d44a0..5f461d8 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -1,32 +1,34 @@ _clang_createIndex +_clang_createTranslationUnit +_clang_createTranslationUnitFromSourceFile _clang_disposeIndex +_clang_disposeTranslationUnit _clang_getCursor _clang_getCursorColumn _clang_getCursorDecl _clang_getCursorFromDecl _clang_getCursorKind +_clang_getCursorKindSpelling _clang_getCursorLine _clang_getCursorSource -_clang_getCursorWithHint -_clang_getDeclarationName -_clang_getDeclSpelling -_clang_getDeclLine +_clang_getCursorSourceFile +_clang_getCursorSpelling _clang_getDeclColumn +_clang_getDeclLine _clang_getDeclSource +_clang_getDeclSourceFile +_clang_getDeclSpelling +_clang_getDeclarationName +_clang_getDefinitionSpellingAndExtent _clang_getEntity _clang_getEntityFromDecl +_clang_getFileName +_clang_getFileTime +_clang_getTranslationUnitSpelling _clang_getURI -_clang_loadDeclaration -_clang_loadTranslationUnit -_clang_createTranslationUnit -_clang_createTranslationUnitFromSourceFile -_clang_disposeTranslationUnit -_clang_initCXLookupHint _clang_isDeclaration -_clang_isReference _clang_isDefinition _clang_isInvalid -_clang_getCursorSpelling -_clang_getCursorKindSpelling -_clang_getDefinitionSpellingAndExtent -_clang_getTranslationUnitSpelling +_clang_isReference +_clang_loadDeclaration +_clang_loadTranslationUnit diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index ee77c03..dd0eeea 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -26,6 +26,7 @@ if(MSVC) # windows.h doesn't compile with /Za get_target_property(NON_ANSI_COMPILE_FLAGS CIndex COMPILE_FLAGS) string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) + set(NON_ANSI_COMPILE_FLAGS "${NON_ANSI_COMPILE_FLAGS} /D_CINDEX_LIB_") set_target_properties(CIndex PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) endif(MSVC) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index cb2aa20..222512a 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -6,7 +6,4 @@ if (CLANG_BUILD_EXPERIMENTAL) add_subdirectory(wpa) endif () add_subdirectory(CIndex) -if (MSVC) -else () - add_subdirectory(c-index-test) -endif () +add_subdirectory(c-index-test) diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index cf2a706..8791ee2 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -4,7 +4,23 @@ #include <stdio.h> #include <string.h> +#ifdef _MSC_VER +char *basename(const char* path) +{ + char* base1 = (char*)strrchr(path, '/'); + char* base2 = (char*)strrchr(path, '\\'); + if (base1 && base2) + return((base1 > base2) ? base1 + 1 : base2 + 1); + else if (base1) + return(base1 + 1); + else if (base2) + return(base2 + 1); + + return((char*)path); +} +#else extern char *basename(const char *); +#endif static void PrintCursor(CXCursor Cursor) { if (clang_isInvalid(Cursor.kind)) @@ -54,7 +70,6 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, CXCursor Ref; while (startBuf < endBuf) { - CXLookupHint hint; if (*startBuf == '\n') { startBuf++; curLine++; @@ -62,11 +77,8 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, } else if (*startBuf != '\t') curColumn++; - clang_initCXLookupHint(&hint); - hint.decl = Cursor.decl; - - Ref = clang_getCursorWithHint(Unit, clang_getCursorSource(Cursor), - curLine, curColumn, &hint); + Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor), + curLine, curColumn); if (Ref.kind == CXCursor_NoDeclFound) { /* Nothing found here; that's fine. */ } else if (Ref.kind != CXCursor_FunctionDecl) { diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index f77767c..671fc35 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -26,6 +26,7 @@ #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompileOptions.h" +#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FixItRewriter.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/InitHeaderSearch.h" @@ -69,7 +70,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" -#include "llvm/System/Process.h" #include "llvm/System/Program.h" #include "llvm/System/Signals.h" #include "llvm/Target/TargetSelect.h" @@ -106,8 +106,6 @@ static bool ResolveParsedLocation(ParsedSourceLocation &ParsedLoc, /// anything. llvm::Timer *ClangFrontendTimer = 0; -static bool HadErrors = false; - static llvm::cl::opt<bool> Verbose("v", llvm::cl::desc("Enable verbose output")); static llvm::cl::opt<bool> @@ -240,6 +238,8 @@ TokenCache("token-cache", llvm::cl::value_desc("path"), // Diagnostic Options //===----------------------------------------------------------------------===// +static DiagnosticOptions DiagOpts; + static llvm::cl::opt<bool> VerifyDiagnostics("verify", llvm::cl::desc("Verify emitted diagnostics and warnings")); @@ -283,10 +283,9 @@ MessageLength("fmessage-length", llvm::cl::value_desc("N")); static llvm::cl::opt<bool> -NoColorDiagnostic("fno-color-diagnostics", - llvm::cl::desc("Don't use colors when showing diagnostics " - "(automatically turned off if output is not a " - "terminal).")); +PrintColorDiagnostic("fcolor-diagnostics", + llvm::cl::desc("Use colors in diagnostics")); + //===----------------------------------------------------------------------===// // C++ Visualization. //===----------------------------------------------------------------------===// @@ -655,10 +654,18 @@ static llvm::cl::opt<bool> NoElideConstructors("fno-elide-constructors", llvm::cl::desc("Disable C++ copy constructor elision")); +static llvm::cl::opt<bool> +NoMergeConstants("fno-merge-all-constants", + llvm::cl::desc("Disallow merging of constants.")); + static llvm::cl::opt<std::string> TargetABI("target-abi", llvm::cl::desc("Target a particular ABI type")); +static llvm::cl::opt<std::string> +TargetTriple("triple", + llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)")); + // It might be nice to add bounds to the CommandLine library directly. struct OptLevelParser : public llvm::cl::parser<unsigned> { @@ -878,132 +885,6 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK, } //===----------------------------------------------------------------------===// -// Target Triple Processing. -//===----------------------------------------------------------------------===// - -static llvm::cl::opt<std::string> -TargetTriple("triple", - llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)")); - -static llvm::cl::opt<std::string> -MacOSVersionMin("mmacosx-version-min", - llvm::cl::desc("Specify target Mac OS X version (e.g. 10.5)")); - -// If -mmacosx-version-min=10.3.9 is specified, change the triple from being -// something like powerpc-apple-darwin9 to powerpc-apple-darwin7 - -// FIXME: We should have the driver do this instead. -static void HandleMacOSVersionMin(llvm::Triple &Triple) { - if (Triple.getOS() != llvm::Triple::Darwin) { - fprintf(stderr, - "-mmacosx-version-min only valid for darwin (Mac OS X) targets\n"); - exit(1); - } - - // Validate that MacOSVersionMin is a 'version number', starting with 10.[3-9] - if (MacOSVersionMin.size() < 4 || - MacOSVersionMin.substr(0, 3) != "10." || - !isdigit(MacOSVersionMin[3])) { - fprintf(stderr, - "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n", - MacOSVersionMin.c_str()); - exit(1); - } - - unsigned VersionNum = MacOSVersionMin[3]-'0'; - - if (VersionNum <= 4 && Triple.getArch() == llvm::Triple::x86_64) { - fprintf(stderr, - "-mmacosx-version-min=%s is invalid with -arch x86_64.\n", - MacOSVersionMin.c_str()); - exit(1); - } - - - llvm::SmallString<16> NewDarwinString; - NewDarwinString += "darwin"; - - // Turn MacOSVersionMin into a darwin number: e.g. 10.3.9 is 3 -> darwin7. - VersionNum += 4; - if (VersionNum > 9) { - NewDarwinString += '1'; - VersionNum -= 10; - } - NewDarwinString += (VersionNum+'0'); - - if (MacOSVersionMin.size() == 4) { - // "10.4" is ok. - } else if (MacOSVersionMin.size() == 6 && - MacOSVersionMin[4] == '.' && - isdigit(MacOSVersionMin[5])) { // 10.4.7 is ok. - // Add the period piece (.7) to the end of the triple. This gives us - // something like ...-darwin8.7 - NewDarwinString += '.'; - NewDarwinString += MacOSVersionMin[5]; - } else { // "10.4" is ok. 10.4x is not. - fprintf(stderr, - "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n", - MacOSVersionMin.c_str()); - exit(1); - } - - Triple.setOSName(NewDarwinString.str()); -} - -static llvm::cl::opt<std::string> -IPhoneOSVersionMin("miphoneos-version-min", - llvm::cl::desc("Specify target iPhone OS version (e.g. 2.0)")); - -// If -miphoneos-version-min=2.2 is specified, change the triple from being -// something like armv6-apple-darwin10 to armv6-apple-darwin9.2.2. We use -// 9 as the default major Darwin number, and encode the iPhone OS version -// number in the minor version and revision. - -// FIXME: We should have the driver do this instead. -static void HandleIPhoneOSVersionMin(llvm::Triple &Triple) { - if (Triple.getOS() != llvm::Triple::Darwin) { - fprintf(stderr, - "-miphoneos-version-min only valid for darwin (Mac OS X) targets\n"); - exit(1); - } - - // Validate that IPhoneOSVersionMin is a 'version number', starting with - // [2-9].[0-9] - if (IPhoneOSVersionMin.size() != 3 || !isdigit(IPhoneOSVersionMin[0]) || - IPhoneOSVersionMin[1] != '.' || !isdigit(IPhoneOSVersionMin[2])) { - fprintf(stderr, - "-miphoneos-version-min=%s is invalid, expected something like '2.0'.\n", - IPhoneOSVersionMin.c_str()); - exit(1); - } - - // Turn IPhoneOSVersionMin into a darwin number: e.g. 2.0 is 2 -> 9.2.0 - llvm::SmallString<16> NewDarwinString; - NewDarwinString += "darwin9."; - NewDarwinString += IPhoneOSVersionMin; - Triple.setOSName(NewDarwinString.str()); -} - -/// CreateTargetTriple - Process the various options that affect the target -/// triple and build a final aggregate triple that we are compiling for. -static llvm::Triple CreateTargetTriple() { - // Initialize base triple. If a -triple option has been specified, use - // that triple. Otherwise, default to the host triple. - llvm::Triple Triple(TargetTriple); - if (Triple.getTriple().empty()) - Triple = llvm::Triple(llvm::sys::getHostTriple()); - - // If -mmacosx-version-min=10.3.9 is specified, change the triple from being - // something like powerpc-apple-darwin9 to powerpc-apple-darwin7 - if (!MacOSVersionMin.empty()) - HandleMacOSVersionMin(Triple); - else if (!IPhoneOSVersionMin.empty()) - HandleIPhoneOSVersionMin(Triple); - - return Triple; -} - -//===----------------------------------------------------------------------===// // SourceManager initialization. //===----------------------------------------------------------------------===// @@ -1056,6 +937,9 @@ static bool InitializeSourceManager(Preprocessor &PP, // -A... - Play with #assertions // -undef - Undefine all predefined macros +static llvm::cl::opt<bool> +undef_macros("undef", llvm::cl::value_desc("macro"), llvm::cl::desc("undef all system defines")); + static llvm::cl::list<std::string> D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix, llvm::cl::desc("Predefine the specified macro")); @@ -1099,8 +983,8 @@ static llvm::cl::opt<bool> nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories")); static llvm::cl::opt<bool> -nostdclanginc("nostdclanginc", - llvm::cl::desc("Disable standard clang #include directories")); +nobuiltininc("nobuiltininc", + llvm::cl::desc("Disable builtin #include directories")); // Various command line options. These four add directories to each chain. static llvm::cl::list<std::string> @@ -1240,7 +1124,7 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers, Init.AddDefaultEnvVarPaths(Lang); - if (!nostdclanginc) + if (!nobuiltininc) AddClangIncludePaths(Argv0, &Init); if (!nostdinc) @@ -1367,7 +1251,7 @@ public: PreprocessorInitOptions InitOpts; InitializePreprocessorInitOptions(InitOpts); - if (InitializePreprocessor(*PP, InitOpts)) + if (InitializePreprocessor(*PP, InitOpts, undef_macros)) return 0; return PP.take(); @@ -1493,6 +1377,8 @@ static void InitializeCompileOptions(CompileOptions &Opts, Opts.DisableRedZone = DisableRedZone; Opts.NoImplicitFloat = NoImplicitFloat; + + Opts.MergeAllConstants = !NoMergeConstants; } //===----------------------------------------------------------------------===// @@ -1681,14 +1567,7 @@ public: // Output diags both where requested... Chain1.reset(Normal); // .. and to our log file. - Chain2.reset(new TextDiagnosticPrinter(*BuildLogFile, - !NoShowColumn, - !NoCaretDiagnostics, - !NoShowLocation, - PrintSourceRangeInfo, - PrintDiagnosticOption, - !NoDiagnosticsFixIt, - MessageLength)); + Chain2.reset(new TextDiagnosticPrinter(*BuildLogFile, DiagOpts)); } virtual void setLangOptions(const LangOptions *LO) { @@ -1862,8 +1741,8 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, Features, Context)); if (!Consumer.get()) { - fprintf(stderr, "Unexpected program action!\n"); - HadErrors = true; + PP.getDiagnostics().Report(FullSourceLoc(), + diag::err_fe_invalid_ast_action); return; } @@ -2082,25 +1961,25 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, if (InitializeSourceManager(PP, InFile)) return; } - + // If we have an ASTConsumer, run the parser with it. if (Consumer) { CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0; void *CreateCodeCompleterData = 0; - + if (!CodeCompletionAt.FileName.empty()) { // Tell the source manager to chop off the given file at a specific // line and column. - if (const FileEntry *Entry + if (const FileEntry *Entry = PP.getFileManager().getFile(CodeCompletionAt.FileName)) { // Truncate the named file at the given line/column. PP.getSourceManager().truncateFileAt(Entry, CodeCompletionAt.Line, CodeCompletionAt.Column); - + // Set up the creation routine for code-completion. CreateCodeCompleter = BuildPrintingCodeCompleter; } else { - PP.getDiagnostics().Report(FullSourceLoc(), + PP.getDiagnostics().Report(FullSourceLoc(), diag::err_fe_invalid_code_complete_file) << CodeCompletionAt.FileName; } @@ -2174,11 +2053,9 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, // handles. Also, we don't want to try to erase an open file. OS.reset(); - if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) && - !OutPath.isEmpty()) { - // If we had errors, try to erase the output file. + // If we had errors, try to erase the output file. + if (PP.getDiagnostics().getNumErrors() && !OutPath.isEmpty()) OutPath.eraseFromDisk(); - } } /// ProcessInputFile - Process a single AST input file with the specified state. @@ -2233,11 +2110,9 @@ static void ProcessASTInputFile(const std::string &InFile, ProgActions PA, // handles. Also, we don't want to try to erase an open file. OS.reset(); - if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) && - !OutPath.isEmpty()) { - // If we had errors, try to erase the output file. + // If we had errors, try to erase the output file. + if (PP.getDiagnostics().getNumErrors() && !OutPath.isEmpty()) OutPath.eraseFromDisk(); - } } static llvm::cl::list<std::string> @@ -2276,6 +2151,16 @@ int main(int argc, char **argv) { if (InputFilenames.empty()) InputFilenames.push_back("-"); + // Initialize the diagnostic options. + DiagOpts.ShowColumn = !NoShowColumn; + DiagOpts.ShowLocation = !NoShowLocation; + DiagOpts.ShowCarets = !NoCaretDiagnostics; + DiagOpts.ShowFixits = !NoDiagnosticsFixIt; + DiagOpts.ShowSourceRanges = PrintSourceRangeInfo; + DiagOpts.ShowOptionNames = PrintDiagnosticOption; + DiagOpts.ShowColors = PrintColorDiagnostic; + DiagOpts.MessageLength = MessageLength; + // Create the diagnostic client for reporting errors or for // implementing -verify. llvm::OwningPtr<DiagnosticClient> DiagClient; @@ -2292,26 +2177,7 @@ int main(int argc, char **argv) { } } else if (HTMLDiag.empty()) { // Print diagnostics to stderr by default. - - // If -fmessage-length=N was not specified, determine whether this - // is a terminal and, if so, implicitly define -fmessage-length - // appropriately. - if (MessageLength.getNumOccurrences() == 0) - MessageLength.setValue(llvm::sys::Process::StandardErrColumns()); - - if (!NoColorDiagnostic) { - NoColorDiagnostic.setValue(!llvm::sys::Process::StandardErrHasColors()); - } - - DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), - !NoShowColumn, - !NoCaretDiagnostics, - !NoShowLocation, - PrintSourceRangeInfo, - PrintDiagnosticOption, - !NoDiagnosticsFixIt, - MessageLength, - !NoColorDiagnostic)); + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), DiagOpts)); } else { DiagClient.reset(CreateHTMLDiagnosticClient(HTMLDiag)); } @@ -2338,18 +2204,14 @@ int main(int argc, char **argv) { llvm::llvm_install_error_handler(LLVMErrorHandler, static_cast<void*>(&Diags)); - // -I- is a deprecated GCC feature, scan for it and reject it. - for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) { - if (I_dirs[i] == "-") { - Diags.Report(FullSourceLoc(), diag::err_pp_I_dash_not_supported); - I_dirs.erase(I_dirs.begin()+i); - --i; - } - } + // Initialize base triple. If a -triple option has been specified, use + // that triple. Otherwise, default to the host triple. + llvm::Triple Triple(TargetTriple); + if (Triple.getTriple().empty()) + Triple = llvm::Triple(llvm::sys::getHostTriple()); // Get information about the target being compiled for. - llvm::Triple Triple = CreateTargetTriple(); - llvm::OwningPtr<TargetInfo> + llvm::OwningPtr<TargetInfo> Target(TargetInfo::CreateTargetInfo(Triple.getTriple())); if (Target == 0) { @@ -2390,8 +2252,8 @@ int main(int argc, char **argv) { continue; } - /// Create a SourceManager object. This tracks and owns all the file - /// buffers allocated to a translation unit. + // Create a SourceManager object. This tracks and owns all the file + // buffers allocated to a translation unit. if (!SourceMgr) SourceMgr.reset(new SourceManager()); else @@ -2415,26 +2277,21 @@ int main(int argc, char **argv) { *SourceMgr.get(), HeaderInfo); llvm::OwningPtr<Preprocessor> PP(PPFactory.CreatePreprocessor()); - if (!PP) continue; - // Handle generating dependencies, if requested + // Handle generating dependencies, if requested. if (!DependencyFile.empty()) { - llvm::raw_ostream *DependencyOS; if (DependencyTargets.empty()) { - // FIXME: Use a proper diagnostic - llvm::errs() << "-dependency-file requires at least one -MT option\n"; - HadErrors = true; + Diags.Report(FullSourceLoc(), diag::err_fe_dependency_file_requires_MT); continue; } std::string ErrStr; - DependencyOS = + llvm::raw_ostream *DependencyOS = new llvm::raw_fd_ostream(DependencyFile.c_str(), ErrStr); if (!ErrStr.empty()) { - // FIXME: Use a proper diagnostic - llvm::errs() << "unable to open dependency file: " + ErrStr; - HadErrors = true; + Diags.Report(FullSourceLoc(), diag::err_fe_error_opening) + << DependencyFile << ErrStr; continue; } @@ -2483,5 +2340,5 @@ int main(int argc, char **argv) { // -time-passes usable. llvm::llvm_shutdown(); - return HadErrors || (Diags.getNumErrors() != 0); + return (Diags.getNumErrors() != 0); } diff --git a/tools/wpa/clang-wpa.cpp b/tools/wpa/clang-wpa.cpp index fa2326d..346634b 100644 --- a/tools/wpa/clang-wpa.cpp +++ b/tools/wpa/clang-wpa.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/CallGraph.h" - +#include "clang/Frontend/ASTUnit.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/TextDiagnosticBuffer.h" @@ -56,7 +56,7 @@ int main(int argc, char **argv) { CG.reset(new CallGraph()); for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) - CG->addTU(*ASTUnits[i]); + CG->addTU(ASTUnits[i]->getASTContext()); CG->ViewCallGraph(); } diff --git a/www/UniversalDriver.html b/www/UniversalDriver.html index f66151a..82ccc8de 100644 --- a/www/UniversalDriver.html +++ b/www/UniversalDriver.html @@ -77,6 +77,9 @@ welcome!</p> wiki page for their work to support the ARM EABI provide an interesting glimpse into how related issues impact the operating system distribution.</li> + <li><a href="http://icculus.org/fatelf/">FatELF</a> is a proposal for bringing + Mac OS X like "Universal Binary" support to ELF based platforms.</li> + </ul> </div> diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl index 4184ce6..8ecd1bba 100644 --- a/www/analyzer/latest_checker.html.incl +++ b/www/analyzer/latest_checker.html.incl @@ -1 +1 @@ -<b><a href="http://checker.minormatter.com/checker-225.tar.bz2">checker-225.tar.bz2</a></b> (built October 21, 2009) +<b><a href="http://checker.minormatter.com/checker-226.tar.bz2">checker-226.tar.bz2</a></b> (built October 29, 2009) diff --git a/www/cxx_status.html b/www/cxx_status.html index ecfc8a8..e1df3be 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -24,7 +24,7 @@ <!--*************************************************************************--> <h1>C++ Support in Clang</h1> <!--*************************************************************************--> -<p>Last updated: $Date: 2009-10-20 23:10:15 +0200 (Tue, 20 Oct 2009) $</p> +<p>Last updated: $Date: 2009-10-30 15:54:38 +0100 (Fri, 30 Oct 2009) $</p> <p> This page tracks the status of C++ support in Clang.<br> @@ -327,6 +327,7 @@ welcome!</p> <td class="na">N/A</td> <td class="complete"></td> <td class="na">N/A</td> + <td></td> </tr> <tr> <td> 3.3.6 [basic.scope.class]</td> @@ -407,6 +408,7 @@ welcome!</p> <td class="na">N/A</td> <td class="medium"></td> <td class="na">N/A</td> + <td></td> </tr> <tr><td> 3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr> <tr><td> 3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr> @@ -732,7 +734,7 @@ welcome!</p> <td class="advanced"></td> <td class="advanced"></td> <td></td> - <td>Dereferenced member function pointers have the wrong type.</td> + <td>Dereferenced member function pointers have the wrong type(see FIXME in CheckPointerToMemberOperands).</td> </tr> <tr> <td> 5.6 [expr.mul]</td> @@ -1521,6 +1523,7 @@ welcome!</p> <td class="advanced" align="center"></td> <td class="advanced" align="center"></td> <td class="advanced" align="center"></td> + <td></td> </tr> <tr> <td> 12.4 [class.dtor]</td> @@ -1606,6 +1609,7 @@ welcome!</p> <td class="advanced" align="center"></td> <td class="advanced" align="center"></td> <td class="na" align="center">N/A</td> + <td></td> </tr> <tr> <td> 13.3.1.2 [over.match.oper]</td> @@ -1661,6 +1665,7 @@ welcome!</p> <td class="advanced" align="center"></td> <td class="advanced" align="center"></td> <td class="na" align="center">N/A</td> + <td></td> </tr> <tr> <td> 13.3.3.1 [over.best.ics]</td> @@ -1792,7 +1797,7 @@ welcome!</p> </tr> <tr> <td>14 [temp]</td> - <td class="basic" align="center">N/A</td> + <td class="medium" align="center"></td> <td class="basic" align="center"></td> <td class="basic" align="center"></td> <td class="broken" align="center"></td> @@ -2075,11 +2080,12 @@ welcome!</p> </tr> <tr> <td> 14.7.2 [temp.explicit]</td> + <td class="complete" align="center"></td> <td class="advanced" align="center"></td> - <td class="medium" align="center"></td> - <td class="medium" align="center"></td> - <td class="broken" align="center"></td> - <td></td> + <td class="advanced" align="center"></td> + <td class="complete" align="center"></td> + <td>Cannot test paragraph 11 until access control is implemented.<br/> + ASTs do not carry enough information to reproduce source code accurately.</td> </tr> <tr> <td> 14.7.3 [temp.expl.spec]</td> |